Merge branch 'master' of https://github.com/janeczku/calibre-web into ebookconvert-any

This commit is contained in:
bodybybuddha
2018-08-28 09:56:08 -04:00
42 changed files with 37648 additions and 3392 deletions
+213 -81
View File
@@ -2,9 +2,7 @@
# -*- coding: utf-8 -*-
try:
from googleapiclient.errors import HttpError
# gdrive_support = True
except ImportError:
# gdrive_support = False
pass
try:
@@ -87,6 +85,7 @@ except ImportError:
import time
import server
import random
current_milli_time = lambda: int(round(time.time() * 1000))
@@ -94,7 +93,8 @@ current_milli_time = lambda: int(round(time.time() * 1000))
# Global variables
gdrive_watch_callback_token = 'target=calibreweb-watch_files'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2'])
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
'fb2'}
def md5(fname):
hash_md5 = hashlib.md5()
@@ -136,9 +136,9 @@ class ReverseProxied(object):
scheme = environ.get('HTTP_X_SCHEME', '')
if scheme:
environ['wsgi.url_scheme'] = scheme
server = environ.get('HTTP_X_FORWARDED_SERVER', '')
if server:
environ['HTTP_HOST'] = server
servr = environ.get('HTTP_X_FORWARDED_SERVER', '')
if servr:
environ['HTTP_HOST'] = servr
return self.app(environ, start_response)
@@ -185,8 +185,8 @@ db.setup_db()
def is_gdrive_ready():
return os.path.exists(os.path.join(config.get_main_dir,'settings.yaml')) and \
os.path.exists(os.path.join(config.get_main_dir,'gdrive_credentials'))
return os.path.exists(os.path.join(config.get_main_dir, 'settings.yaml')) and \
os.path.exists(os.path.join(config.get_main_dir, 'gdrive_credentials'))
@babel.localeselector
@@ -287,10 +287,10 @@ class Pagination(object):
def has_next(self):
return self.page < self.pages
# right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shown
# left_edge: first left_edges count of all pages are shown as number -> 1,2 shown
# left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shown
# left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shown
# right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shwn
# left_edge: first left_edges count of all pages are shown as number -> 1,2 shwn
# left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shwn
# left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shwn
def iter_pages(self, left_edge=2, left_current=2,
right_current=4, right_edge=2):
last = 0
@@ -321,7 +321,7 @@ def remote_login_required(f):
return f(*args, **kwargs)
if request.is_xhr:
data = {'status': 'error', 'message': 'Forbidden'}
response = make_response(json.dumps(data, ensure_ascii=false))
response = make_response(json.dumps(data, ensure_ascii=False))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response, 403
abort(403)
@@ -338,9 +338,10 @@ def url_for_other_page(page):
args['page'] = page
return url_for(request.endpoint, **args)
# shortentitles to at longest nchar, shorten longer words if necessary
@app.template_filter('shortentitle')
def shortentitle_filter(s,nchar=20):
def shortentitle_filter(s, nchar=20):
text = s.split()
res = "" # result
suml = 0 # overall length
@@ -471,7 +472,7 @@ def common_filters():
# Creates for all stored languages a translated speaking name in the array for the UI
def speaking_language(languages = None):
def speaking_language(languages=None):
if not languages:
languages = db.session.query(db.Languages).all()
for lang in languages:
@@ -486,17 +487,17 @@ def speaking_language(languages = None):
# Fill indexpage with all requested data from database
def fill_indexpage(page, database, db_filter, order, *join):
if current_user.show_detail_random():
random = db.session.query(db.Books).filter(common_filters())\
randm = db.session.query(db.Books).filter(common_filters())\
.order_by(func.random()).limit(config.config_random_books)
else:
random = false
randm = false()
off = int(int(config.config_books_per_page) * (page - 1))
pagination = Pagination(page, config.config_books_per_page,
len(db.session.query(database)
.filter(db_filter).filter(common_filters()).all()))
entries = db.session.query(database).join(*join,isouter=True).filter(db_filter)\
.filter(common_filters()).order_by(*order).offset(off).limit(config.config_books_per_page).all()
return entries, random, pagination
return entries, randm, pagination
# Modifies different Database objects, first check if elements have to be added to database, than check
@@ -893,6 +894,73 @@ def get_email_status_json():
return response
# checks if domain is in database (including wildcards)
# example SELECT * FROM @TABLE WHERE 'abcdefg' LIKE Name;
# from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/
def check_valid_domain(domain_text):
# result = session.query(Notification).from_statement(text(sql)).params(id=5).all()
#ToDo: check possible SQL injection
domain_text = domain_text.split('@',1)[-1].lower()
sql = "SELECT * FROM registration WHERE '%s' LIKE domain;" % domain_text
result = ub.session.query(ub.Registration).from_statement(text(sql)).all()
return len(result)
''' POST /post
{
name: 'username', //name of field (column in db)
pk: 1 //primary key (record id)
value: 'superuser!' //new value
}'''
@app.route("/ajax/editdomain", methods=['POST'])
@login_required
@admin_required
def edit_domain():
vals = request.form.to_dict()
answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first()
# domain_name = request.args.get('domain')
answer.domain = vals['value'].replace('*','%').replace('?','_').lower()
ub.session.commit()
return ""
@app.route("/ajax/adddomain", methods=['POST'])
@login_required
@admin_required
def add_domain():
domain_name = request.form.to_dict()['domainname'].replace('*','%').replace('?','_').lower()
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).first()
if not check:
new_domain = ub.Registration(domain=domain_name)
ub.session.add(new_domain)
ub.session.commit()
return ""
@app.route("/ajax/deletedomain", methods=['POST'])
@login_required
@admin_required
def delete_domain():
domain_id = request.form.to_dict()['domainid'].replace('*','%').replace('?','_').lower()
ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete()
ub.session.commit()
# If last domain was deleted, add all domains by default
if not ub.session.query(ub.Registration).count():
new_domain = ub.Registration(domain="%.%")
ub.session.add(new_domain)
ub.session.commit()
return ""
@app.route("/ajax/domainlist")
@login_required
@admin_required
def list_domain():
answer = ub.session.query(ub.Registration).all()
json_dumps = json.dumps([{"domain":r.domain.replace('%','*').replace('_','?'),"id":r.id} for r in answer])
js=json.dumps(json_dumps.replace('"', "'")).lstrip('"').strip('"')
response = make_response(js.replace("'",'"'))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
@app.route("/get_authors_json", methods=['GET', 'POST'])
@login_required_if_no_ano
def get_authors_json():
@@ -1076,7 +1144,7 @@ def hot_books(page):
random = db.session.query(db.Books).filter(common_filters())\
.order_by(func.random()).limit(config.config_random_books)
else:
random = false
random = false()
off = int(int(config.config_books_per_page) * (page - 1))
all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(
ub.func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
@@ -1996,30 +2064,38 @@ def register():
if request.method == "POST":
to_save = request.form.to_dict()
if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
if not to_save["nickname"] or not to_save["email"]:
flash(_(u"Please fill out all fields!"), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
existing_user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == to_save["nickname"].lower()).first()
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"]).first()
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"].lower()).first()
if not existing_user and not existing_email:
content = ub.User()
content.password = generate_password_hash(to_save["password"])
content.nickname = to_save["nickname"]
content.email = to_save["email"]
content.role = config.config_default_role
content.sidebar_view = config.config_default_show
try:
ub.session.add(content)
ub.session.commit()
except Exception:
ub.session.rollback()
flash(_(u"An unknown error occured. Please try again later."), category="error")
# content.password = generate_password_hash(to_save["password"])
if check_valid_domain(to_save["email"]):
content.nickname = to_save["nickname"]
content.email = to_save["email"]
password = helper.generate_random_password()
content.password = generate_password_hash(password)
content.role = config.config_default_role
content.sidebar_view = config.config_default_show
try:
ub.session.add(content)
ub.session.commit()
helper.send_registration_mail(to_save["email"],to_save["nickname"], password)
except Exception:
ub.session.rollback()
flash(_(u"An unknown error occurred. Please try again later."), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
else:
flash(_(u"Your e-mail is not allowed to register"), category="error")
app.logger.info('Registering failed for user "' + to_save['nickname'] + '" e-mail adress: ' + to_save["email"])
return render_title_template('register.html', title=_(u"register"), page="register")
flash("Your account has been created. Please login.", category="success")
flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success")
return redirect(url_for('login'))
else:
flash(_(u"This username or email address is already in use."), category="error")
flash(_(u"This username or e-mail address is already in use."), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
return render_title_template('register.html', title=_(u"register"), page="register")
@@ -2134,7 +2210,7 @@ def token_verified():
data['status'] = 'success'
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
response = make_response(json.dumps(data, ensure_ascii=false))
response = make_response(json.dumps(data, ensure_ascii=False))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
@@ -2156,7 +2232,7 @@ def send_to_kindle(book_id):
else:
flash(_(u"There was an error sending this book: %(res)s", res=result), category="error")
else:
flash(_(u"Please configure your kindle email address first..."), category="error")
flash(_(u"Please configure your kindle e-mail address first..."), category="error")
return redirect(request.environ["HTTP_REFERER"])
@@ -2363,7 +2439,7 @@ def edit_shelf(shelf_id):
@login_required
def delete_shelf(shelf_id):
cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
deleted = false
deleted = None
if current_user.role_admin():
deleted = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).delete()
else:
@@ -2456,17 +2532,21 @@ def profile():
to_save = request.form.to_dict()
content.random_books = 0
if current_user.role_passwd() or current_user.role_admin():
if to_save["password"]:
if "password" in to_save:
content.password = generate_password_hash(to_save["password"])
if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
content.kindle_mail = to_save["kindle_mail"]
if to_save["email"] and to_save["email"] != content.email:
if config.config_public_reg and not check_valid_domain(to_save["email"]):
flash(_(u"E-mail is not from valid domain"), category="error")
return render_title_template("user_edit.html", content=content, downloads=downloads,
title=_(u"%(name)s's profile", name=current_user.nickname))
content.email = to_save["email"]
if "show_random" in to_save and to_save["show_random"] == "on":
content.random_books = 1
if "default_language" in to_save:
content.default_language = to_save["default_language"]
if to_save["locale"]:
if "locale" in to_save:
content.locale = to_save["locale"]
content.sidebar_view = 0
if "show_random" in to_save:
@@ -2499,7 +2579,7 @@ def profile():
ub.session.commit()
except IntegrityError:
ub.session.rollback()
flash(_(u"Found an existing account for this email address."), category="error")
flash(_(u"Found an existing account for this e-mail address."), category="error")
return render_title_template("user_edit.html", content=content, downloads=downloads,
title=_(u"%(name)s's profile", name=current_user.nickname))
flash(_(u"Profile updated"), category="success")
@@ -2606,7 +2686,7 @@ def view_configuration():
if "show_mature_content" in to_save:
content.config_default_show = content.config_default_show + ub.MATURE_CONTENT
ub.session.commit()
flash(_(u"Calibre-web configuration updated"), category="success")
flash(_(u"Calibre-Web configuration updated"), category="success")
config.loadSettings()
if reboot_required:
# db.engine.dispose() # ToDo verify correct
@@ -2634,6 +2714,7 @@ def configuration_helper(origin):
gdriveError=None
db_change = False
success = False
filedata = None
if gdriveutils.gdrive_support == False:
gdriveError = _('Import of optional Google Drive requirements missing')
else:
@@ -2644,7 +2725,6 @@ def configuration_helper(origin):
filedata=json.load(settings)
if not 'web' in filedata:
gdriveError = _('client_secrets.json is not configured for web application')
filedata = None
if request.method == "POST":
to_save = request.form.to_dict()
content = ub.session.query(ub.Settings).first() # type: ub.Settings
@@ -2768,7 +2848,7 @@ def configuration_helper(origin):
db.session.close()
db.engine.dispose()
ub.session.commit()
flash(_(u"Calibre-web configuration updated"), category="success")
flash(_(u"Calibre-Web configuration updated"), category="success")
config.loadSettings()
app.logger.setLevel(config.config_log_level)
logging.getLogger("book_formats").setLevel(config.config_log_level)
@@ -2793,10 +2873,10 @@ def configuration_helper(origin):
app.logger.info('Reboot required, restarting')
if origin:
success = True
if is_gdrive_ready() and gdriveutils.gdrive_support == True:
if is_gdrive_ready() and gdriveutils.gdrive_support == True and config.config_use_google_drive == True:
gdrivefolders=gdriveutils.listRootFolders()
else:
gdrivefolders=None
gdrivefolders=list()
return render_title_template("config_edit.html", origin=origin, success=success, content=config,
show_authenticate_google_drive=not is_gdrive_ready(), gdrive=gdriveutils.gdrive_support,
gdriveError=gdriveError, gdrivefolders=gdrivefolders,
@@ -2812,13 +2892,6 @@ def new_user():
translations = [LC('en')] + babel.list_translations()
if request.method == "POST":
to_save = request.form.to_dict()
if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
flash(_(u"Please fill out all fields!"), category="error")
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
title=_(u"Add new user"))
content.password = generate_password_hash(to_save["password"])
content.nickname = to_save["nickname"]
content.email = to_save["email"]
content.default_language = to_save["default_language"]
content.mature_content = "show_mature_content" in to_save
content.theme = int(to_save["theme"])
@@ -2858,6 +2931,18 @@ def new_user():
content.role = content.role + ub.ROLE_PASSWD
if "edit_shelf_role" in to_save:
content.role = content.role + ub.ROLE_EDIT_SHELFS
if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
flash(_(u"Please fill out all fields!"), category="error")
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
title=_(u"Add new user"))
content.password = generate_password_hash(to_save["password"])
content.nickname = to_save["nickname"]
if config.config_public_reg and not check_valid_domain(to_save["email"]):
flash(_(u"E-mail is not from valid domain"), category="error")
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
title=_(u"Add new user"))
else:
content.email = to_save["email"]
try:
ub.session.add(content)
ub.session.commit()
@@ -2865,7 +2950,7 @@ def new_user():
return redirect(url_for('admin'))
except IntegrityError:
ub.session.rollback()
flash(_(u"Found an existing account for this email address or nickname."), category="error")
flash(_(u"Found an existing account for this e-mail address or nickname."), category="error")
else:
content.role = config.config_default_role
content.sidebar_view = config.config_default_show
@@ -2889,22 +2974,23 @@ def edit_mailsettings():
content.mail_use_ssl = int(to_save["mail_use_ssl"])
try:
ub.session.commit()
flash(_(u"Mail settings updated"), category="success")
flash(_(u"E-mail server settings updated"), category="success")
except Exception as e:
flash(e, category="error")
if "test" in to_save and to_save["test"]:
if current_user.kindle_mail:
result = helper.send_test_mail(current_user.kindle_mail, current_user.nickname)
if result is None:
flash(_(u"Test E-Mail successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail),
flash(_(u"Test e-mail successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail),
category="success")
else:
flash(_(u"There was an error sending the Test E-Mail: %(res)s", res=result), category="error")
flash(_(u"There was an error sending the Test e-mail: %(res)s", res=result), category="error")
else:
flash(_(u"Please configure your kindle email address first..."), category="error")
flash(_(u"Please configure your kindle e-mail address first..."), category="error")
else:
flash(_(u"E-Mail settings updated"), category="success")
return render_title_template("email_edit.html", content=content, title=_(u"Edit mail settings"), page="mailset")
flash(_(u"E-mail server settings updated"), category="success")
return render_title_template("email_edit.html", content=content, title=_(u"Edit e-mail server settings"),
page="mailset")
@app.route("/admin/user/<int:user_id>", methods=["GET", "POST"])
@@ -2916,9 +3002,9 @@ def edit_user(user_id):
languages = speaking_language()
translations = babel.list_translations() + [LC('en')]
for book in content.downloads:
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
if downloadBook:
downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
downloadbook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
if downloadbook:
downloads.append(downloadbook)
else:
ub.delete_download(book.book_id)
# ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete()
@@ -3046,6 +3132,26 @@ def edit_user(user_id):
nick=content.nickname), page="edituser")
@app.route("/admin/resetpassword/<int:user_id>")
@login_required
@admin_required
def reset_password(user_id):
if not config.config_public_reg:
abort(404)
if current_user is not None and current_user.is_authenticated:
existing_user = ub.session.query(ub.User).filter(ub.User.id == user_id).first()
password = helper.generate_random_password()
existing_user.password = generate_password_hash(password)
try:
ub.session.commit()
helper.send_registration_mail(existing_user.email, existing_user.nickname, password, True)
flash(_(u"Password for user %s reset" % existing_user.nickname), category="success")
except Exception:
ub.session.rollback()
flash(_(u"An unknown error occurred. Please try again later."), category="error")
return redirect(url_for('admin'))
@app.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
@login_required_if_no_ano
@edit_required
@@ -3062,14 +3168,14 @@ def edit_book(book_id):
flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error")
return redirect(url_for("index"))
for index in range(0, len(book.languages)):
for indx in range(0, len(book.languages)):
try:
book.languages[index].language_name = LC.parse(book.languages[index].lang_code).get_language_name(
book.languages[indx].language_name = LC.parse(book.languages[indx].lang_code).get_language_name(
get_locale())
except Exception:
book.languages[index].language_name = _(isoLanguages.get(part3=book.languages[index].lang_code).name)
for author in book.authors:
author_names.append(author.name.replace('|', ','))
book.languages[indx].language_name = _(isoLanguages.get(part3=book.languages[indx].lang_code).name)
for authr in book.authors:
author_names.append(authr.name.replace('|', ','))
#Option for showing convertbook button
if config.config_ebookconverter == 2:
@@ -3097,7 +3203,7 @@ def edit_book(book_id):
conversion_formats=allowed_conversion_formats)
# Update book
edited_books_id = set()
edited_books_id = {}
# Check and handle Uploaded file
if 'btn-upload-format' in request.files:
@@ -3107,7 +3213,8 @@ def edit_book(book_id):
if '.' in requested_file.filename:
file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
if file_ext not in ALLOWED_EXTENSIONS:
flash(_('File extension "%s" is not allowed to be uploaded to this server' % file_ext), category="error")
flash(_('File extension "%s" is not allowed to be uploaded to this server' % file_ext),
category="error")
return redirect(url_for('show_book', book_id=book.id))
else:
flash(_('File to be uploaded must have an extension'), category="error")
@@ -3143,10 +3250,36 @@ def edit_book(book_id):
db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
# Queue uploader info
uploadText=_(u"File format %s added to %s" % (file_ext.upper(),book.title))
uploadText=_(u"File format %s added to %s" % (file_ext.upper(), book.title))
helper.global_WorkerThread.add_upload(current_user.nickname,
"<a href=\""+ url_for('show_book', book_id=book.id) +"\">"+ uploadText + "</a>")
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
if 'btn-upload-cover' in request.files:
requested_file = request.files['btn-upload-cover']
# check for empty request
if requested_file.filename != '':
file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
# file_name = book.path.rsplit('/', 1)[-1]
filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
saved_filename = os.path.join(filepath, 'cover.' + file_ext)
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
if not os.path.exists(filepath):
try:
os.makedirs(filepath)
except OSError:
flash(_(u"Failed to create path for cover %s (Permission denied)." % filepath), category="error")
return redirect(url_for('show_book', book_id=book.id))
try:
requested_file.save(saved_filename)
# im=Image.open(saved_filename)
book.has_cover = 1
except OSError:
flash(_(u"Failed to store cover-file %s." % saved_filename), category="error")
return redirect(url_for('show_book', book_id=book.id))
except IOError:
flash(_(u"Cover-file is not a valid image file" % saved_filename), category="error")
return redirect(url_for('show_book', book_id=book.id))
to_save = request.form.to_dict()
try:
@@ -3316,13 +3449,14 @@ def edit_book(book_id):
else:
input_tags = to_save[cc_string].split(',')
input_tags = list(map(lambda it: it.strip(), input_tags))
modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], db.session, 'custom')
modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], db.session,
'custom')
db.session.commit()
if config.config_use_google_drive:
gdriveutils.updateGdriveCalibreFromLocal()
author_names = []
for author in book.authors:
author_names.append(author.name)
for authr in book.authors:
author_names.append(authr.name)
if "detail_view" in to_save:
return redirect(url_for('show_book', book_id=book.id))
else:
@@ -3358,9 +3492,7 @@ def upload():
if file_ext not in ALLOWED_EXTENSIONS:
flash(
_('File extension "%s" is not allowed to be uploaded to this server' %
file_ext),
category="error"
)
file_ext), category="error")
return redirect(url_for('index'))
else:
flash(_('File to be uploaded must have an extension'), category="error")
@@ -3369,12 +3501,12 @@ def upload():
# extract metadata from file
meta = uploader.upload(requested_file)
title = meta.title
author = meta.author
authr = meta.author
tags = meta.tags
series = meta.series
series_index = meta.series_id
title_dir = helper.get_valid_filename(title)
author_dir = helper.get_valid_filename(author)
author_dir = helper.get_valid_filename(authr)
filepath = os.path.join(config.config_calibre_dir, author_dir, title_dir)
saved_filename = os.path.join(filepath, title_dir + meta.extension.lower())
@@ -3403,11 +3535,11 @@ def upload():
move(meta.cover, os.path.join(filepath, "cover.jpg"))
# handle authors
is_author = db.session.query(db.Authors).filter(db.Authors.name == author).first()
is_author = db.session.query(db.Authors).filter(db.Authors.name == authr).first()
if is_author:
db_author = is_author
else:
db_author = db.Authors(author, helper.get_sorted_author(author), "")
db_author = db.Authors(authr, helper.get_sorted_author(authr), "")
db.session.add(db_author)
# handle series