mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-26 01:50:31 +00:00
Implement split library and books
Bugfix arrows in comic reader Fix kobo download link Updated requirement
This commit is contained in:
parent
fad6550ff1
commit
d68e57c4fc
@ -1725,6 +1725,9 @@ def _db_configuration_update_helper():
|
|||||||
calibre_db.update_config(config)
|
calibre_db.update_config(config)
|
||||||
if not os.access(os.path.join(config.config_calibre_dir, "metadata.db"), os.W_OK):
|
if not os.access(os.path.join(config.config_calibre_dir, "metadata.db"), os.W_OK):
|
||||||
flash(_("DB is not Writeable"), category="warning")
|
flash(_("DB is not Writeable"), category="warning")
|
||||||
|
_config_string(to_save, "config_calibre_split_dir")
|
||||||
|
config.config_calibre_split = to_save.get('config_calibre_split', 0) == "on"
|
||||||
|
calibre_db.update_config(config)
|
||||||
config.save()
|
config.save()
|
||||||
return _db_configuration_result(None, gdrive_error)
|
return _db_configuration_result(None, gdrive_error)
|
||||||
|
|
||||||
|
@ -69,6 +69,8 @@ class _Settings(_Base):
|
|||||||
|
|
||||||
config_calibre_dir = Column(String)
|
config_calibre_dir = Column(String)
|
||||||
config_calibre_uuid = Column(String)
|
config_calibre_uuid = Column(String)
|
||||||
|
config_calibre_split = Column(Boolean, default=False)
|
||||||
|
config_calibre_split_dir = Column(String)
|
||||||
config_port = Column(Integer, default=constants.DEFAULT_PORT)
|
config_port = Column(Integer, default=constants.DEFAULT_PORT)
|
||||||
config_external_port = Column(Integer, default=constants.DEFAULT_PORT)
|
config_external_port = Column(Integer, default=constants.DEFAULT_PORT)
|
||||||
config_certfile = Column(String)
|
config_certfile = Column(String)
|
||||||
@ -389,6 +391,9 @@ class ConfigSQL(object):
|
|||||||
self.db_configured = False
|
self.db_configured = False
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def get_book_path(self):
|
||||||
|
return self.config_calibre_split_dir if self.config_calibre_split_dir else self.config_calibre_dir
|
||||||
|
|
||||||
def store_calibre_uuid(self, calibre_db, Library_table):
|
def store_calibre_uuid(self, calibre_db, Library_table):
|
||||||
try:
|
try:
|
||||||
calibre_uuid = calibre_db.session.query(Library_table).one_or_none()
|
calibre_uuid = calibre_db.session.query(Library_table).one_or_none()
|
||||||
|
22
cps/editbooks.py
Executable file → Normal file
22
cps/editbooks.py
Executable file → Normal file
@ -126,7 +126,7 @@ def edit_book(book_id):
|
|||||||
edited_books_id = book.id
|
edited_books_id = book.id
|
||||||
modify_date = True
|
modify_date = True
|
||||||
title_author_error = helper.update_dir_structure(edited_books_id,
|
title_author_error = helper.update_dir_structure(edited_books_id,
|
||||||
config.config_calibre_dir,
|
config.get_book_path(),
|
||||||
input_authors[0],
|
input_authors[0],
|
||||||
renamed_author=renamed)
|
renamed_author=renamed)
|
||||||
if title_author_error:
|
if title_author_error:
|
||||||
@ -271,7 +271,7 @@ def upload():
|
|||||||
meta.extension.lower())
|
meta.extension.lower())
|
||||||
else:
|
else:
|
||||||
error = helper.update_dir_structure(book_id,
|
error = helper.update_dir_structure(book_id,
|
||||||
config.config_calibre_dir,
|
config.get_book_path(),
|
||||||
input_authors[0],
|
input_authors[0],
|
||||||
meta.file_path,
|
meta.file_path,
|
||||||
title_dir + meta.extension.lower(),
|
title_dir + meta.extension.lower(),
|
||||||
@ -321,7 +321,7 @@ def convert_bookformat(book_id):
|
|||||||
return redirect(url_for('edit-book.show_edit_book', book_id=book_id))
|
return redirect(url_for('edit-book.show_edit_book', book_id=book_id))
|
||||||
|
|
||||||
log.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to)
|
log.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to)
|
||||||
rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(),
|
rtn = helper.convert_book_format(book_id, config.get_book_path(), book_format_from.upper(),
|
||||||
book_format_to.upper(), current_user.name)
|
book_format_to.upper(), current_user.name)
|
||||||
|
|
||||||
if rtn is None:
|
if rtn is None:
|
||||||
@ -391,7 +391,7 @@ def edit_list_book(param):
|
|||||||
elif param == 'title':
|
elif param == 'title':
|
||||||
sort_param = book.sort
|
sort_param = book.sort
|
||||||
if handle_title_on_edit(book, vals.get('value', "")):
|
if handle_title_on_edit(book, vals.get('value', "")):
|
||||||
rename_error = helper.update_dir_structure(book.id, config.config_calibre_dir)
|
rename_error = helper.update_dir_structure(book.id, config.get_book_path())
|
||||||
if not rename_error:
|
if not rename_error:
|
||||||
ret = Response(json.dumps({'success': True, 'newValue': book.title}),
|
ret = Response(json.dumps({'success': True, 'newValue': book.title}),
|
||||||
mimetype='application/json')
|
mimetype='application/json')
|
||||||
@ -409,7 +409,7 @@ def edit_list_book(param):
|
|||||||
mimetype='application/json')
|
mimetype='application/json')
|
||||||
elif param == 'authors':
|
elif param == 'authors':
|
||||||
input_authors, __, renamed = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == "true")
|
input_authors, __, renamed = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == "true")
|
||||||
rename_error = helper.update_dir_structure(book.id, config.config_calibre_dir, input_authors[0],
|
rename_error = helper.update_dir_structure(book.id, config.get_book_path(), input_authors[0],
|
||||||
renamed_author=renamed)
|
renamed_author=renamed)
|
||||||
if not rename_error:
|
if not rename_error:
|
||||||
ret = Response(json.dumps({
|
ret = Response(json.dumps({
|
||||||
@ -513,10 +513,10 @@ def merge_list_book():
|
|||||||
for element in from_book.data:
|
for element in from_book.data:
|
||||||
if element.format not in to_file:
|
if element.format not in to_file:
|
||||||
# create new data entry with: book_id, book_format, uncompressed_size, name
|
# create new data entry with: book_id, book_format, uncompressed_size, name
|
||||||
filepath_new = os.path.normpath(os.path.join(config.config_calibre_dir,
|
filepath_new = os.path.normpath(os.path.join(config.get_book_path(),
|
||||||
to_book.path,
|
to_book.path,
|
||||||
to_name + "." + element.format.lower()))
|
to_name + "." + element.format.lower()))
|
||||||
filepath_old = os.path.normpath(os.path.join(config.config_calibre_dir,
|
filepath_old = os.path.normpath(os.path.join(config.get_book_path(),
|
||||||
from_book.path,
|
from_book.path,
|
||||||
element.name + "." + element.format.lower()))
|
element.name + "." + element.format.lower()))
|
||||||
copyfile(filepath_old, filepath_new)
|
copyfile(filepath_old, filepath_new)
|
||||||
@ -556,7 +556,7 @@ def table_xchange_author_title():
|
|||||||
|
|
||||||
if edited_books_id:
|
if edited_books_id:
|
||||||
# toDo: Handle error
|
# toDo: Handle error
|
||||||
edit_error = helper.update_dir_structure(edited_books_id, config.config_calibre_dir, input_authors[0],
|
edit_error = helper.update_dir_structure(edited_books_id, config.get_book_path(), input_authors[0],
|
||||||
renamed_author=renamed)
|
renamed_author=renamed)
|
||||||
if modify_date:
|
if modify_date:
|
||||||
book.last_modified = datetime.utcnow()
|
book.last_modified = datetime.utcnow()
|
||||||
@ -753,7 +753,7 @@ def move_coverfile(meta, db_book):
|
|||||||
cover_file = meta.cover
|
cover_file = meta.cover
|
||||||
else:
|
else:
|
||||||
cover_file = os.path.join(constants.STATIC_DIR, 'generic_cover.jpg')
|
cover_file = os.path.join(constants.STATIC_DIR, 'generic_cover.jpg')
|
||||||
new_cover_path = os.path.join(config.config_calibre_dir, db_book.path)
|
new_cover_path = os.path.join(config.get_book_path(), db_book.path)
|
||||||
try:
|
try:
|
||||||
os.makedirs(new_cover_path, exist_ok=True)
|
os.makedirs(new_cover_path, exist_ok=True)
|
||||||
copyfile(cover_file, os.path.join(new_cover_path, "cover.jpg"))
|
copyfile(cover_file, os.path.join(new_cover_path, "cover.jpg"))
|
||||||
@ -839,7 +839,7 @@ def delete_book_from_table(book_id, book_format, json_response):
|
|||||||
book = calibre_db.get_book(book_id)
|
book = calibre_db.get_book(book_id)
|
||||||
if book:
|
if book:
|
||||||
try:
|
try:
|
||||||
result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
|
result, error = helper.delete_book(book, config.get_book_path(), book_format=book_format.upper())
|
||||||
if not result:
|
if not result:
|
||||||
if json_response:
|
if json_response:
|
||||||
return json.dumps([{"location": url_for("edit-book.show_edit_book", book_id=book_id),
|
return json.dumps([{"location": url_for("edit-book.show_edit_book", book_id=book_id),
|
||||||
@ -1172,7 +1172,7 @@ def upload_single_file(file_request, book, book_id):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
file_name = book.path.rsplit('/', 1)[-1]
|
file_name = book.path.rsplit('/', 1)[-1]
|
||||||
filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
|
filepath = os.path.normpath(os.path.join(config.get_book_path(), book.path))
|
||||||
saved_filename = os.path.join(filepath, file_name + '.' + file_ext)
|
saved_filename = os.path.join(filepath, file_name + '.' + file_ext)
|
||||||
|
|
||||||
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
|
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
|
||||||
|
@ -48,7 +48,8 @@ def get_epub_layout(book, book_data):
|
|||||||
'n': 'urn:oasis:names:tc:opendocument:xmlns:container',
|
'n': 'urn:oasis:names:tc:opendocument:xmlns:container',
|
||||||
'pkg': 'http://www.idpf.org/2007/opf',
|
'pkg': 'http://www.idpf.org/2007/opf',
|
||||||
}
|
}
|
||||||
file_path = os.path.normpath(os.path.join(config.config_calibre_dir, book.path, book_data.name + "." + book_data.format.lower()))
|
file_path = os.path.normpath(os.path.join(config.get_book_path(),
|
||||||
|
book.path, book_data.name + "." + book_data.format.lower()))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
epubZip = zipfile.ZipFile(file_path)
|
epubZip = zipfile.ZipFile(file_path)
|
||||||
|
@ -781,7 +781,7 @@ def get_book_cover_internal(book, resolution=None):
|
|||||||
|
|
||||||
# Send the book cover from the Calibre directory
|
# Send the book cover from the Calibre directory
|
||||||
else:
|
else:
|
||||||
cover_file_path = os.path.join(config.config_calibre_dir, book.path)
|
cover_file_path = os.path.join(config.get_book_path(), book.path)
|
||||||
if os.path.isfile(os.path.join(cover_file_path, "cover.jpg")):
|
if os.path.isfile(os.path.join(cover_file_path, "cover.jpg")):
|
||||||
return send_from_directory(cover_file_path, "cover.jpg")
|
return send_from_directory(cover_file_path, "cover.jpg")
|
||||||
else:
|
else:
|
||||||
@ -934,7 +934,7 @@ def save_cover(img, book_path):
|
|||||||
else:
|
else:
|
||||||
return False, message
|
return False, message
|
||||||
else:
|
else:
|
||||||
return save_cover_from_filestorage(os.path.join(config.config_calibre_dir, book_path), "cover.jpg", img)
|
return save_cover_from_filestorage(os.path.join(config.get_book_path(), book_path), "cover.jpg", img)
|
||||||
|
|
||||||
|
|
||||||
def do_download_file(book, book_format, client, data, headers):
|
def do_download_file(book, book_format, client, data, headers):
|
||||||
@ -947,7 +947,7 @@ def do_download_file(book, book_format, client, data, headers):
|
|||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
else:
|
else:
|
||||||
filename = os.path.join(config.config_calibre_dir, book.path)
|
filename = os.path.join(config.get_book_path(), book.path)
|
||||||
if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
|
if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
|
||||||
# ToDo: improve error handling
|
# ToDo: improve error handling
|
||||||
log.error('File not found: %s', os.path.join(filename, data.name + "." + book_format))
|
log.error('File not found: %s', os.path.join(filename, data.name + "." + book_format))
|
||||||
|
@ -205,7 +205,7 @@ def HandleSyncRequest():
|
|||||||
for book in books:
|
for book in books:
|
||||||
formats = [data.format for data in book.Books.data]
|
formats = [data.format for data in book.Books.data]
|
||||||
if 'KEPUB' not in formats and config.config_kepubifypath and 'EPUB' in formats:
|
if 'KEPUB' not in formats and config.config_kepubifypath and 'EPUB' in formats:
|
||||||
helper.convert_book_format(book.Books.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name)
|
helper.convert_book_format(book.Books.id, config.get_book_path(), 'EPUB', 'KEPUB', current_user.name)
|
||||||
|
|
||||||
kobo_reading_state = get_or_create_reading_state(book.Books.id)
|
kobo_reading_state = get_or_create_reading_state(book.Books.id)
|
||||||
entitlement = {
|
entitlement = {
|
||||||
|
@ -179,8 +179,9 @@ kthoom.ImageFile = function(file) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function updateDirectionButtons(){
|
function updateDirectionButtons(){
|
||||||
var left, right = 1;
|
var left = 1;
|
||||||
if (currentImage == 0 ) {
|
var right = 1;
|
||||||
|
if (currentImage <= 0 ) {
|
||||||
if (settings.direction === 0) {
|
if (settings.direction === 0) {
|
||||||
left = 0;
|
left = 0;
|
||||||
} else {
|
} else {
|
||||||
|
6
cps/tasks/convert.py
Executable file → Normal file
6
cps/tasks/convert.py
Executable file → Normal file
@ -62,11 +62,11 @@ class TaskConvert(CalibreTask):
|
|||||||
df = gdriveutils.getFileFromEbooksFolder(cur_book.path,
|
df = gdriveutils.getFileFromEbooksFolder(cur_book.path,
|
||||||
data.name + "." + self.settings['old_book_format'].lower())
|
data.name + "." + self.settings['old_book_format'].lower())
|
||||||
if df:
|
if df:
|
||||||
datafile = os.path.join(config.config_calibre_dir,
|
datafile = os.path.join(config.get_book_path(),
|
||||||
cur_book.path,
|
cur_book.path,
|
||||||
data.name + "." + self.settings['old_book_format'].lower())
|
data.name + "." + self.settings['old_book_format'].lower())
|
||||||
if not os.path.exists(os.path.join(config.config_calibre_dir, cur_book.path)):
|
if not os.path.exists(os.path.join(config.get_book_path(), cur_book.path)):
|
||||||
os.makedirs(os.path.join(config.config_calibre_dir, cur_book.path))
|
os.makedirs(os.path.join(config.get_book_path(), cur_book.path))
|
||||||
df.GetContentFile(datafile)
|
df.GetContentFile(datafile)
|
||||||
worker_db.session.close()
|
worker_db.session.close()
|
||||||
else:
|
else:
|
||||||
|
2
cps/tasks/mail.py
Executable file → Normal file
2
cps/tasks/mail.py
Executable file → Normal file
@ -239,7 +239,7 @@ class TaskEmail(CalibreTask):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _get_attachment(cls, book_path, filename):
|
def _get_attachment(cls, book_path, filename):
|
||||||
"""Get file as MIMEBase message"""
|
"""Get file as MIMEBase message"""
|
||||||
calibre_path = config.config_calibre_dir
|
calibre_path = config.get_book_path()
|
||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
df = gdriveutils.getFileFromEbooksFolder(book_path, filename)
|
df = gdriveutils.getFileFromEbooksFolder(book_path, filename)
|
||||||
if df:
|
if df:
|
||||||
|
@ -114,7 +114,7 @@ class TaskBackupMetadata(CalibreTask):
|
|||||||
True)
|
True)
|
||||||
else:
|
else:
|
||||||
# ToDo: Handle book folder not found or not readable
|
# ToDo: Handle book folder not found or not readable
|
||||||
book_metadata_filepath = os.path.join(config.config_calibre_dir, book.path, 'metadata.opf')
|
book_metadata_filepath = os.path.join(config.get_book_path(), book.path, 'metadata.opf')
|
||||||
# prepare finalize everything and output
|
# prepare finalize everything and output
|
||||||
doc = etree.ElementTree(package)
|
doc = etree.ElementTree(package)
|
||||||
try:
|
try:
|
||||||
|
@ -209,7 +209,7 @@ class TaskGenerateCoverThumbnails(CalibreTask):
|
|||||||
if stream is not None:
|
if stream is not None:
|
||||||
stream.close()
|
stream.close()
|
||||||
else:
|
else:
|
||||||
book_cover_filepath = os.path.join(config.config_calibre_dir, book.path, 'cover.jpg')
|
book_cover_filepath = os.path.join(config.get_book_path(), book.path, 'cover.jpg')
|
||||||
if not os.path.isfile(book_cover_filepath):
|
if not os.path.isfile(book_cover_filepath):
|
||||||
raise Exception('Book cover file not found')
|
raise Exception('Book cover file not found')
|
||||||
|
|
||||||
@ -404,7 +404,7 @@ class TaskGenerateSeriesThumbnails(CalibreTask):
|
|||||||
if stream is not None:
|
if stream is not None:
|
||||||
stream.close()
|
stream.close()
|
||||||
|
|
||||||
book_cover_filepath = os.path.join(config.config_calibre_dir, book.path, 'cover.jpg')
|
book_cover_filepath = os.path.join(config.get_book_path(), book.path, 'cover.jpg')
|
||||||
if not os.path.isfile(book_cover_filepath):
|
if not os.path.isfile(book_cover_filepath):
|
||||||
raise Exception('Book cover file not found')
|
raise Exception('Book cover file not found')
|
||||||
|
|
||||||
|
@ -16,6 +16,18 @@
|
|||||||
<button type="button" data-toggle="modal" id="calibre_modal_path" data-link="config_calibre_dir" data-filefilter="metadata.db" data-target="#fileModal" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
<button type="button" data-toggle="modal" id="calibre_modal_path" data-link="config_calibre_dir" data-filefilter="metadata.db" data-target="#fileModal" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<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 %} >
|
||||||
|
<label for="config_calibre_split">{{_('Separate Book files from Library')}}</label>
|
||||||
|
</div>
|
||||||
|
<div data-related="split_settings">
|
||||||
|
<div class="form-group required input-group">
|
||||||
|
<input type="text" class="form-control" id="config_calibre_split_dir" name="config_calibre_split_dir" value="{% if config.config_calibre_split_dir != None %}{{ config.config_calibre_split_dir }}{% endif %}" autocomplete="off">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button type="button" data-toggle="modal" id="calibre_modal_split_path" data-link="config_calibre_split_dir" data-filefilter="" data-target="#fileModal" id="book_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% if feature_support['gdrive'] %}
|
{% if feature_support['gdrive'] %}
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} >
|
<input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} >
|
||||||
|
6
cps/web.py
Executable file → Normal file
6
cps/web.py
Executable file → Normal file
@ -1192,7 +1192,7 @@ def serve_book(book_id, book_format, anyname):
|
|||||||
if book_format.upper() == 'TXT':
|
if book_format.upper() == 'TXT':
|
||||||
log.info('Serving book: %s', data.name)
|
log.info('Serving book: %s', data.name)
|
||||||
try:
|
try:
|
||||||
rawdata = open(os.path.join(config.config_calibre_dir, book.path, data.name + "." + book_format),
|
rawdata = open(os.path.join(config.get_book_path(), book.path, data.name + "." + book_format),
|
||||||
"rb").read()
|
"rb").read()
|
||||||
result = chardet.detect(rawdata)
|
result = chardet.detect(rawdata)
|
||||||
return make_response(
|
return make_response(
|
||||||
@ -1202,7 +1202,7 @@ def serve_book(book_id, book_format, anyname):
|
|||||||
return "File Not Found"
|
return "File Not Found"
|
||||||
# enable byte range read of pdf
|
# enable byte range read of pdf
|
||||||
response = make_response(
|
response = make_response(
|
||||||
send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format))
|
send_from_directory(os.path.join(config.get_book_path(), book.path), data.name + "." + book_format))
|
||||||
if not range_header:
|
if not range_header:
|
||||||
log.info('Serving book: %s', data.name)
|
log.info('Serving book: %s', data.name)
|
||||||
response.headers['Accept-Ranges'] = 'bytes'
|
response.headers['Accept-Ranges'] = 'bytes'
|
||||||
@ -1226,7 +1226,7 @@ def send_to_ereader(book_id, book_format, convert):
|
|||||||
response = [{'type': "danger", 'message': _("Please configure the SMTP mail settings first...")}]
|
response = [{'type': "danger", 'message': _("Please configure the SMTP mail settings first...")}]
|
||||||
return Response(json.dumps(response), mimetype='application/json')
|
return Response(json.dumps(response), mimetype='application/json')
|
||||||
elif current_user.kindle_mail:
|
elif current_user.kindle_mail:
|
||||||
result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir,
|
result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.get_book_path(),
|
||||||
current_user.name)
|
current_user.name)
|
||||||
if result is None:
|
if result is None:
|
||||||
ub.update_download(book_id, int(current_user.id))
|
ub.update_download(book_id, int(current_user.id))
|
||||||
|
@ -9,7 +9,7 @@ iso-639>=0.4.5,<0.5.0
|
|||||||
PyPDF>=3.0.0,<3.16.0
|
PyPDF>=3.0.0,<3.16.0
|
||||||
pytz>=2016.10
|
pytz>=2016.10
|
||||||
requests>=2.28.0,<2.32.0
|
requests>=2.28.0,<2.32.0
|
||||||
SQLAlchemy>=1.3.0,<2.0.0
|
SQLAlchemy>=1.3.0,<2.1.0
|
||||||
tornado>=6.3,<6.4
|
tornado>=6.3,<6.4
|
||||||
Wand>=0.4.4,<0.7.0
|
Wand>=0.4.4,<0.7.0
|
||||||
unidecode>=0.04.19,<1.4.0
|
unidecode>=0.04.19,<1.4.0
|
||||||
|
@ -49,7 +49,7 @@ install_requires =
|
|||||||
PyPDF>=3.0.0,<3.16.0
|
PyPDF>=3.0.0,<3.16.0
|
||||||
pytz>=2016.10
|
pytz>=2016.10
|
||||||
requests>=2.28.0,<2.32.0
|
requests>=2.28.0,<2.32.0
|
||||||
SQLAlchemy>=1.3.0,<2.0.0
|
SQLAlchemy>=1.3.0,<2.1.0
|
||||||
tornado>=6.3,<6.4
|
tornado>=6.3,<6.4
|
||||||
Wand>=0.4.4,<0.7.0
|
Wand>=0.4.4,<0.7.0
|
||||||
unidecode>=0.04.19,<1.4.0
|
unidecode>=0.04.19,<1.4.0
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user