Merge branch 'master' into Develop
This commit is contained in:
@@ -1838,6 +1838,9 @@ def _configuration_update_helper():
|
||||
services.goodreads_support.connect(config.config_goodreads_api_key,
|
||||
config.config_use_goodreads)
|
||||
|
||||
# Google Books API configuration
|
||||
reboot_required |=_config_string(to_save, "config_googlebooks_api_key")
|
||||
|
||||
_config_int(to_save, "config_updatechannel")
|
||||
|
||||
# Reverse proxy login configuration
|
||||
|
||||
@@ -65,7 +65,7 @@ def _extract_cover_from_archive(original_file_extension, tmp_file_name, rar_exec
|
||||
cover_data = extension = None
|
||||
if original_file_extension.upper() == '.CBZ':
|
||||
cf = zipfile.ZipFile(tmp_file_name)
|
||||
for name in cf.namelist():
|
||||
for name in sorted(cf.namelist()):
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
@@ -74,7 +74,7 @@ def _extract_cover_from_archive(original_file_extension, tmp_file_name, rar_exec
|
||||
break
|
||||
elif original_file_extension.upper() == '.CBT':
|
||||
cf = tarfile.TarFile(tmp_file_name)
|
||||
for name in cf.getnames():
|
||||
for name in sorted(cf.getnames()):
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
@@ -85,7 +85,7 @@ def _extract_cover_from_archive(original_file_extension, tmp_file_name, rar_exec
|
||||
try:
|
||||
rarfile.UNRAR_TOOL = rar_executable
|
||||
cf = rarfile.RarFile(tmp_file_name)
|
||||
for name in cf.namelist():
|
||||
for name in sorted(cf.namelist()):
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
@@ -96,7 +96,7 @@ def _extract_cover_from_archive(original_file_extension, tmp_file_name, rar_exec
|
||||
log.error('Rarfile failed with error: {}'.format(ex))
|
||||
elif original_file_extension.upper() == '.CB7' and use_7zip:
|
||||
cf = py7zr.SevenZipFile(tmp_file_name)
|
||||
for name in cf.getnames():
|
||||
for name in sorted(cf.getnames()):
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
|
||||
@@ -117,6 +117,7 @@ class _Settings(_Base):
|
||||
|
||||
config_use_goodreads = Column(Boolean, default=False)
|
||||
config_goodreads_api_key = Column(String)
|
||||
config_googlebooks_api_key = Column(String, default='')
|
||||
config_register_email = Column(Boolean, default=False)
|
||||
config_login_type = Column(Integer, default=0)
|
||||
|
||||
@@ -325,7 +326,7 @@ class ConfigSQL(object):
|
||||
def to_dict(self):
|
||||
storage = {}
|
||||
for k, v in self.__dict__.items():
|
||||
if k[0] != '_' and not k.endswith("_e") and not k == "cli":
|
||||
if k[0] != '_' and not k.endswith("_e") and not k == "cli" and 'api' not in k.lower():
|
||||
storage[k] = v
|
||||
return storage
|
||||
|
||||
|
||||
@@ -406,7 +406,7 @@ def edit_book_param(param, vals, multi=False):
|
||||
kobo_sync_status.remove_synced_book(book.id)
|
||||
continue
|
||||
elif param == 'read_status':
|
||||
error = helper.edit_book_read_status(book.id, vals['value'] == "True", True)
|
||||
error = helper.edit_book_read_status(book.id, vals['value'] == "True")
|
||||
if error:
|
||||
if multi:
|
||||
out.append({"success":False, "msg":error})
|
||||
|
||||
@@ -303,7 +303,7 @@ def get_sorted_author(value):
|
||||
return value2
|
||||
|
||||
|
||||
def edit_book_read_status(book_id, read_status=None, archived=False):
|
||||
def edit_book_read_status(book_id, read_status=None):
|
||||
if not config.config_read_column:
|
||||
book = ub.session.query(ub.ReadBook).filter(and_(ub.ReadBook.user_id == int(current_user.id),
|
||||
ub.ReadBook.book_id == book_id)).first()
|
||||
@@ -327,7 +327,7 @@ def edit_book_read_status(book_id, read_status=None, archived=False):
|
||||
else:
|
||||
try:
|
||||
calibre_db.create_functions(config)
|
||||
book = calibre_db.get_filtered_book(book_id, archived)
|
||||
book = calibre_db.get_filtered_book(book_id, True)
|
||||
book_read_status = getattr(book, 'custom_column_' + str(config.config_read_column))
|
||||
if len(book_read_status):
|
||||
if read_status is None:
|
||||
|
||||
@@ -1014,6 +1014,8 @@ def handle_getests():
|
||||
@kobo.route("/v1/products/dailydeal", methods=["GET", "POST"])
|
||||
@kobo.route("/v1/products/deals", methods=["GET", "POST"])
|
||||
@kobo.route("/v1/products", methods=["GET", "POST"])
|
||||
@kobo.route("/v1/products/<path:dummy>", methods=["GET", "POST"])
|
||||
@kobo.route("/v1/products/<path:dummy>/", methods=["GET", "POST"])
|
||||
@kobo.route("/v1/affiliate", methods=["GET", "POST"])
|
||||
@kobo.route("/v1/deals", methods=["GET", "POST"])
|
||||
def HandleProductsRequest(dummy=None):
|
||||
@@ -1201,6 +1203,9 @@ def NATIVE_KOBO_RESOURCES():
|
||||
"image_host": "//cdn.kobo.com/book-images/",
|
||||
"image_url_quality_template": "https://cdn.kobo.com/book-images/{ImageId}/{Width}/{Height}/{Quality}/{IsGreyscale}/image.jpg",
|
||||
"image_url_template": "https://cdn.kobo.com/book-images/{ImageId}/{Width}/{Height}/false/image.jpg",
|
||||
"instapaper_enabled": "True",
|
||||
"instapaper_env_url": "https://www.instapaper.com/api/kobo",
|
||||
"instapaper_link_account_start": "https://authorize.kobo.com/{region}/{language}/linkinstapaper",
|
||||
"kobo_audiobooks_credit_redemption": "False",
|
||||
"kobo_audiobooks_enabled": "True",
|
||||
"kobo_audiobooks_orange_deal_enabled": "False",
|
||||
|
||||
@@ -23,7 +23,7 @@ from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
from cps import logger
|
||||
from cps import logger, config
|
||||
from cps.isoLanguages import get_lang3, get_language_name
|
||||
from cps.services.Metadata import MetaRecord, MetaSourceInfo, Metadata
|
||||
|
||||
@@ -38,6 +38,7 @@ class Google(Metadata):
|
||||
BOOK_URL = "https://books.google.com/books?id="
|
||||
SEARCH_URL = "https://www.googleapis.com/books/v1/volumes?q="
|
||||
ISBN_TYPE = "ISBN_13"
|
||||
API_KEY = "&key=" + config.config_googlebooks_api_key
|
||||
|
||||
def search(
|
||||
self, query: str, generic_cover: str = "", locale: str = "en"
|
||||
@@ -50,7 +51,7 @@ class Google(Metadata):
|
||||
tokens = [quote(t.encode("utf-8")) for t in title_tokens]
|
||||
query = "+".join(tokens)
|
||||
try:
|
||||
results = requests.get(Google.SEARCH_URL + query)
|
||||
results = requests.get(Google.SEARCH_URL + query + Google.API_KEY)
|
||||
results.raise_for_status()
|
||||
except Exception as e:
|
||||
log.warning(e)
|
||||
|
||||
68
cps/opds.py
68
cps/opds.py
@@ -88,8 +88,8 @@ def feed_letter_books(book_id):
|
||||
letter,
|
||||
[db.Books.sort],
|
||||
True, config.config_read_column)
|
||||
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/new")
|
||||
@@ -101,7 +101,8 @@ def feed_new():
|
||||
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
|
||||
db.Books, True, [db.Books.timestamp.desc()],
|
||||
True, config.config_read_column)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/discover")
|
||||
@@ -112,7 +113,8 @@ def feed_discover():
|
||||
query = calibre_db.generate_linked_query(config.config_read_column, db.Books)
|
||||
entries = query.filter(calibre_db.common_filters()).order_by(func.random()).limit(config.config_books_per_page)
|
||||
pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/rated")
|
||||
@@ -125,7 +127,8 @@ def feed_best_rated():
|
||||
db.Books, db.Books.ratings.any(db.Ratings.rating > 9),
|
||||
[db.Books.timestamp.desc()],
|
||||
True, config.config_read_column)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/hot")
|
||||
@@ -149,7 +152,8 @@ def feed_hot():
|
||||
num_books = entries.__len__()
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1),
|
||||
config.config_books_per_page, num_books)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/author")
|
||||
@@ -174,7 +178,8 @@ def feed_letter_author(book_id):
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
entries.count())
|
||||
entries = entries.limit(config.config_books_per_page).offset(off).all()
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_author', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_author', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/author/<int:book_id>")
|
||||
@@ -197,7 +202,8 @@ def feed_publisherindex():
|
||||
.limit(config.config_books_per_page).offset(off)
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
len(calibre_db.session.query(db.Publishers).all()))
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_publisher', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_publisher', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/publisher/<int:book_id>")
|
||||
@@ -230,7 +236,8 @@ def feed_letter_category(book_id):
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
entries.count())
|
||||
entries = entries.offset(off).limit(config.config_books_per_page).all()
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_category', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_category', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/category/<int:book_id>")
|
||||
@@ -263,7 +270,8 @@ def feed_letter_series(book_id):
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
entries.count())
|
||||
entries = entries.offset(off).limit(config.config_books_per_page).all()
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_series', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_series', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/series/<int:book_id>")
|
||||
@@ -275,7 +283,8 @@ def feed_series(book_id):
|
||||
db.Books.series.any(db.Series.id == book_id),
|
||||
[db.Books.series_index],
|
||||
True, config.config_read_column)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/ratings")
|
||||
@@ -297,7 +306,8 @@ def feed_ratingindex():
|
||||
element = list()
|
||||
for entry in entries:
|
||||
element.append(FeedObject(entry[0].id, _("{} Stars").format(entry.name)))
|
||||
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_ratings', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_ratings', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/ratings/<book_id>")
|
||||
@@ -321,7 +331,8 @@ def feed_formatindex():
|
||||
element = list()
|
||||
for entry in entries:
|
||||
element.append(FeedObject(entry.format, entry.format))
|
||||
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_format', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_format', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/formats/<book_id>")
|
||||
@@ -333,7 +344,8 @@ def feed_format(book_id):
|
||||
db.Books.data.any(db.Data.format == book_id.upper()),
|
||||
[db.Books.timestamp.desc()],
|
||||
True, config.config_read_column)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/language")
|
||||
@@ -351,7 +363,8 @@ def feed_languagesindex():
|
||||
languages[0].name = isoLanguages.get_language_name(get_locale(), languages[0].lang_code)
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
len(languages))
|
||||
return render_xml_template('feed.xml', listelements=languages, folder='opds.feed_languages', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=languages, folder='opds.feed_languages', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/language/<int:book_id>")
|
||||
@@ -363,7 +376,8 @@ def feed_languages(book_id):
|
||||
db.Books.languages.any(db.Languages.id == book_id),
|
||||
[db.Books.timestamp.desc()],
|
||||
True, config.config_read_column)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/shelfindex")
|
||||
@@ -377,7 +391,8 @@ def feed_shelfindex():
|
||||
number = len(shelf)
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
number)
|
||||
return render_xml_template('feed.xml', listelements=shelf, folder='opds.feed_shelf', pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', listelements=shelf, folder='opds.feed_shelf', pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/shelf/<int:book_id>")
|
||||
@@ -417,7 +432,8 @@ def feed_shelf(book_id):
|
||||
except (OperationalError, InvalidRequestError) as e:
|
||||
ub.session.rollback()
|
||||
log.error_or_exception("Settings Database error: {}".format(e))
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/download/<book_id>/<book_format>/")
|
||||
@@ -470,7 +486,8 @@ def feed_read_books():
|
||||
return abort(403)
|
||||
off = request.args.get("offset") or 0
|
||||
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
@opds.route("/opds/unreadbooks")
|
||||
@@ -480,7 +497,8 @@ def feed_unread_books():
|
||||
return abort(403)
|
||||
off = request.args.get("offset") or 0
|
||||
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
class FeedObject:
|
||||
@@ -502,7 +520,8 @@ def feed_search(term):
|
||||
entries, __, ___ = calibre_db.get_search_results(term, config=config)
|
||||
entries_count = len(entries) if len(entries) > 0 else 1
|
||||
pagination = Pagination(1, entries_count, entries_count)
|
||||
return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination, cc=cc)
|
||||
else:
|
||||
return render_xml_template('feed.xml', searchterm="")
|
||||
|
||||
@@ -524,7 +543,8 @@ def render_xml_dataset(data_table, book_id):
|
||||
getattr(db.Books, data_table.__tablename__).any(data_table.id == book_id),
|
||||
[db.Books.timestamp.desc()],
|
||||
True, config.config_read_column)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination, cc=cc)
|
||||
|
||||
|
||||
def render_element_index(database_column, linked_table, folder):
|
||||
@@ -545,7 +565,9 @@ def render_element_index(database_column, linked_table, folder):
|
||||
elements.append({'id': entry.id, 'name': entry.id})
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
len(entries) + 1)
|
||||
cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True)
|
||||
return render_xml_template('feed.xml',
|
||||
letterelements=elements,
|
||||
folder=folder,
|
||||
pagination=pagination)
|
||||
pagination=pagination,
|
||||
cc=cc)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
from urllib.parse import urlparse, urljoin
|
||||
|
||||
from flask import request, url_for, redirect, current_app
|
||||
from flask import request, url_for, current_app
|
||||
|
||||
|
||||
def is_safe_url(target):
|
||||
|
||||
@@ -22,7 +22,7 @@ import requests
|
||||
|
||||
from goodreads.client import GoodreadsClient
|
||||
from goodreads.request import GoodreadsRequest
|
||||
import xmltodict
|
||||
from lxml import etree
|
||||
|
||||
try:
|
||||
import Levenshtein
|
||||
@@ -33,6 +33,39 @@ from .. import logger
|
||||
from ..clean_html import clean_string
|
||||
|
||||
|
||||
|
||||
|
||||
def etree_to_dict(t):
|
||||
"""
|
||||
Convert lxml ElementTree to a nested dict (similar to xmltodict).
|
||||
"""
|
||||
d = {t.tag: {} if t.attrib else None}
|
||||
children = list(t)
|
||||
|
||||
if children:
|
||||
dd = {}
|
||||
for dc in map(etree_to_dict, children):
|
||||
for k, v in dc.items():
|
||||
if k in dd:
|
||||
if not isinstance(dd[k], list):
|
||||
dd[k] = [dd[k]]
|
||||
dd[k].append(v)
|
||||
else:
|
||||
dd[k] = v
|
||||
d = {t.tag: dd}
|
||||
|
||||
if t.attrib:
|
||||
d[t.tag].update(('@' + k, v) for k, v in t.attrib.items())
|
||||
|
||||
text = (t.text or '').strip()
|
||||
if text:
|
||||
if children or t.attrib:
|
||||
d[t.tag]['#text'] = text
|
||||
else:
|
||||
d[t.tag] = text
|
||||
|
||||
return d
|
||||
|
||||
class my_GoodreadsClient(GoodreadsClient):
|
||||
|
||||
def request(self, *args, **kwargs):
|
||||
@@ -59,7 +92,9 @@ class my_GoodreadsRequest(GoodreadsRequest):
|
||||
if resp.status_code != 200:
|
||||
raise GoodreadsRequestException(resp.reason, self.path)
|
||||
if self.req_format == 'xml':
|
||||
data_dict = xmltodict.parse(resp.content)
|
||||
root = etree.fromstring(resp.content)
|
||||
data_dict = etree_to_dict(root)
|
||||
|
||||
return data_dict['GoodreadsResponse']
|
||||
else:
|
||||
raise Exception("Invalid format")
|
||||
|
||||
@@ -235,7 +235,7 @@ class CalibreTask:
|
||||
|
||||
@property
|
||||
def dead(self):
|
||||
"""Determines whether this task can be garbage collected
|
||||
"""Determines whether or not this task can be garbage collected
|
||||
|
||||
We have a separate dictating this because there may be certain tasks that want to override this
|
||||
"""
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// register new event emitter locationchange that fires on urlchange
|
||||
// source: https://stackoverflow.com/a/52809105/21941129
|
||||
(() => {
|
||||
let oldPushState = history.pushState;
|
||||
history.pushState = function pushState() {
|
||||
let ret = oldPushState.apply(this, arguments);
|
||||
window.dispatchEvent(new Event('locationchange'));
|
||||
return ret;
|
||||
};
|
||||
|
||||
let oldReplaceState = history.replaceState;
|
||||
history.replaceState = function replaceState() {
|
||||
let ret = oldReplaceState.apply(this, arguments);
|
||||
window.dispatchEvent(new Event('locationchange'));
|
||||
return ret;
|
||||
};
|
||||
|
||||
window.addEventListener('popstate', () => {
|
||||
window.dispatchEvent(new Event('locationchange'));
|
||||
});
|
||||
})();
|
||||
@@ -163,6 +163,10 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="config_googlebooks_api_key">{{_('Google Books API Key')}}</label>
|
||||
<input type="text" class="form-control" id="config_googlebooks_api_key" name="config_googlebooks_api_key" value="{% if config.config_googlebooks_api_key != '' %}{{ config.config_googlebooks_api_key }}{% endif %}" autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="config_allow_reverse_proxy_header_login" name="config_allow_reverse_proxy_header_login" data-control="reverse-proxy-login-settings" {% if config.config_allow_reverse_proxy_header_login %}checked{% endif %}>
|
||||
<label for="config_allow_reverse_proxy_header_login">{{_('Allow Reverse Proxy Authentication')}}</label>
|
||||
|
||||
@@ -63,7 +63,57 @@
|
||||
term="{{tag.name}}"
|
||||
label="{{tag.name}}"/>
|
||||
{% endfor %}
|
||||
{% if entry.Books.comments[0] %}<summary>{{entry.Books.comments[0].text|striptags}}</summary>{% endif %}
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
{% if entry.Books.ratings.__len__() > 0 %}
|
||||
RATING: {% for number in range((entry.Books.ratings[0].rating/2)|int(2)) %}★{% endfor %}<br/>
|
||||
{% endif %}
|
||||
{% if entry.Books.tags|length > 0 %}
|
||||
TAGS: {% for tag in entry.Books.tags %}{{tag.name}}{{ ", " if not loop.last else "" }}{% endfor %}<br/>
|
||||
{% endif %}
|
||||
{% if entry.Books.series.__len__() > 0 %}
|
||||
SERIES: {{entry.Books.series[0].name}} [{{entry.Books.series_index|formatfloat(2)}}]<br/>
|
||||
{% endif %}
|
||||
|
||||
{% if cc|length > 0 %}
|
||||
{% for c in cc %}
|
||||
{% if entry.Books['custom_column_' ~ c.id]|length > 0 %}
|
||||
{{ c.name }}:
|
||||
{% for column in entry.Books['custom_column_' ~ c.id] %}
|
||||
{% if c.datatype == 'rating' %}
|
||||
{{ (column.value / 2)|formatfloat }}
|
||||
{% else %}
|
||||
{% if c.datatype == 'bool' %}
|
||||
{% if column.value == true %}
|
||||
✓
|
||||
{% else %}
|
||||
✕
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if c.datatype == 'float' %}
|
||||
{{ column.value|formatfloat(2) }}
|
||||
{% elif c.datatype == 'datetime' %}
|
||||
{{ column.value|formatdate }}
|
||||
{% elif c.datatype == 'comments' %}
|
||||
{{ column.value|safe }}
|
||||
{% elif c.datatype == 'series' %}
|
||||
{{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }}
|
||||
{% elif c.datatype == 'text' %}
|
||||
{{ column.value.strip() }}{% if not loop.last %}, {% endif %}
|
||||
{% else %}
|
||||
{{ column.value }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if entry.Books.comments[0] %}
|
||||
<p>{{entry.Books.comments[0].text}}</p>
|
||||
{% endif %}
|
||||
</div></content>
|
||||
{% if entry.Books.has_cover %}
|
||||
<link type="image/jpeg" href="{{url_for('opds.feed_get_cover', book_id=entry.Books.id)}}" rel="http://opds-spec.org/image"/>
|
||||
<link type="image/jpeg" href="{{url_for('opds.feed_get_cover', book_id=entry.Books.id)}}" rel="http://opds-spec.org/image/thumbnail"/>
|
||||
|
||||
@@ -41,8 +41,7 @@
|
||||
<div class="plexBack"><a href="{{url_for('web.index')}}"></a></div>
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated or g.allow_anonymous %}
|
||||
<!--# margin 0, padding 15, background color-->
|
||||
<form class="navbar-form navbar-left" role="search" action="{{url_for('search.simple_search')}}" method="GET">
|
||||
<form class="navbar-form navbar-left" role="search" action="{{url_for('search.simple_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')}}" value="{{searchterm}}">
|
||||
|
||||
@@ -48,8 +48,7 @@
|
||||
<div class="modal-body text-center">
|
||||
<p>
|
||||
<span class="hidden" id="book_format">{{_('This book format will be permanently erased from database')}}</span>
|
||||
<span class="hidden" id="book_complete">{{_('This book will be permanently erased from database')}}</span>
|
||||
<span>{{_('and hard disk')}}</span>
|
||||
<span class="hidden" id="book_complete">{{_('This book will be permanently erased from database and hard disk')}}</span>
|
||||
</p>
|
||||
{% if config.config_kobo_sync %}
|
||||
<p>
|
||||
|
||||
@@ -216,6 +216,5 @@
|
||||
<script src="{{ url_for('static', filename='js/libs/screenfull.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/libs/reader.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/reading/epub.js') }}"></script>
|
||||
<!--script src="{{ url_for('static', filename='js/reading/locationchange-polyfill.js') }}"></script-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
13
cps/web.py
13
cps/web.py
@@ -812,14 +812,19 @@ def index(page):
|
||||
return render_books_list("newest", sort_param, 1, page)
|
||||
|
||||
|
||||
@web.route('/<data>/<sort_param>', defaults={'page': 1, 'book_id': 1})
|
||||
@web.route('/<data>/<sort_param>/', defaults={'page': 1, 'book_id': 1})
|
||||
@web.route('/<data>/<sort_param>/<book_id>', defaults={'page': 1})
|
||||
@web.route('/<data>/<sort_param>/<book_id>/<int:page>')
|
||||
@login_required_if_no_ano
|
||||
def books_list(data, sort_param, book_id, page):
|
||||
return render_books_list(data, sort_param, book_id, page)
|
||||
|
||||
# Limit number of routes to avoid redirects
|
||||
data =["rated", "discover", "unread", "read", "hot", "download", "author", "publisher", "series", "ratings", "formats",
|
||||
"category", "language", "archived", "search", "advsearch", "newest"]
|
||||
for d in data:
|
||||
web.add_url_rule('/{}/<sort_param>'.format(d), view_func=books_list, defaults={'page': 1, 'book_id': 1, "data": d})
|
||||
web.add_url_rule('/{}/<sort_param>/'.format(d), view_func=books_list, defaults={'page': 1, 'book_id': 1, "data": d})
|
||||
web.add_url_rule('/{}/<sort_param>/<book_id>'.format(d), view_func=books_list, defaults={'page': 1, "data": d})
|
||||
web.add_url_rule('/{}/<sort_param>/<book_id>/<int:page>'.format(d), defaults={"data": d}, view_func=books_list)
|
||||
|
||||
|
||||
@web.route("/table")
|
||||
@user_login_required
|
||||
|
||||
842
messages.pot
842
messages.pot
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user