Commit b160a8de authored by Ozzieisaacs's avatar Ozzieisaacs

Merge branch 'master' into Develop

# Conflicts:
#	cps/__init__.py
#	cps/comic.py
#	cps/editbooks.py
#	cps/helper.py
#	cps/kobo.py
#	cps/translations/nl/LC_MESSAGES/messages.mo
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/ub.py
#	cps/uploader.py
#	cps/web.py
parents 27eb09fb e3246fd7
......@@ -36,6 +36,10 @@ from flask_principal import Principal
from . import config_sql, logger, cache_buster, cli, ub, db
from .reverseproxy import ReverseProxied
from .server import WebServer
try:
from werkzeug.middleware.proxy_fix import ProxyFix
except ImportError:
from werkzeug.contrib.fixers import ProxyFix
mimetypes.init()
mimetypes.add_type('application/xhtml+xml', '.xhtml')
......@@ -76,7 +80,10 @@ log = logger.create()
from . import services
def create_app():
app.wsgi_app = ReverseProxied(app.wsgi_app)
try:
app.wsgi_app = ReverseProxied(ProxyFix(app.wsgi_app, x_for=1, x_host=1))
except TypeError:
app.wsgi_app = ReverseProxied(ProxyFix(app.wsgi_app))
# For python2 convert path to unicode
if sys.version_info < (3, 0):
app.static_folder = app.static_folder.decode('utf-8')
......@@ -88,7 +95,10 @@ def create_app():
log.info('Starting Calibre Web...')
Principal(app)
lm.init_app(app)
app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT')
if os.environ.get('FLASK_DEBUG'):
app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT')
else:
app.secret_key = os.getenv('SECRET_KEY', os.urandom(32))
web_server.init_app(app, config)
db.setup_db(config)
......
......@@ -50,11 +50,11 @@ feature_support = {
'kobo': bool(services.kobo)
}
# try:
# import rarfile
# feature_support['rar'] = True
# except ImportError:
# feature_support['rar'] = False
try:
import rarfile
feature_support['rar'] = True
except ImportError:
feature_support['rar'] = False
try:
from .oauth_bb import oauth_check, oauthblueprints
......@@ -253,23 +253,23 @@ def list_domain(allow):
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
@admi.route("/ajax/editrestriction/<int:type>", methods=['POST'])
@admi.route("/ajax/editrestriction/<int:res_type>", methods=['POST'])
@login_required
@admin_required
def edit_restriction(type):
def edit_restriction(res_type):
element = request.form.to_dict()
if element['id'].startswith('a'):
if type == 0: # Tags as template
if res_type == 0: # Tags as template
elementlist = config.list_allowed_tags()
elementlist[int(element['id'][1:])]=element['Element']
config.config_allowed_tags = ','.join(elementlist)
config.save()
if type == 1: # CustomC
if res_type == 1: # CustomC
elementlist = config.list_allowed_column_values()
elementlist[int(element['id'][1:])]=element['Element']
config.config_allowed_column_value = ','.join(elementlist)
config.save()
if type == 2: # Tags per user
if res_type == 2: # Tags per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -279,7 +279,7 @@ def edit_restriction(type):
elementlist[int(element['id'][1:])]=element['Element']
usr.allowed_tags = ','.join(elementlist)
ub.session.commit()
if type == 3: # CColumn per user
if res_type == 3: # CColumn per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -290,18 +290,17 @@ def edit_restriction(type):
usr.allowed_column_value = ','.join(elementlist)
ub.session.commit()
if element['id'].startswith('d'):
if type == 0: # Tags as template
if res_type == 0: # Tags as template
elementlist = config.list_denied_tags()
elementlist[int(element['id'][1:])]=element['Element']
config.config_denied_tags = ','.join(elementlist)
config.save()
if type == 1: # CustomC
if res_type == 1: # CustomC
elementlist = config.list_denied_column_values()
elementlist[int(element['id'][1:])]=element['Element']
config.config_denied_column_value = ','.join(elementlist)
config.save()
pass
if type == 2: # Tags per user
if res_type == 2: # Tags per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -311,7 +310,7 @@ def edit_restriction(type):
elementlist[int(element['id'][1:])]=element['Element']
usr.denied_tags = ','.join(elementlist)
ub.session.commit()
if type == 3: # CColumn per user
if res_type == 3: # CColumn per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -339,26 +338,26 @@ def restriction_deletion(element, list_func):
return ','.join(elementlist)
@admi.route("/ajax/addrestriction/<int:type>", methods=['POST'])
@admi.route("/ajax/addrestriction/<int:res_type>", methods=['POST'])
@login_required
@admin_required
def add_restriction(type):
def add_restriction(res_type):
element = request.form.to_dict()
if type == 0: # Tags as template
if res_type == 0: # Tags as template
if 'submit_allow' in element:
config.config_allowed_tags = restriction_addition(element, config.list_allowed_tags)
config.save()
elif 'submit_deny' in element:
config.config_denied_tags = restriction_addition(element, config.list_denied_tags)
config.save()
if type == 1: # CCustom as template
if res_type == 1: # CCustom as template
if 'submit_allow' in element:
config.config_allowed_column_value = restriction_addition(element, config.list_denied_column_values)
config.save()
elif 'submit_deny' in element:
config.config_denied_column_value = restriction_addition(element, config.list_allowed_column_values)
config.save()
if type == 2: # Tags per user
if res_type == 2: # Tags per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -370,7 +369,7 @@ def add_restriction(type):
elif 'submit_deny' in element:
usr.denied_tags = restriction_addition(element, usr.list_denied_tags)
ub.session.commit()
if type == 3: # CustomC per user
if res_type == 3: # CustomC per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -384,26 +383,26 @@ def add_restriction(type):
ub.session.commit()
return ""
@admi.route("/ajax/deleterestriction/<int:type>", methods=['POST'])
@admi.route("/ajax/deleterestriction/<int:res_type>", methods=['POST'])
@login_required
@admin_required
def delete_restriction(type):
def delete_restriction(res_type):
element = request.form.to_dict()
if type == 0: # Tags as template
if res_type == 0: # Tags as template
if element['id'].startswith('a'):
config.config_allowed_tags = restriction_deletion(element, config.list_allowed_tags)
config.save()
elif element['id'].startswith('d'):
config.config_denied_tags = restriction_deletion(element, config.list_denied_tags)
config.save()
elif type == 1: # CustomC as template
elif res_type == 1: # CustomC as template
if element['id'].startswith('a'):
config.config_allowed_column_value = restriction_deletion(element, config.list_allowed_column_values)
config.save()
elif element['id'].startswith('d'):
config.config_denied_column_value = restriction_deletion(element, config.list_denied_column_values)
config.save()
elif type == 2: # Tags per user
elif res_type == 2: # Tags per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -415,7 +414,7 @@ def delete_restriction(type):
elif element['id'].startswith('d'):
usr.denied_tags = restriction_deletion(element, usr.list_denied_tags)
ub.session.commit()
elif type == 3: # Columns per user
elif res_type == 3: # Columns per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True: # select current user if admins are editing their own rights
usr = ub.session.query(ub.User).filter(ub.User.id == int(usr_id)).first()
......@@ -431,23 +430,23 @@ def delete_restriction(type):
#@admi.route("/ajax/listrestriction/<int:type>/<int:user_id>", defaults={'user_id': '0'})
@admi.route("/ajax/listrestriction/<int:type>")
@admi.route("/ajax/listrestriction/<int:res_type>")
@login_required
@admin_required
def list_restriction(type):
if type == 0: # Tags as template
def list_restriction(res_type):
if res_type == 0: # Tags as template
restrict = [{'Element': x, 'type':_('Deny'), 'id': 'd'+str(i) }
for i,x in enumerate(config.list_denied_tags()) if x != '' ]
allow = [{'Element': x, 'type':_('Allow'), 'id': 'a'+str(i) }
for i,x in enumerate(config.list_allowed_tags()) if x != '']
json_dumps = restrict + allow
elif type == 1: # CustomC as template
elif res_type == 1: # CustomC as template
restrict = [{'Element': x, 'type':_('Deny'), 'id': 'd'+str(i) }
for i,x in enumerate(config.list_denied_column_values()) if x != '' ]
allow = [{'Element': x, 'type':_('Allow'), 'id': 'a'+str(i) }
for i,x in enumerate(config.list_allowed_column_values()) if x != '']
json_dumps = restrict + allow
elif type == 2: # Tags per user
elif res_type == 2: # Tags per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id == usr_id).first()
......@@ -458,7 +457,7 @@ def list_restriction(type):
allow = [{'Element': x, 'type':_('Allow'), 'id': 'a'+str(i) }
for i,x in enumerate(usr.list_allowed_tags()) if x != '']
json_dumps = restrict + allow
elif type == 3: # CustomC per user
elif res_type == 3: # CustomC per user
usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True:
usr = ub.session.query(ub.User).filter(ub.User.id==usr_id).first()
......@@ -540,8 +539,7 @@ def _configuration_update_helper():
_config_string("config_calibre")
_config_string("config_converterpath")
if _config_int("config_login_type"):
reboot_required |= config.config_login_type != constants.LOGIN_STANDARD
reboot_required |= _config_int("config_login_type")
#LDAP configurator,
if config.config_login_type == constants.LOGIN_LDAP:
......
......@@ -43,9 +43,9 @@ except ImportError as e:
def _extractCover(tmp_file_name, original_file_extension, rarExceutable):
cover_data = extension = None
if use_comic_meta:
archive = ComicArchive(tmp_file_name)
cover_data = None
for index, name in enumerate(archive.getPageNameList()):
ext = os.path.splitext(name)
if len(ext) > 1:
......@@ -81,7 +81,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExceutable):
if len(ext) > 1:
extension = ext[1].lower()
if extension == '.jpg' or extension == '.jpeg':
cover_data = cf.extractfile(name).read()
cover_data = cf.read(name)
break
except Exception as e:
log.debug('Rarfile failed with error: %s', e)
......@@ -99,7 +99,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExceutable):
def get_comic_info(tmp_file_path, original_file_name, original_file_extension, rarExceutable):
if use_comic_meta:
archive = ComicArchive(tmp_file_path)
archive = ComicArchive(tmp_file_path, rar_exe_path=rarExceutable)
if archive.seemsToBeAComicArchive():
if archive.hasMetadata(MetaDataStyle.CIX):
style = MetaDataStyle.CIX
......@@ -120,7 +120,7 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r
else:
loadedMetadata.language = ""
return BookMeta(
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=loadedMetadata.title or original_file_name,
......@@ -131,16 +131,15 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r
series=loadedMetadata.series or "",
series_id=loadedMetadata.issue or "",
languages=loadedMetadata.language)
else:
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=original_file_name,
author=u'Unknown',
cover=_extractCover(tmp_file_path, original_file_extension, rarExceutable),
description="",
tags="",
series="",
series_id="",
languages="")
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=original_file_name,
author=u'Unknown',
cover=_extractCover(tmp_file_path, original_file_extension, rarExceutable),
description="",
tags="",
series="",
series_id="",
languages="")
......@@ -102,8 +102,8 @@ DEFAULT_MAIL_SERVER = "mail.example.org"
DEFAULT_PASSWORD = "admin123"
DEFAULT_PORT = 8083
env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT)
try:
env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT)
DEFAULT_PORT = int(env_CALIBRE_PORT)
except ValueError:
print('Environment variable CALIBRE_PORT has invalid value (%s), faling back to default (8083)' % env_CALIBRE_PORT)
......
......@@ -418,7 +418,7 @@ def dispose():
except: pass
if old_session.bind:
try: old_session.bind.dispose()
except: pass
except Exception: pass
for attr in list(Books.__dict__.keys()):
if attr.startswith("custom_column_"):
......
......@@ -176,48 +176,59 @@ def delete_book(book_id, book_format):
if current_user.role_delete_books():
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
if book:
helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
if not book_format:
# delete book from Shelfs, Downloads, Read list
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete()
ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete()
ub.session.query(ub.ArchivedBook).filter(ub.ArchivedBook.book_id == book_id).delete()
ub.delete_download(book_id)
ub.session.commit()
# check if only this book links to:
# author, language, series, tags, custom columns
modify_database_object([u''], book.authors, db.Authors, db.session, 'author')
modify_database_object([u''], book.tags, db.Tags, db.session, 'tags')
modify_database_object([u''], book.series, db.Series, db.session, 'series')
modify_database_object([u''], book.languages, db.Languages, db.session, 'languages')
modify_database_object([u''], book.publishers, db.Publishers, db.session, 'publishers')
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
for c in cc:
cc_string = "custom_column_" + str(c.id)
if not c.is_multiple:
if len(getattr(book, cc_string)) > 0:
if c.datatype == 'bool' or c.datatype == 'integer' or c.datatype == 'float':
del_cc = getattr(book, cc_string)[0]
getattr(book, cc_string).remove(del_cc)
db.session.delete(del_cc)
elif c.datatype == 'rating':
del_cc = getattr(book, cc_string)[0]
getattr(book, cc_string).remove(del_cc)
if len(del_cc.books) == 0:
try:
helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
if not book_format:
# delete book from Shelfs, Downloads, Read list
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete()
ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete()
ub.delete_download(book_id)
ub.session.commit()
# check if only this book links to:
# author, language, series, tags, custom columns
modify_database_object([u''], book.authors, db.Authors, db.session, 'author')
modify_database_object([u''], book.tags, db.Tags, db.session, 'tags')
modify_database_object([u''], book.series, db.Series, db.session, 'series')
modify_database_object([u''], book.languages, db.Languages, db.session, 'languages')
modify_database_object([u''], book.publishers, db.Publishers, db.session, 'publishers')
cc = db.session.query(db.Custom_Columns).\
filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
for c in cc:
cc_string = "custom_column_" + str(c.id)
if not c.is_multiple:
if len(getattr(book, cc_string)) > 0:
if c.datatype == 'bool' or c.datatype == 'integer' or c.datatype == 'float':
del_cc = getattr(book, cc_string)[0]
getattr(book, cc_string).remove(del_cc)
log.debug('remove ' + str(c.id))
db.session.delete(del_cc)
else:
del_cc = getattr(book, cc_string)[0]
getattr(book, cc_string).remove(del_cc)
db.session.delete(del_cc)
else:
modify_database_object([u''], getattr(book, cc_string), db.cc_classes[c.id],
db.session, 'custom')
db.session.query(db.Books).filter(db.Books.id == book_id).delete()
else:
db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format).delete()
db.session.commit()
db.session.commit()
elif c.datatype == 'rating':
del_cc = getattr(book, cc_string)[0]
getattr(book, cc_string).remove(del_cc)
if len(del_cc.books) == 0:
log.debug('remove ' + str(c.id))
db.session.delete(del_cc)
db.session.commit()
else:
del_cc = getattr(book, cc_string)[0]
getattr(book, cc_string).remove(del_cc)
log.debug('remove ' + str(c.id))
db.session.delete(del_cc)
db.session.commit()
else:
modify_database_object([u''], getattr(book, cc_string), db.cc_classes[c.id],
db.session, 'custom')
db.session.query(db.Books).filter(db.Books.id == book_id).delete()
else:
db.session.query(db.Data).filter(db.Data.book == book.id).\
filter(db.Data.format == book_format).delete()
db.session.commit()
except Exception as e:
log.debug(e)
db.session.rollback()
else:
# book not found
log.error('Book with id "%s" could not be deleted: not found', book_id)
......@@ -524,11 +535,12 @@ def edit_book(book_id):
if not error:
if to_save["cover_url"]:
if helper.save_cover_from_url(to_save["cover_url"], book.path) is True:
result, error = helper.save_cover_from_url(to_save["cover_url"], book.path)
if result is True:
book.has_cover = 1
modif_date = True
else:
flash(_(u"Cover is not a jpg file, can't save"), category="error")
flash(error, category="error")
if book.series_index != to_save["series_index"]:
book.series_index = to_save["series_index"]
......
......@@ -298,6 +298,9 @@ def delete_book_file(book, calibrepath, book_format=None):
log.error("Deleting book %s failed, path has subfolders: %s", book.id, book.path)
return False
shutil.rmtree(path, ignore_errors=True)
authorpath = os.path.join(calibrepath, os.path.split(book.path)[0])
if not os.listdir(authorpath):
shutil.rmtree(authorpath, ignore_errors=True)
return True
else:
log.error("Deleting book %s failed, book path not valid: %s", book.id, book.path)
......@@ -318,8 +321,8 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
new_titledir = get_valid_filename(localbook.title) + " (" + str(book_id) + ")"
if titledir != new_titledir:
new_title_path = os.path.join(os.path.dirname(path), new_titledir)
try:
new_title_path = os.path.join(os.path.dirname(path), new_titledir)
if not os.path.exists(new_title_path):
os.renames(path, new_title_path)
else:
......@@ -336,8 +339,8 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
src=path, dest=new_title_path, error=str(ex))
if authordir != new_authordir:
new_author_path = os.path.join(calibrepath, new_authordir, os.path.basename(path))
try:
new_author_path = os.path.join(calibrepath, new_authordir, os.path.basename(path))
os.renames(path, new_author_path)
localbook.path = new_authordir + '/' + localbook.path.split('/')[1]
except OSError as ex:
......@@ -530,12 +533,9 @@ def save_cover_from_filestorage(filepath, saved_filename, img):
return False, _(u"Failed to create path for cover")
try:
img.save(os.path.join(filepath, saved_filename))
except IOError:
log.error(u"Cover-file is not a valid image file")
return False, _(u"Cover-file is not a valid image file")
except OSError:
log.error(u"Failed to store cover-file")
return False, _(u"Failed to store cover-file")
except (IOError, OSError):
log.error(u"Cover-file is not a valid image file, or could not be stored")
return False, _(u"Cover-file is not a valid image file, or could not be stored")
return True, None
......@@ -840,7 +840,7 @@ def get_search_results(term):
db.Books.authors.any(and_(*q)),
db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + term + "%")),
func.lower(db.Books.title).ilike("%" + term + "%")
)).all()
)).order_by(db.Books.sort).all()
def get_cc_columns():
......
......@@ -66,8 +66,8 @@ log = logger.create()
def get_store_url_for_current_request():
# Programmatically modify the current url to point to the official Kobo store
base, sep, request_path_with_auth_token = request.full_path.rpartition("/kobo/")
auth_token, sep, request_path = request_path_with_auth_token.rstrip("?").partition(
__, __, request_path_with_auth_token = request.full_path.rpartition("/kobo/")
__, __, request_path = request_path_with_auth_token.rstrip("?").partition(
"/"
)
return KOBO_STOREAPI_URL + "/" + request_path
......
......@@ -62,7 +62,6 @@ particular calls to non-Kobo specific endpoints such as the CalibreWeb book down
from binascii import hexlify
from datetime import datetime
from os import urandom
import os
from flask import g, Blueprint, url_for, abort, request
from flask_login import login_user, login_required
......@@ -82,7 +81,7 @@ log = logger.create()
def register_url_value_preprocessor(kobo):
@kobo.url_value_preprocessor
def pop_auth_token(endpoint, values):
def pop_auth_token(__, values):
g.auth_token = values.pop("auth_token")
......
......@@ -4,7 +4,7 @@ body {
overflow-y: auto;
color: white;
font-family: sans-serif;
margin: 0px;
margin: 0;
}
#main {
......@@ -13,7 +13,7 @@ body {
}
.view {
padding-top:0px;
padding-top: 0;
}
#sidebar a,
......@@ -34,18 +34,18 @@ body {
cursor: pointer;
padding: 4px;
transition: all .2s ease;
transition: all 0.2s ease;
}
#sidebar a:hover,
#sidebar a:focus {
outline: none;
box-shadow: 0px 2px 8px 1px black;
box-shadow: 0 2px 8px 1px black;
}
#sidebar a.active,
#sidebar a.active img + span {
background-color: #45B29D;
background-color: #45B29D;
}
#sidebar li img {
......@@ -79,7 +79,6 @@ body {
font-size: 10px;
line-height: 10px;
text-align: right;
transition: min-height 150ms ease-in-out;
}
......@@ -92,18 +91,17 @@ body {
top: 0;
left: 0;
bottom: 0;
transition: width 150ms ease-in-out;
}
#progress .bar-load {
color: #000;
background-color: #CCC;
background-color: #ccc;
}
#progress .bar-read {
color: #FFF;
background-color: #45B29D;
color: #fff;
background-color: #45b29d;
}
#progress .text {
......@@ -152,7 +150,8 @@ body {
max-width: 70%;
}
th, td {
th,
td {
padding: 5px;
}
......@@ -206,18 +205,17 @@ th {
}
.dark-theme #titlebar {
color: #DDD;
color: #ddd;
}
.dark-theme #titlebar a:active {
color: #FFF;
color: #fff;
}
.dark-theme #progress .bar-read {
background-color: red;
}
.dark-theme .overlay {
background-color: rgba(0,0,0,0.8);
background-color: rgba(0, 0, 0, 0.8);
}
.sm2-bar-ui {
font-size: 20px;
}
.sm2-bar-ui.compact {
max-width: 90%;
}
.sm2-progress .sm2-progress-ball {
width: .5333em;
height: 1.9333em;
border-radius: 0em;
}
.sm2-progress .sm2-progress-track {
height: 0.15em;
background: white;
}
.sm2-bar-ui .sm2-main-controls,
.sm2-bar-ui .sm2-playlist-drawer {
background-color: transparent;
}
.sm2-bar-ui .sm2-inline-texture {
background: transparent;
}
.rating .glyphicon-star {
color: gray;
}
.rating .glyphicon-star.good {
color: white;
}
body {
overflow: hidden;
background: #272B30;
color: #aaa;
}
#main {
position: absolute;
width: 100%;
height: 100%;
}
#area {
width: 80%;
height: 80%;
margin: 5% auto;
max-width: 1250px;
}
#area iframe {
border: none;
}
#prev {
left: 40px;
}
#next {
right: 40px;
}
xmp,
pre,
plaintext {
display: block;
font-family: -moz-fixed;
white-space: pre;
margin: 1em 0;
}
#area {
overflow: hidden;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
font-family: -moz-fixed;
column-count: 2;
-webkit-columns: 2;
-moz-columns: 2;
column-gap: 20px;
-moz-column-gap: 20px;
-webkit-column-gap: 20px;
position: relative;
}
font-size: 20px;
}
.sm2-bar-ui.compact {
max-width: 90%;
}
.sm2-progress .sm2-progress-ball {
width: 0.5333em;
height: 1.9333em;
border-radius: 0;
}
.sm2-progress .sm2-progress-track {
height: 0.15em;
background: white;
}
.sm2-bar-ui .sm2-main-controls,
.sm2-bar-ui .sm2-playlist-drawer {
background-color: transparent;
}
.sm2-bar-ui .sm2-inline-texture {
background: transparent;
}
.rating .glyphicon-star {
color: gray;
}
.rating .glyphicon-star.good {
color: white;
}
body {
overflow: hidden;
background: #272b30;
color: #aaa;
}
#main {
position: absolute;
width: 100%;
height: 100%;
}
#area {
width: 80%;
height: 80%;
margin: 5% auto;
max-width: 1250px;
overflow: hidden;
}
#area iframe {
border: none;
}
#prev {
left: 40px;
}
#next {
right: 40px;
}
xmp,
pre,
plaintext {
display: block;
font-family: -moz-fixed;
white-space: pre;
margin: 1em 0;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
font-family: -moz-fixed;
column-count: 2;
-webkit-columns: 2;
-moz-columns: 2;
column-gap: 20px;
-moz-column-gap: 20px;
-webkit-column-gap: 20px;
position: relative;
}
@font-face {
font-family: 'fontello';
src: url('fonts/fontello.eot?60518104');
src: url('fonts/fontello.eot?60518104#iefix') format('embedded-opentype'),
url('fonts/fontello.woff?60518104') format('woff'),
url('fonts/fontello.ttf?60518104') format('truetype'),
url('fonts/fontello.svg?60518104#fontello') format('svg');
src:
url('fonts/fontello.eot?60518104#iefix') format('embedded-opentype'),
url('fonts/fontello.woff?60518104') format('woff'),
url('fonts/fontello.ttf?60518104') format('truetype'),
url('fonts/fontello.svg?60518104#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
......@@ -22,17 +23,15 @@ body {
border-radius: 5px;
background: #fff;
overflow: hidden;
-webkit-transition: -webkit-transform .4s, width .2s;
-moz-transition: -webkit-transform .4s, width .2s;
-ms-transition: -webkit-transform .4s, width .2s;
-moz-box-shadow: inset 0 0 50px rgba(0,0,0,.1);
-webkit-box-shadow: inset 0 0 50px rgba(0,0,0,.1);
-ms-box-shadow: inset 0 0 50px rgba(0,0,0,.1);
box-shadow: inset 0 0 50px rgba(0,0,0,.1);
-webkit-transition: -webkit-transform 0.4s, width 0.2s;
-moz-transition: -webkit-transform 0.4s, width 0.2s;
-ms-transition: -webkit-transform 0.4s, width 0.2s;
-moz-box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.1);
-webkit-box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.1);
-ms-box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.1);
}
#titlebar {
height: 8%;
min-height: 20px;
......@@ -42,11 +41,11 @@ body {
color: #4f4f4f;
font-weight: 100;
font-family: Georgia, "Times New Roman", Times, serif;
opacity: .5;
opacity: 0.5;
text-align: center;
-webkit-transition: opacity .5s;
-moz-transition: opacity .5s;
-ms-transition: opacity .5s;
-webkit-transition: opacity 0.5s;
-moz-transition: opacity 0.5s;
-ms-transition: opacity 0.5s;
z-index: 10;
}
......@@ -60,7 +59,7 @@ body {
line-height: 20px;
overflow: hidden;
display: inline-block;
opacity: .5;
opacity: 0.5;
padding: 4px;
border-radius: 4px;
}
......@@ -70,35 +69,27 @@ body {
}
#titlebar a:hover {
opacity: .8;
border: 1px rgba(0,0,0,.2) solid;
opacity: 0.8;
border: 1px rgba(0, 0, 0, 0.2) solid;
padding: 3px;
}
#titlebar a:active {
opacity: 1;
color: rgba(0,0,0,.6);
/* margin: 1px -1px -1px 1px; */
-moz-box-shadow: inset 0 0 6px rgba(155,155,155,.8);
-webkit-box-shadow: inset 0 0 6px rgba(155,155,155,.8);
-ms-box-shadow: inset 0 0 6px rgba(155,155,155,.8);
box-shadow: inset 0 0 6px rgba(155,155,155,.8);
color: rgba(0, 0, 0, 0.6);
-moz-box-shadow: inset 0 0 6px rgba(155, 155, 155, 0.8);
-webkit-box-shadow: inset 0 0 6px rgba(155, 155, 155, 0.8);
-ms-box-shadow: inset 0 0 6px rgba(155, 155, 155, 0.8);
box-shadow: inset 0 0 6px rgba(155, 155, 155, 0.8);
}
#book-title {
font-weight: 600;
}
#title-seperator {
display: none;
}
#book-title { font-weight: 600; }
#title-seperator { display: none; }
#viewer {
width: 80%;
height: 80%;
/* margin-left: 10%; */
margin: 0 auto;
/* max-width: 1250px; */
z-index: 2;
position: relative;
overflow: hidden;
......@@ -108,14 +99,16 @@ body {
border: none;
}
#left,#prev {
#left,
#prev {
left: 40px;
padding-right:80px;
padding-right: 80px;
}
#right,#next {
#right,
#next {
right: 40px;
padding-left:80px;
padding-left: 80px;
}
.arrow {
......@@ -148,24 +141,20 @@ body {
#sidebar {
background: #6b6b6b;
position: absolute;
/* left: -260px; */
/* -webkit-transform: translate(-260px, 0);
-moz-transform: translate(-260px, 0); */
top: 0;
min-width: 300px;
width: 25%;
height: 100%;
-webkit-transition: -webkit-transform .5s;
-moz-transition: -moz-transform .5s;
-ms-transition: -moz-transform .5s;
-webkit-transition: -webkit-transform 0.5s;
-moz-transition: -moz-transform 0.5s;
-ms-transition: -moz-transform 0.5s;
overflow: hidden;
}
#sidebar.open {
/* left: 0; */
/* -webkit-transform: translate(0, 0);
-moz-transform: translate(0, 0); */
/* left: 0; */
/* -webkit-transform: translate(0, 0);
-moz-transform: translate(0, 0); */
}
#main.closed {
......@@ -192,10 +181,10 @@ body {
width: 100%;
padding: 13px 0;
height: 14px;
-moz-box-shadow: 0px 1px 3px rgba(0,0,0,.6);
-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,.6);
-ms-box-shadow: 0px 1px 3px rgba(0,0,0,.6);
box-shadow: 0px 1px 3px rgba(0,0,0,.6);
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
-ms-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
#opener {
......@@ -203,19 +192,13 @@ body {
float: left;
}
/* #opener #slider {
width: 25px;
} */
#metainfo {
display: inline-block;
text-align: center;
max-width: 80%;
}
#title-controls {
float: right;
}
#title-controls { float: right; }
#panels a {
visibility: hidden;
......@@ -227,22 +210,17 @@ body {
margin-left: 6px;
}
#panels a::before {
visibility: visible;
}
#panels a:hover {
color: #AAA;
}
#panels a::before { visibility: visible; }
#panels a:hover { color: #aaa; }
#panels a:active {
color: #AAA;
color: #aaa;
margin: 1px 0 -1px 6px;
}
#panels a.active,
#panels a.active:hover {
color: #AAA;
color: #aaa;
}
#searchBox {
......@@ -250,28 +228,11 @@ body {
float: left;
margin-left: 10px;
margin-top: -1px;
/*
border-radius: 5px;
background: #9b9b9b;
float: left;
margin-left: 5px;
margin-top: -5px;
padding: 3px 10px;
color: #000;
border: none;
outline: none; */
}
input::-webkit-input-placeholder {
color: #454545;
}
input:-moz-placeholder {
color: #454545;
}
input:-ms-placeholder {
color: #454545;
}
input::-webkit-input-placeholder { color: #454545; }
input:-moz-placeholder { color: #454545; }
input:-ms-placeholder { color: #454545; }
#divider {
position: absolute;
......@@ -307,13 +268,11 @@ input:-ms-placeholder {
width: 25%;
height: 100%;
visibility: hidden;
-webkit-transition: visibility 0 ease .5s;
-moz-transition: visibility 0 ease .5s;
-ms-transition: visibility 0 ease .5s;
-webkit-transition: visibility 0 ease 0.5s;
-moz-transition: visibility 0 ease 0.5s;
-ms-transition: visibility 0 ease 0.5s;
}
#sidebar.open #tocView,
#sidebar.open #bookmarksView {
overflow-y: auto;
......@@ -351,7 +310,7 @@ input:-ms-placeholder {
}
.list_item a {
color: #AAA;
color: #aaa;
text-decoration: none;
}
......@@ -360,7 +319,7 @@ input:-ms-placeholder {
}
.list_item a.section {
font-size: .8em;
font-size: 0.8em;
}
.list_item.currentChapter > a,
......@@ -370,7 +329,7 @@ input:-ms-placeholder {
/* #tocView li.openChapter > a, */
.list_item a:hover {
color: #E2E2E2;
color: #e2e2e2;
}
.list_item ul {
......@@ -431,7 +390,7 @@ input:-ms-placeholder {
}
#searchResults a {
color: #AAA;
color: #aaa;
text-decoration: none;
}
......@@ -447,11 +406,11 @@ input:-ms-placeholder {
}
#searchResults li > p {
color: #AAA;
color: #aaa;
}
#searchResults li a:hover {
color: #E2E2E2;
color: #e2e2e2;
}
#searchView.shown {
......@@ -496,7 +455,7 @@ input:-ms-placeholder {
}
#note-text[disabled], #note-text[disabled="disabled"]{
opacity: .5;
opacity: 0.5;
}
#note-anchor {
......@@ -505,30 +464,30 @@ input:-ms-placeholder {
}
#settingsPanel {
display:none;
display: none;
}
#settingsPanel h3 {
color:#f1f1f1;
font-family:Georgia, "Times New Roman", Times, serif;
margin-bottom:10px;
color: #f1f1f1;
font-family: Georgia, "Times New Roman", Times, serif;
margin-bottom: 10px;
}
#settingsPanel ul {
margin-top:60px;
list-style-type:none;
margin-top: 60px;
list-style-type: none;
}
#settingsPanel li {
font-size:1em;
color:#f1f1f1;
font-size: 1em;
color: #f1f1f1;
}
#settingsPanel .xsmall { font-size:x-small; }
#settingsPanel .small { font-size:small; }
#settingsPanel .medium { font-size:medium; }
#settingsPanel .large { font-size:large; }
#settingsPanel .xlarge { font-size:x-large; }
#settingsPanel .xsmall { font-size: x-small; }
#settingsPanel .small { font-size: small; }
#settingsPanel .medium { font-size: medium; }
#settingsPanel .large { font-size: large; }
#settingsPanel .xlarge { font-size: x-large; }
.highlight { background-color: yellow }
......@@ -556,7 +515,7 @@ input:-ms-placeholder {
left: 0;
z-index: 1000;
opacity: 0;
background: rgba(255,255,255,0.8);
background: rgba(255, 255, 255, 0.8);
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
-ms-transition: all 0.3s;
......@@ -589,7 +548,7 @@ input:-ms-placeholder {
font-size: 22px;
font-weight: 300;
opacity: 0.8;
background: rgba(0,0,0,0.1);
background: rgba(0, 0, 0, 0.1);
border-radius: 3px 3px 0 0;
}
......@@ -823,23 +782,18 @@ and (orientation : landscape)
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
margin-right: 0.2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* you can be more comfortable with increased icons size */
font-size: 112%;
}
.icon-search:before { content: '\e807'; } /* '' */
.icon-resize-full-1:before { content: '\e804'; } /* '' */
.icon-cancel-circled2:before { content: '\e80f'; } /* '' */
......
/* http://davidwalsh.name/css-tooltips */
/* base CSS element */
.popup {
background: #eee;
......@@ -9,10 +10,8 @@
position: fixed;
max-width: 300px;
font-size: 12px;
display: none;
margin-left: 2px;
margin-top: 30px;
}
......@@ -38,7 +37,7 @@
}
/* below */
.popup:before {
.popup::before {
position: absolute;
display: inline-block;
border-bottom: 10px solid #eee;
......@@ -51,7 +50,7 @@
content: '';
}
.popup:after {
.popup::after {
position: absolute;
display: inline-block;
border-bottom: 9px solid #eee;
......@@ -64,33 +63,31 @@
}
/* above */
.popup.above:before {
.popup.above::before {
border-bottom: none;
border-top: 10px solid #eee;
border-top-color: rgba(0, 0, 0, 0.2);
top: 100%;
}
.popup.above:after {
.popup.above::after {
border-bottom: none;
border-top: 9px solid #eee;
top: 100%;
}
.popup.left:before,
.popup.left:after
{
.popup.left::before,
.popup.left::after {
left: 20px;
}
.popup.right:before,
.popup.right:after
{
.popup.right::before,
.popup.right::after {
left: auto;
right: 20px;
}
.popup.show, .popup.on {
.popup.show,
.popup.on {
display: block;
}
\ No newline at end of file
}
This diff is collapsed.
@media (min-device-width: 768px) {
.upload-modal-dialog {
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%, -50%) !important;
}
.upload-modal-dialog {
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%, -50%) !important;
}
}
......@@ -28,7 +28,7 @@ $( 'body.mailset' ).addClass( 'admin' );
curHref = window.location.href.split('/');
prevHref = document.referrer.split('/');
$( '.navbar-form.navbar-left' )
.before( '<div class="plexBack"><a href="' + document.referrer + '"></a></div>' );
.before( '<div class="plexBack"><a href="' + encodeURI(document.referrer) + '"></a></div>' );
if ( history.length === 1 ||
curHref[0] +
curHref[1] +
......@@ -43,7 +43,7 @@ if ( history.length === 1 ||
//Weird missing a after pressing back from edit.
setTimeout(function() {
if ( $( '.plexBack a').length < 1 ) {
$( '.plexBack' ).append('<a href="' + document.referrer + '"></a>');
$( '.plexBack' ).append('<a href="' + encodeURI(document.referrer) + '"></a>');
}
},10);
......
......@@ -45,7 +45,7 @@ $("#sort_name").click(function() {
});*/
// Find count of middle element
if (count > 20) {
var middle = parseInt(count / 2) + (count % 2);
var middle = parseInt(count / 2, 10) + (count % 2);
// search for the middle of all visibe elements
$(".row").each(function() {
index++;
......@@ -146,7 +146,7 @@ $("#all").click(function() {
// Find count of middle element
var listItems = $("#list").children(".row");
var listlength = listItems.length;
var middle = parseInt(listlength / 2) + (listlength % 2);
var middle = parseInt(listlength / 2, 10) + (listlength % 2);
// go through all elements and make them visible
listItems.each(function() {
$(this).show();
......@@ -178,7 +178,7 @@ $(".char").click(function() {
});
if (count > 20) {
// Find count of middle element
var middle = parseInt(count / 2) + (count % 2);
var middle = parseInt(count / 2, 10) + (count % 2);
// search for the middle of all visibe elements
$(".row").each(function() {
index++;
......
......@@ -112,7 +112,7 @@ $(function() {
return "";
},
url: path + "/../../ajax/listrestriction/" + type,
rowStyle: function(row, index) {
rowStyle: function(row) {
// console.log('Reihe :' + row + " Index :" + index);
if (row.id.charAt(0) === "a") {
return {classes: "bg-primary"};
......@@ -120,15 +120,15 @@ $(function() {
return {classes: "bg-dark-danger"};
}
},
onClickCell: function (field, value, row, $element) {
if (field == 3) {
onClickCell: function (field, value, row) {
if (field === 3) {
$.ajax ({
type: "Post",
data: "id=" + row.id + "&type=" + row.type + "&Element=" + row.Element,
url: path + "/../../ajax/deleterestriction/" + type,
async: true,
timeout: 900,
success:function(data) {
success:function() {
$.ajax({
method:"get",
url: path + "/../../ajax/listrestriction/" + type,
......@@ -145,14 +145,14 @@ $(function() {
striped: false
});
$("#restrict-elements-table").removeClass("table-hover");
$("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row, old, $el) {
$("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row) {
$.ajax({
url: path + "/../../ajax/editrestriction/" + type,
type: "Post",
data: row
});
});
$("[id^=submit_]").click(function(event) {
$("[id^=submit_]").click(function() {
$(this)[0].blur();
$.ajax({
url: path + "/../../ajax/addrestriction/" + type,
......@@ -196,7 +196,7 @@ $(function() {
});
/* Function for deleting domain restrictions */
function TableActions (value, row, index) {
function TableActions (value, row) {
return [
"<a class=\"danger remove\" data-toggle=\"modal\" data-target=\"#DeleteDomain\" data-domain-id=\"" + row.id
+ "\" title=\"Remove\">",
......@@ -206,7 +206,7 @@ function TableActions (value, row, index) {
}
/* Function for deleting domain restrictions */
function RestrictionActions (value, row, index) {
function RestrictionActions (value, row) {
return [
"<div class=\"danger remove\" data-restriction-id=\"" + row.id + "\" title=\"Remove\">",
"<i class=\"glyphicon glyphicon-trash\"></i>",
......
......@@ -344,7 +344,7 @@
<input type="text" class="form-control" id="config_converterpath" name="config_converterpath" value="{% if config.config_converterpath != None %}{{ config.config_converterpath }}{% endif %}" autocomplete="off">
</div>
</div>
{% if rarfile_support %}
{% if feature_support['rar'] %}
<div class="form-group">
<label for="config_rarfile_location">{{_('Location of Unrar binary')}}</label>
<input type="text" class="form-control" name="config_rarfile_location" id="config_rarfile_location" value="{% if config.config_rarfile_location != None %}{{ config.config_rarfile_location }}{% endif %}" autocomplete="off">
......
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/">
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/terms/">
<id>urn:uuid:2853dacf-ed79-42f5-8e8a-a7bb3d1ae6a2</id>
<updated>{{ current_time }}</updated>
<link rel="self"
......
......@@ -42,7 +42,7 @@
<form class="navbar-form navbar-left" role="search" action="{{url_for('web.search')}}" method="GET">
<div class="form-group input-group input-group-sm">
<label for="query" class="sr-only">{{_('Search')}}</label>
<input type="text" class="form-control" id="query" name="query" placeholder="{{_('Search Library')}}">
<input type="text" class="form-control" id="query" name="query" placeholder="{{_('Search Library')}}" value="{{searchterm}}">
<span class="input-group-btn">
<button type="submit" id="query_submit" class="btn btn-default">{{_('Search')}}</button>
</span>
......@@ -224,6 +224,11 @@
$("#btn-upload").change(function() {
$("#form-upload").submit();
});
$(document).ready(function() {
var inp = $('#query').first()
var val = inp.val()
inp.val('').blur().focus().val(val)
});
});
</script>
{% block js %}{% endblock %}
......
......@@ -2,10 +2,10 @@
{% block body %}
<div class="discover">
{% if entries|length < 1 %}
<h2>{{_('No Results Found')}} {{searchterm}}</h2>
<p>{{_('Search Term:')}} {{searchterm}}</p>
<h2>{{_('No Results Found')}} {{adv_searchterm}}</h2>
<p>{{_('Search Term:')}} {{adv_searchterm}}</p>
{% else %}
<h2>{{entries|length}} {{_('Results for:')}} {{searchterm}}</h2>
<h2>{{entries|length}} {{_('Results for:')}} {{adv_searchterm}}</h2>
{% if g.user.is_authenticated %}
{% if g.user.shelf.all() or g.shelves_access %}
<div id="shelf-actions" class="btn-toolbar" role="toolbar">
......@@ -28,8 +28,8 @@
</div>
{% endif %}
{% endif %}
<div class="filterheader hidden-xs hidden-sm"><!-- ToDo: Implement filter for search results -->
<a id="new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort='new')}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
<!--div class="filterheader hidden-xs hidden-sm"--><!-- ToDo: Implement filter for search results -->
<!--a id="new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort='new')}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
<a id="old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort='old')}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
<a id="asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
<a id="desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
......@@ -39,7 +39,7 @@
<div class="btn-group character" role="group">
<a id="no_shelf" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort='pubold')}}"><span class="glyphicon glyphicon-list"></span><b>?</b></a>
<div id="all" class="btn btn-primary">{{_('All')}}</div>
</div>
</div-->
{% endif %}
<div class="row">
......
......@@ -62,7 +62,7 @@ def get_sidebar_config(kwargs=None):
sidebar = list()
sidebar.append({"glyph": "glyphicon-book", "text": _('Recently Added'), "link": 'web.index', "id": "new",
"visibility": constants.SIDEBAR_RECENT, 'public': True, "page": "root",
"show_text": _('Show recent books'), "config_show": True})
"show_text": _('Show recent books'), "config_show":False})
sidebar.append({"glyph": "glyphicon-fire", "text": _('Hot Books'), "link": 'web.books_list', "id": "hot",
"visibility": constants.SIDEBAR_HOT, 'public': True, "page": "hot",
"show_text": _('Show Hot Books'), "config_show": True})
......@@ -161,6 +161,8 @@ class UserBase:
return self.default_language
def check_visibility(self, value):
if value == constants.SIDEBAR_RECENT:
return True
return constants.has_flag(self.sidebar_view, value)
def show_detail_random(self):
......@@ -621,7 +623,7 @@ def create_anonymous_user(session):
session.add(user)
try:
session.commit()
except Exception as e:
except Exception:
session.rollback()
......
......@@ -85,7 +85,7 @@ def process(tmp_file_path, original_file_name, original_file_extension, rarExcec
meta = epub.get_epub_info(tmp_file_path, original_file_name, original_file_extension)
if ".FB2" == original_file_extension.upper() and use_fb2_meta is True:
meta = fb2.get_fb2_info(tmp_file_path, original_file_extension)
if original_file_extension.upper() in ['.CBZ', '.CBT', 'CBR']:
if original_file_extension.upper() in ['.CBZ', '.CBT', '.CBR']:
meta = comic.get_comic_info(tmp_file_path,
original_file_name,
original_file_extension,
......
......@@ -38,8 +38,12 @@ from flask import render_template, request, redirect, send_from_directory, make_
from flask_babel import gettext as _
from flask_login import login_user, logout_user, login_required, current_user
from sqlalchemy.exc import IntegrityError
from sqlalchemy.sql.expression import text, func, true, false, not_, and_, exists, or_
from werkzeug.exceptions import default_exceptions, FailedDependency
from sqlalchemy.sql.expression import text, func, true, false, not_, and_, or_
from werkzeug.exceptions import default_exceptions
try:
from werkzeug.exceptions import FailedDependency
except ImportError:
from werkzeug.exceptions import UnprocessableEntity as FailedDependency
from werkzeug.datastructures import Headers
from werkzeug.security import generate_password_hash, check_password_hash
......@@ -72,11 +76,11 @@ try:
except ImportError:
pass # We're not using Python 3
# try:
# import rarfile
# feature_support['rar'] = True
# except ImportError:
# feature_support['rar'] = False
#try:
# import rarfile
# feature_support['rar'] = True
#except ImportError:
# feature_support['rar'] = False
try:
from natsort import natsorted as sort
......@@ -750,7 +754,7 @@ def render_category_books(page, book_id, order):
name = db.session.query(db.Tags).filter(db.Tags.id == book_id).first()
if name:
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.tags.any(db.Tags.id == book_id),
[db.Series.name, db.Books.series_index, order[0]],
[order[0], db.Series.name, db.Books.series_index],
db.books_series_link, db.Series)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id,
title=_(u"Category: %(name)s", name=name.name), page="category")
......@@ -926,9 +930,17 @@ def search():
for element in entries:
ids.append(element.id)
searched_ids[current_user.id] = ids
return render_title_template('search.html', searchterm=term, entries=entries, title=_(u"Search"), page="search")
return render_title_template('search.html',
searchterm=term,
adv_searchterm=term,
entries=entries,
title=_(u"Search"),
page="search")
else:
return render_title_template('search.html', searchterm="", title=_(u"Search"), page="search")
return render_title_template('search.html',
searchterm="",
title=_(u"Search"),
page="search")
@web.route("/advanced_search", methods=['GET'])
......@@ -937,7 +949,7 @@ def advanced_search():
# Build custom columns names
cc = get_cc_columns()
db.session.connection().connection.connection.create_function("lower", 1, lcase)
q = db.session.query(db.Books).filter(common_filters())
q = db.session.query(db.Books).filter(common_filters()).order_by(db.Books.sort)
include_tag_inputs = request.args.getlist('include_tag')
exclude_tag_inputs = request.args.getlist('exclude_tag')
......@@ -1066,7 +1078,7 @@ def advanced_search():
for element in q:
ids.append(element.id)
searched_ids[current_user.id] = ids
return render_title_template('search.html', searchterm=searchterm,
return render_title_template('search.html', adv_searchterm=searchterm,
entries=q, title=_(u"search"), page="search")
# prepare data for search-form
tags = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters()) \
......@@ -1319,16 +1331,11 @@ def login():
log.info('Login failed for user "%s" IP-adress: %s', form['username'], ipAdress)
flash(_(u"Wrong Username or Password"), category="error")
if feature_support['oauth']:
oauth_status = get_oauth_status()
else:
oauth_status = None
next_url = url_for('web.index')
return render_title_template('login.html',
title=_(u"login"),
next_url=next_url,
config=config,
# oauth_status=oauth_status,
oauth_check=oauth_check,
mail=config.get_mail_server_configured(), page="login")
......
......@@ -300,11 +300,6 @@ class WorkerThread(threading.Thread):
# check which converter to use kindlegen is "1"
if format_old_ext == '.epub' and format_new_ext == '.mobi':
if config.config_ebookconverter == 1:
'''if os.name == 'nt':
command = config.config_converterpath + u' "' + file_path + u'.epub"'
if sys.version_info < (3, 0):
command = command.encode(sys.getfilesystemencoding())
else:'''
command = [config.config_converterpath, file_path + u'.epub']
quotes = [1]
if config.config_ebookconverter == 2:
......@@ -314,12 +309,6 @@ class WorkerThread(threading.Thread):
# windows py 3.x no encode and as string with quotes empty element for parameters is okay
# separate handling for windows and linux
quotes = [1,2]
'''if os.name == 'nt':
command = config.config_converterpath + u' "' + file_path + format_old_ext + u'" "' + \
file_path + format_new_ext + u'" ' + config.config_calibre
if sys.version_info < (3, 0):
command = command.encode(sys.getfilesystemencoding())
else:'''
command = [config.config_converterpath, (file_path + format_old_ext),
(file_path + format_new_ext)]
quotes_index = 3
......
......@@ -31,8 +31,7 @@ rarfile>=2.7
# other
natsort>=2.2.0,<7.1.0
git+https://github.com/OzzieIsaacs/comicapi.git@ad8bfe5a1c31db882480433f86db2c5c57634a3f#egg=comicapi
git+https://github.com/OzzieIsaacs/comicapi.git@15dff9ce4e1ffed29ba4a2feadfcdb6bed00bcad#egg=comicapi
#Kobo integration
jsonschema>=3.2.0,<3.3.0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment