Skip to content

Commit 192c4ea

Browse files
authored
Merge pull request #2 from harmtemolder/master
Updated code to match new style search result page
2 parents ea42cf3 + a6c398a commit 192c4ea

File tree

5 files changed

+309
-133
lines changed

5 files changed

+309
-133
lines changed

.gitignore

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# “Compiled”
2+
*.zip
3+
4+
# Calibre
5+
calibre
6+
7+
# PyCharm
8+
.idea
9+
10+
# Byte-compiled / optimized / DLL files
11+
__pycache__/
12+
*.py[cod]
13+
*$py.class
14+
15+
# C extensions
16+
*.so
17+
18+
# Distribution / packaging
19+
.Python
20+
build/
21+
develop-eggs/
22+
dist/
23+
downloads/
24+
eggs/
25+
.eggs/
26+
lib/
27+
lib64/
28+
parts/
29+
sdist/
30+
var/
31+
wheels/
32+
share/python-wheels/
33+
*.egg-info/
34+
.installed.cfg
35+
*.egg
36+
MANIFEST
37+
38+
# PyInstaller
39+
# Usually these files are written by a python script from a template
40+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
41+
*.manifest
42+
*.spec
43+
44+
# Installer logs
45+
pip-log.txt
46+
pip-delete-this-directory.txt
47+
48+
# Unit test / coverage reports
49+
htmlcov/
50+
.tox/
51+
.nox/
52+
.coverage
53+
.coverage.*
54+
.cache
55+
nosetests.xml
56+
coverage.xml
57+
*.cover
58+
*.py,cover
59+
.hypothesis/
60+
.pytest_cache/
61+
cover/
62+
63+
# Translations
64+
*.mo
65+
*.pot
66+
67+
# Django stuff:
68+
*.log
69+
local_settings.py
70+
db.sqlite3
71+
db.sqlite3-journal
72+
73+
# Flask stuff:
74+
instance/
75+
.webassets-cache
76+
77+
# Scrapy stuff:
78+
.scrapy
79+
80+
# Sphinx documentation
81+
docs/_build/
82+
83+
# PyBuilder
84+
.pybuilder/
85+
target/
86+
87+
# Jupyter Notebook
88+
.ipynb_checkpoints
89+
90+
# IPython
91+
profile_default/
92+
ipython_config.py
93+
94+
# pyenv
95+
# For a library or package, you might want to ignore these files since the code is
96+
# intended to run in multiple environments; otherwise, check them in:
97+
# .python-version
98+
99+
# pipenv
100+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
101+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
102+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
103+
# install all needed dependencies.
104+
#Pipfile.lock
105+
106+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
107+
__pypackages__/
108+
109+
# Celery stuff
110+
celerybeat-schedule
111+
celerybeat.pid
112+
113+
# SageMath parsed files
114+
*.sage.py
115+
116+
# Environments
117+
.env
118+
.venv
119+
env/
120+
venv/
121+
ENV/
122+
env.bak/
123+
venv.bak/
124+
125+
# Spyder project settings
126+
.spyderproject
127+
.spyproject
128+
129+
# Rope project settings
130+
.ropeproject
131+
132+
# mkdocs documentation
133+
/site
134+
135+
# mypy
136+
.mypy_cache/
137+
.dmypy.json
138+
dmypy.json
139+
140+
# Pyre type checker
141+
.pyre/
142+
143+
# pytype static type analyzer
144+
.pytype/
145+
146+
# Cython debug symbols
147+
cython_debug/

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,19 @@ A Libgen Fiction store plugin for Calibre
44
## Installation
55

66
Download a release from [here](https://github.com/fallaciousreasoning/CalibreLibgenStore/releases) and follow the instructions to add the plugin to Calibre.
7+
8+
## Testing & development
9+
10+
While working on any of the scripts, run this to update the plugin in Calibre and start it in debug mode:
11+
12+
```shell
13+
calibre-customize -b . && calibre-debug -g
14+
```
15+
16+
## Build a release
17+
18+
Run this to zip all PY files together:
19+
20+
```shell
21+
./zip.sh
22+
```

__init__.py

Lines changed: 74 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,112 @@
1-
# -*- coding: utf-8 -*-
2-
31
from __future__ import (unicode_literals, division, absolute_import, print_function)
2+
3+
from calibre.customize import StoreBase
4+
from calibre.devices.usbms.driver import debug_print
5+
from calibre.gui2 import open_url
6+
from calibre.gui2.store import StorePlugin
7+
from calibre.gui2.store.search_result import SearchResult
8+
from calibre.gui2.store.web_store_dialog import WebStoreDialog
9+
from PyQt5.Qt import QUrl
10+
11+
from .libgen_client import LibgenFictionClient
12+
413
store_version = 5 # Needed for dynamic plugin loading
514

615
__license__ = 'MIT'
716
__copyright__ = 'Fallacious Reasoning'
817
__docformat__ = 'restructuredtext en'
918

10-
#####################################################################
11-
# Plug-in base class
12-
#####################################################################
13-
14-
from calibre.customize import InterfaceActionBase
15-
1619
PLUGIN_NAME = 'Libgen Fiction'
17-
PLUGIN_DESCRIPTION = 'Adds a Libfen Fiction search provider to Calibre'
18-
PLUGIN_VERSION_TUPLE = (0, 1, 0)
19-
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
20+
PLUGIN_DESCRIPTION = 'Adds a Libgen Fiction search provider to Calibre'
2021
PLUGIN_AUTHORS = "Fallacious Reasoning (https://github.com/fallaciousreasoning/CalibreLibgenStore)"
22+
PLUGIN_VERSION = (0, 2, 0)
2123

22-
#####################################################################
23-
24-
import base64
25-
import mimetypes
26-
import re
27-
import urllib
28-
import urllib2
29-
from contextlib import closing
30-
31-
from lxml import etree
32-
33-
from .libgen_client import LibgenFictionClient
24+
class LibgenStore(StorePlugin):
25+
def genesis(self):
26+
'''
27+
Initialize the Libgen Client
28+
'''
29+
debug_print('Libgen Fiction::__init__.py:LibgenStore:genesis')
3430

35-
from calibre import browser, url_slash_cleaner
36-
from calibre.constants import __appname__, __version__
37-
from calibre.gui2.store.basic_config import BasicStoreConfig
38-
from calibre.gui2.store.search_result import SearchResult
39-
from calibre.gui2.store import StorePlugin
31+
self.libgen = LibgenFictionClient()
4032

41-
from calibre.customize import StoreBase
33+
def search(self, query, max_results=10, timeout=60):
34+
'''
35+
Searches LibGen for Books. Since the mirror links are not direct
36+
downloads, it should not provide these as `s.downloads`.
37+
'''
4238

39+
debug_print('Libgen Fiction::__init__.py:LibgenStore:search:query =',
40+
query)
4341

44-
web_url = 'http://libgen.io/'
45-
libgen = LibgenFictionClient()
42+
libgen_results = self.libgen.search(query)
4643

47-
def search(query, max_results=10, timeout=60):
48-
libgen_results = libgen.search(query)
49-
for result in libgen_results.results[:min(max_results, len(libgen_results.results))]:
50-
s = SearchResult()
44+
for result in libgen_results.results[:min(max_results, len(libgen_results.results))]:
45+
debug_print('Libgen Fiction::__init__.py:LibgenStore:search:'
46+
'result.title =',
47+
result.title)
5148

52-
s.title = result.title
53-
s.author = result.author
54-
s.series = result.series
55-
s.language = result.language
49+
for mirror in result.mirrors[0:1]: # Calibre only shows 1 anyway
50+
debug_print('Libgen Fiction::__init__.py:LibgenStore:search:'
51+
'result.mirror.url =', mirror.url)
5652

57-
for download in result.downloads:
58-
s.downloads[download.format] = download.url
53+
s = SearchResult()
5954

60-
s.formats = ', '.join(s.downloads.keys())
61-
s.drm = SearchResult.DRM_UNLOCKED
62-
s.cover_url = result.image_url
55+
s.store_name = PLUGIN_NAME
56+
s.cover_url = result.image_url
57+
s.title = '{} ({}, {}{})'.format(
58+
result.title, result.language, mirror.size, mirror.unit)
59+
s.author = result.authors
60+
s.price = '0.00'
61+
s.detail_item = result.md5
62+
s.drm = SearchResult.DRM_UNLOCKED
63+
s.formats = mirror.format
64+
s.plugin_author = PLUGIN_AUTHORS
6365

64-
# don't show results with no downloads
65-
if not s.formats:
66-
continue
66+
debug_print('Libgen Fiction::__init__.py:LibgenStore:search:s =',
67+
s)
6768

68-
yield s
69+
yield s
6970

70-
71-
class LibgenStore(StorePlugin):
72-
def search(self, query, max_results=10, timeout=60):
71+
def open(self, parent=None, detail_item=None, external=False):
7372
'''
74-
Searches LibGen for Books
73+
Open the specified item in the external, or Calibre's browser
7574
'''
76-
for result in search(query, max_results, timeout):
77-
yield result
7875

79-
if __name__ == '__main__':
80-
import sys
76+
debug_print('Libgen Fiction::__init__.py:LibgenStore:open:locals() =',
77+
locals())
78+
79+
detail_url = (
80+
self.libgen.get_detail_url(detail_item)
81+
if detail_item
82+
else self.libgen.base_url
83+
)
84+
85+
debug_print('Libgen Fiction::__init__.py:LibgenStore:open:detail_url =',
86+
detail_url)
8187

82-
query = ' '.join(sys.argv[1:]) if len(sys.argv) > 1 else "Stormlight Archive"
83-
for result in search(' '.join(sys.argv[1:])):
84-
print('=========================================================================================================\nTitle: {0}\nAuthor: {1}\nSeries: {2}\nLanguage: {3}\nDownloads: {4}'.format(result.title, result.author, result.series, result.language, len(result.downloads)))
88+
if external or self.config.get('open_external', False):
89+
open_url(QUrl(detail_url))
90+
else:
91+
d = WebStoreDialog(
92+
self.gui, self.libgen.base_url, parent, detail_url)
93+
d.setWindowTitle(self.name)
94+
d.set_tags(self.config.get('tags', ''))
95+
d.exec_()
8596

8697
class LibgenStoreWrapper(StoreBase):
8798
name = PLUGIN_NAME
8899
description = PLUGIN_DESCRIPTION
89100
supported_platforms = ['windows', 'osx', 'linux']
90101
author = PLUGIN_AUTHORS
91-
version = PLUGIN_VERSION_TUPLE
102+
version = PLUGIN_VERSION
92103
minimum_calibre_version = (1, 0, 0)
93104
affiliate = False
105+
drm_free_only = True
94106

95107
def load_actual_plugin(self, gui):
96108
'''
97109
This method must return the actual interface action plugin object.
98110
'''
99-
#mod, cls = self.actual_plugin.split(':')
100-
store = LibgenStore(gui, self.name)
101-
self.actual_plugin_object = store#getattr(importlib.import_module(mod), cls)(gui, self.name)
102-
return self.actual_plugin_object
111+
self.actual_plugin_object = LibgenStore(gui, self.name)
112+
return self.actual_plugin_object

0 commit comments

Comments
 (0)