Merge branch 'master' into Develop
# Conflicts: # cps/helper.py
This commit is contained in:
commit
2ba14acf4f
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -6,12 +6,23 @@ labels: ''
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
<!-- Please have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md) -->
|
|
||||||
|
## Short Notice from the maintainer
|
||||||
|
|
||||||
|
After 6 years of more or less intensive programming on Calibre-Web, I need a break.
|
||||||
|
The last few months, maintaining Calibre-Web has felt more like work than a hobby. I felt pressured and teased by people to solve "their" problems and merge PRs for "their" Calibre-Web.
|
||||||
|
I have turned off all notifications from Github/Discord and will now concentrate undisturbed on the development of “my” Calibre-Web over the next few weeks/months.
|
||||||
|
I will look into the issues and maybe also the PRs from time to time, but don't expect a quick response from me.
|
||||||
|
|
||||||
|
|
||||||
|
Please also have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
**Describe the bug/problem**
|
**Describe the bug/problem**
|
||||||
|
|
||||||
A clear and concise description of what the bug is. If you are asking for support, please check our [Wiki](https://github.com/janeczku/calibre-web/wiki) if your question is already answered there.
|
A clear and concise description of what the bug is. If you are asking for support, please check our [Wiki](https://github.com/janeczku/calibre-web/wiki) if your question is already answered there.
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
|
|
||||||
Steps to reproduce the behavior:
|
Steps to reproduce the behavior:
|
||||||
1. Go to '...'
|
1. Go to '...'
|
||||||
2. Click on '....'
|
2. Click on '....'
|
||||||
|
@ -19,15 +30,19 @@ Steps to reproduce the behavior:
|
||||||
4. See error
|
4. See error
|
||||||
|
|
||||||
**Logfile**
|
**Logfile**
|
||||||
|
|
||||||
Add content of calibre-web.log file or the relevant error, try to reproduce your problem with "debug" log-level to get more output.
|
Add content of calibre-web.log file or the relevant error, try to reproduce your problem with "debug" log-level to get more output.
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
|
|
||||||
A clear and concise description of what you expected to happen.
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
**Environment (please complete the following information):**
|
**Environment (please complete the following information):**
|
||||||
|
|
||||||
- OS: [e.g. Windows 10/Raspberry Pi OS]
|
- OS: [e.g. Windows 10/Raspberry Pi OS]
|
||||||
- Python version: [e.g. python2.7]
|
- Python version: [e.g. python2.7]
|
||||||
- Calibre-Web version: [e.g. 0.6.8 or 087c4c59 (git rev-parse --short HEAD)]:
|
- Calibre-Web version: [e.g. 0.6.8 or 087c4c59 (git rev-parse --short HEAD)]:
|
||||||
|
@ -37,3 +52,4 @@ If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here. [e.g. access via reverse proxy, database background sync, special database location]
|
Add any other context about the problem here. [e.g. access via reverse proxy, database background sync, special database location]
|
||||||
|
|
||||||
|
|
9
.github/ISSUE_TEMPLATE/feature_request.md
vendored
9
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -7,7 +7,14 @@ assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md) -->
|
# Short Notice from the maintainer
|
||||||
|
|
||||||
|
After 6 years of more or less intensive programming on Calibre-Web, I need a break.
|
||||||
|
The last few months, maintaining Calibre-Web has felt more like work than a hobby. I felt pressured and teased by people to solve "their" problems and merge PRs for "their" Calibre-Web.
|
||||||
|
I have turned off all notifications from Github/Discord and will now concentrate undisturbed on the development of “my” Calibre-Web over the next few weeks/months.
|
||||||
|
I will look into the issues and maybe also the PRs from time to time, but don't expect a quick response from me.
|
||||||
|
|
||||||
|
Please have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Is your feature request related to a problem? Please describe.**
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
# Short Notice from the maintainer
|
||||||
|
|
||||||
|
After 6 years of more or less intensive programming on Calibre-Web, I need a break.
|
||||||
|
The last few months, maintaining Calibre-Web has felt more like work than a hobby. I felt pressured and teased by people to solve "their" problems and merge PRs for "their" Calibre-Web.
|
||||||
|
I have turned off all notifications from Github/Discord and will now concentrate undisturbed on the development of “my” Calibre-Web over the next few weeks/months.
|
||||||
|
I will look into the issues and maybe also the PRs from time to time, but don't expect a quick response from me.
|
||||||
|
|
||||||
# Calibre-Web
|
# Calibre-Web
|
||||||
|
|
||||||
Calibre-Web is a web app that offers a clean and intuitive interface for browsing, reading, and downloading eBooks using a valid [Calibre](https://calibre-ebook.com) database.
|
Calibre-Web is a web app that offers a clean and intuitive interface for browsing, reading, and downloading eBooks using a valid [Calibre](https://calibre-ebook.com) database.
|
||||||
|
|
|
@ -25,16 +25,23 @@ from .constants import SUPPORTED_CALIBRE_BINARIES
|
||||||
|
|
||||||
log = logger.create()
|
log = logger.create()
|
||||||
|
|
||||||
|
|
||||||
def do_calibre_export(book_id, book_format):
|
def do_calibre_export(book_id, book_format):
|
||||||
try:
|
try:
|
||||||
quotes = [3, 5, 7, 9]
|
quotes = [3, 5, 7, 9]
|
||||||
tmp_dir = get_temp_dir()
|
tmp_dir = get_temp_dir()
|
||||||
calibredb_binarypath = get_calibre_binarypath("calibredb")
|
calibredb_binarypath = get_calibre_binarypath("calibredb")
|
||||||
temp_file_name = str(uuid4())
|
temp_file_name = str(uuid4())
|
||||||
opf_command = [calibredb_binarypath, 'export', '--dont-write-opf', '--with-library', config.config_calibre_dir,
|
my_env = os.environ.copy()
|
||||||
|
if config.config_calibre_split:
|
||||||
|
my_env['CALIBRE_OVERRIDE_DATABASE_PATH'] = os.path.join(config.config_calibre_dir, "metadata.db")
|
||||||
|
library_path = config.config_calibre_split_dir
|
||||||
|
else:
|
||||||
|
library_path = config.config_calibre_dir
|
||||||
|
opf_command = [calibredb_binarypath, 'export', '--dont-write-opf', '--with-library', library_path,
|
||||||
'--to-dir', tmp_dir, '--formats', book_format, "--template", "{}".format(temp_file_name),
|
'--to-dir', tmp_dir, '--formats', book_format, "--template", "{}".format(temp_file_name),
|
||||||
str(book_id)]
|
str(book_id)]
|
||||||
p = process_open(opf_command, quotes)
|
p = process_open(opf_command, quotes, my_env)
|
||||||
_, err = p.communicate()
|
_, err = p.communicate()
|
||||||
if err:
|
if err:
|
||||||
log.error('Metadata embedder encountered an error: %s', err)
|
log.error('Metadata embedder encountered an error: %s', err)
|
||||||
|
@ -44,6 +51,7 @@ def do_calibre_export(book_id, book_format):
|
||||||
log.error_or_exception(ex)
|
log.error_or_exception(ex)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
def get_calibre_binarypath(binary):
|
def get_calibre_binarypath(binary):
|
||||||
binariesdir = config.config_binariesdir
|
binariesdir = config.config_binariesdir
|
||||||
if binariesdir:
|
if binariesdir:
|
||||||
|
|
|
@ -124,7 +124,7 @@ def formatseriesindex_filter(series_index):
|
||||||
return int(series_index)
|
return int(series_index)
|
||||||
else:
|
else:
|
||||||
return series_index
|
return series_index
|
||||||
except ValueError:
|
except (ValueError, TypeError):
|
||||||
return series_index
|
return series_index
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
17
cps/redirect.py
Normal file → Executable file
17
cps/redirect.py
Normal file → Executable file
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
from urllib.parse import urlparse, urljoin
|
from urllib.parse import urlparse, urljoin
|
||||||
|
|
||||||
from flask import request, url_for, redirect
|
from flask import request, url_for, redirect, current_app
|
||||||
|
|
||||||
|
|
||||||
def is_safe_url(target):
|
def is_safe_url(target):
|
||||||
|
@ -38,16 +38,15 @@ def is_safe_url(target):
|
||||||
return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc
|
return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc
|
||||||
|
|
||||||
|
|
||||||
def get_redirect_target():
|
def remove_prefix(text, prefix):
|
||||||
for target in request.values.get('next'), request.referrer:
|
if text.startswith(prefix):
|
||||||
if not target:
|
return text[len(prefix):]
|
||||||
continue
|
return ""
|
||||||
if is_safe_url(target):
|
|
||||||
return target
|
|
||||||
|
|
||||||
|
|
||||||
def redirect_back(endpoint, **values):
|
def redirect_back(endpoint, **values):
|
||||||
target = request.form['next']
|
target = request.form.get('next', None) or url_for(endpoint, **values)
|
||||||
if not target or not is_safe_url(target):
|
adapter = current_app.url_map.bind(urlparse(request.host_url).netloc)
|
||||||
|
if not len(adapter.allowed_methods(remove_prefix(target, request.environ.get('HTTP_X_SCRIPT_NAME',"")))):
|
||||||
target = url_for(endpoint, **values)
|
target = url_for(endpoint, **values)
|
||||||
return redirect(target)
|
return redirect(target)
|
||||||
|
|
|
@ -24,7 +24,7 @@ import socket
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from gevent_.pywsgi import WSGIServer
|
from gevent.pywsgi import WSGIServer
|
||||||
from .gevent_wsgi import MyWSGIHandler
|
from .gevent_wsgi import MyWSGIHandler
|
||||||
from gevent.pool import Pool
|
from gevent.pool import Pool
|
||||||
from gevent.socket import socket as GeventSocket
|
from gevent.socket import socket as GeventSocket
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 8.9 KiB |
BIN
cps/static/icon.png
Normal file
BIN
cps/static/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
5
cps/static/icon.svg
Normal file
5
cps/static/icon.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="140px" height="140px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g><path style="opacity:1" fill="#45b29d" d="M 70.5,5.5 C 87.7691,3.12603 97.4358,10.4594 99.5,27.5C 95.637,46.6972 84.3037,59.1972 65.5,65C 60.9053,66.3929 56.2387,66.7262 51.5,66C 50.0692,65.5348 48.9025,64.7014 48,63.5C 47.3333,60.5 47.3333,57.5 48,54.5C 62.2513,56.0484 73.5846,50.715 82,38.5C 85.0332,33.8945 86.0332,28.8945 85,23.5C 83.0488,19.2854 79.7155,17.2854 75,17.5C 65.5257,19.0759 57.859,23.7425 52,31.5C 38.306,51.6368 33.9727,73.6368 39,97.5C 44.5639,116.532 56.7306,122.699 75.5,116C 80.6017,113.385 85.2684,110.218 89.5,106.5C 95.1927,108.891 96.6927,112.891 94,118.5C 78.4211,132.151 61.2544,134.651 42.5,126C 31.5182,117.21 25.3516,105.71 24,91.5C 20.9978,65.8515 27.3311,42.8515 43,22.5C 50.6154,14.1193 59.7821,8.45258 70.5,5.5 Z"/></g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -252,9 +252,16 @@ class TaskConvert(CalibreTask):
|
||||||
quotes = [3, 5]
|
quotes = [3, 5]
|
||||||
tmp_dir = get_temp_dir()
|
tmp_dir = get_temp_dir()
|
||||||
calibredb_binarypath = os.path.join(config.config_binariesdir, SUPPORTED_CALIBRE_BINARIES["calibredb"])
|
calibredb_binarypath = os.path.join(config.config_binariesdir, SUPPORTED_CALIBRE_BINARIES["calibredb"])
|
||||||
|
my_env = os.environ.copy()
|
||||||
|
if config.config_calibre_split:
|
||||||
|
my_env['CALIBRE_OVERRIDE_DATABASE_PATH'] = os.path.join(config.config_calibre_dir, "metadata.db")
|
||||||
|
library_path = config.config_calibre_split_dir
|
||||||
|
else:
|
||||||
|
library_path = config.config_calibre_dir
|
||||||
|
|
||||||
opf_command = [calibredb_binarypath, 'show_metadata', '--as-opf', str(self.book_id),
|
opf_command = [calibredb_binarypath, 'show_metadata', '--as-opf', str(self.book_id),
|
||||||
'--with-library', config.config_calibre_dir]
|
'--with-library', library_path]
|
||||||
p = process_open(opf_command, quotes)
|
p = process_open(opf_command, quotes, my_env)
|
||||||
p.wait()
|
p.wait()
|
||||||
path_tmp_opf = os.path.join(tmp_dir, "metadata_" + str(uuid4()) + ".opf")
|
path_tmp_opf = os.path.join(tmp_dir, "metadata_" + str(uuid4()) + ".opf")
|
||||||
with open(path_tmp_opf, 'w') as fd:
|
with open(path_tmp_opf, 'w') as fd:
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<input type="checkbox" id="config_calibre_split" name="config_calibre_split" data-control="split_settings" data-t ="{{ config.config_calibre_split_dir }}" {% if config.config_calibre_split %}checked{% endif %} >
|
<input type="checkbox" id="config_calibre_split" name="config_calibre_split" data-control="split_settings" data-t ="{{ config.config_calibre_split_dir }}" {% if config.config_calibre_split %}checked{% endif %} >
|
||||||
<label for="config_calibre_split">{{_('Separate Book files from Library (Highly experimental, might not work at all)')}}</label>
|
<label for="config_calibre_split">{{_('Separate Book files from Library (Experimental, may lead to unexpected behavior)')}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div data-related="split_settings">
|
<div data-related="split_settings">
|
||||||
<div class="form-group required input-group">
|
<div class="form-group required input-group">
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
40
cps/web.py
40
cps/web.py
|
@ -613,10 +613,9 @@ def render_ratings_books(page, book_id, order):
|
||||||
db_filter,
|
db_filter,
|
||||||
[order[0][0]],
|
[order[0][0]],
|
||||||
True, config.config_read_column,
|
True, config.config_read_column,
|
||||||
db.books_series_link,
|
db.books_ratings_link,
|
||||||
db.Books.id == db.books_series_link.c.book,
|
db.Books.id == db.books_ratings_link.c.book,
|
||||||
db.Series,
|
db.Ratings)
|
||||||
db.books_ratings_link, db.Ratings)
|
|
||||||
title = _("Rating: None")
|
title = _("Rating: None")
|
||||||
else:
|
else:
|
||||||
name = calibre_db.session.query(db.Ratings).filter(db.Ratings.id == book_id).first()
|
name = calibre_db.session.query(db.Ratings).filter(db.Ratings.id == book_id).first()
|
||||||
|
@ -634,20 +633,33 @@ def render_ratings_books(page, book_id, order):
|
||||||
|
|
||||||
|
|
||||||
def render_formats_books(page, book_id, order):
|
def render_formats_books(page, book_id, order):
|
||||||
name = calibre_db.session.query(db.Data).filter(db.Data.format == book_id.upper()).first()
|
if book_id == '-1':
|
||||||
if name:
|
name = _("None")
|
||||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||||
db.Books,
|
db.Books,
|
||||||
db.Books.data.any(db.Data.format == book_id.upper()),
|
db.Data.format == None,
|
||||||
|
[order[0][0]],
|
||||||
|
True, config.config_read_column,
|
||||||
|
db.Data)
|
||||||
|
|
||||||
|
else:
|
||||||
|
name = calibre_db.session.query(db.Data).filter(db.Data.format == book_id.upper()).first()
|
||||||
|
if name:
|
||||||
|
name = name.format
|
||||||
|
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||||
|
db.Books,
|
||||||
|
db.Books.data.any(
|
||||||
|
db.Data.format == book_id.upper()),
|
||||||
[order[0][0]],
|
[order[0][0]],
|
||||||
True, config.config_read_column)
|
True, config.config_read_column)
|
||||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
|
||||||
title=_("File format: %(format)s", format=name.format),
|
|
||||||
page="formats",
|
|
||||||
order=order[1])
|
|
||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||||
|
title=_("File format: %(format)s", format=name),
|
||||||
|
page="formats",
|
||||||
|
order=order[1])
|
||||||
|
|
||||||
|
|
||||||
def render_category_books(page, book_id, order):
|
def render_category_books(page, book_id, order):
|
||||||
if book_id == '-1':
|
if book_id == '-1':
|
||||||
|
@ -1057,7 +1069,7 @@ def ratings_list():
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def formats_list():
|
def formats_list():
|
||||||
if current_user.check_visibility(constants.SIDEBAR_FORMAT):
|
if current_user.check_visibility(constants.SIDEBAR_FORMAT):
|
||||||
if current_user.get_view_property('ratings', 'dir') == 'desc':
|
if current_user.get_view_property('formats', 'dir') == 'desc':
|
||||||
order = db.Data.format.desc()
|
order = db.Data.format.desc()
|
||||||
order_no = 0
|
order_no = 0
|
||||||
else:
|
else:
|
||||||
|
@ -1322,7 +1334,7 @@ def handle_login_user(user, remember, message, category):
|
||||||
ub.store_user_session()
|
ub.store_user_session()
|
||||||
flash(message, category=category)
|
flash(message, category=category)
|
||||||
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
|
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
|
||||||
return redirect_back(url_for("web.index"))
|
return redirect_back("web.index")
|
||||||
|
|
||||||
|
|
||||||
def render_login(username="", password=""):
|
def render_login(username="", password=""):
|
||||||
|
@ -1396,7 +1408,7 @@ def login_post():
|
||||||
if user is not None and user.name != "Guest":
|
if user is not None and user.name != "Guest":
|
||||||
ret, __ = reset_password(user.id)
|
ret, __ = reset_password(user.id)
|
||||||
if ret == 1:
|
if ret == 1:
|
||||||
flash(_(u"New Password was send to your email address"), category="info")
|
flash(_(u"New Password was sent to your email address"), category="info")
|
||||||
log.info('Password reset for user "%s" IP-address: %s', username, ip_address)
|
log.info('Password reset for user "%s" IP-address: %s', username, ip_address)
|
||||||
else:
|
else:
|
||||||
log.error(u"An unknown error occurred. Please try again later")
|
log.error(u"An unknown error occurred. Please try again later")
|
||||||
|
|
469
messages.pot
469
messages.pot
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
# GDrive Integration
|
# GDrive Integration
|
||||||
google-api-python-client>=1.7.11,<2.108.0
|
google-api-python-client>=1.7.11,<2.108.0
|
||||||
gevent>20.6.0,<24.0.0
|
gevent>20.6.0,<24.0.0
|
||||||
greenlet>=0.4.17,<2.1.0
|
greenlet>=0.4.17,<3.1.0
|
||||||
httplib2>=0.9.2,<0.23.0
|
httplib2>=0.9.2,<0.23.0
|
||||||
oauth2client>=4.0.0,<4.1.4
|
oauth2client>=4.0.0,<4.1.4
|
||||||
uritemplate>=3.0.0,<4.2.0
|
uritemplate>=3.0.0,<4.2.0
|
||||||
|
@ -38,8 +38,8 @@ faust-cchardet>=2.1.18,<2.1.20
|
||||||
py7zr>=0.15.0,<0.21.0
|
py7zr>=0.15.0,<0.21.0
|
||||||
|
|
||||||
# Comics
|
# Comics
|
||||||
natsort>=2.2.0,<8.4.0
|
natsort>=2.2.0,<8.5.0
|
||||||
comicapi>=2.2.0,<3.3.0
|
comicapi>=2.2.0,<3.3.0
|
||||||
|
|
||||||
# Kobo integration
|
# Kobo integration
|
||||||
jsonschema>=3.2.0,<4.20.0
|
jsonschema>=3.2.0,<4.22.0
|
||||||
|
|
|
@ -68,7 +68,7 @@ include = cps/services*
|
||||||
gdrive =
|
gdrive =
|
||||||
google-api-python-client>=1.7.11,<2.108.0
|
google-api-python-client>=1.7.11,<2.108.0
|
||||||
gevent>20.6.0,<24.0.0
|
gevent>20.6.0,<24.0.0
|
||||||
greenlet>=0.4.17,<2.1.0
|
greenlet>=0.4.17,<3.1.0
|
||||||
httplib2>=0.9.2,<0.23.0
|
httplib2>=0.9.2,<0.23.0
|
||||||
oauth2client>=4.0.0,<4.1.4
|
oauth2client>=4.0.0,<4.1.4
|
||||||
uritemplate>=3.0.0,<4.2.0
|
uritemplate>=3.0.0,<4.2.0
|
||||||
|
@ -99,8 +99,8 @@ metadata =
|
||||||
faust-cchardet>=2.1.18,<2.1.20
|
faust-cchardet>=2.1.18,<2.1.20
|
||||||
py7zr>=0.15.0,<0.21.0
|
py7zr>=0.15.0,<0.21.0
|
||||||
comics =
|
comics =
|
||||||
natsort>=2.2.0,<8.4.0
|
natsort>=2.2.0,<8.5.0
|
||||||
comicapi>=2.2.0,<3.3.0
|
comicapi>=2.2.0,<3.3.0
|
||||||
kobo =
|
kobo =
|
||||||
jsonschema>=3.2.0,<4.20.0
|
jsonschema>=3.2.0,<4.22.0
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user