Added thumbnail urls to book cover srcsets with cache busting ids
This commit is contained in:
parent
626051e489
commit
242a2767a1
|
@ -609,7 +609,8 @@ class CalibreDB():
|
|||
randm = self.session.query(Books) \
|
||||
.filter(self.common_filters(allow_show_archived)) \
|
||||
.order_by(func.random()) \
|
||||
.limit(self.config.config_random_books)
|
||||
.limit(self.config.config_random_books) \
|
||||
.all()
|
||||
else:
|
||||
randm = false()
|
||||
off = int(int(pagesize) * (page - 1))
|
||||
|
|
|
@ -533,6 +533,21 @@ def delete_book(book, calibrepath, book_format):
|
|||
return delete_book_file(book, calibrepath, book_format)
|
||||
|
||||
|
||||
def get_thumbnails_for_books(books):
|
||||
books_with_covers = list(filter(lambda b: b.has_cover, books))
|
||||
book_ids = list(map(lambda b: b.id, books_with_covers))
|
||||
return ub.session\
|
||||
.query(ub.Thumbnail)\
|
||||
.filter(ub.Thumbnail.book_id.in_(book_ids))\
|
||||
.filter(ub.Thumbnail.expiration > datetime.utcnow())\
|
||||
.all()
|
||||
|
||||
|
||||
def get_thumbnails_for_book_series(series):
|
||||
books = list(map(lambda s: s[0], series))
|
||||
return get_thumbnails_for_books(books)
|
||||
|
||||
|
||||
def get_cover_on_failure(use_generic_cover):
|
||||
if use_generic_cover:
|
||||
return send_from_directory(_STATIC_DIR, "generic_cover.jpg")
|
||||
|
@ -558,6 +573,29 @@ def get_cached_book_cover(cache_id):
|
|||
return get_book_cover_internal(book, use_generic_cover_on_failure=True, resolution=resolution)
|
||||
|
||||
|
||||
def get_cached_book_cover_thumbnail(cache_id):
|
||||
parts = cache_id.split('_')
|
||||
thumbnail_uuid = parts[0] if len(parts) else None
|
||||
thumbnail = None
|
||||
if thumbnail_uuid:
|
||||
thumbnail = ub.session\
|
||||
.query(ub.Thumbnail)\
|
||||
.filter(ub.Thumbnail.uuid == thumbnail_uuid)\
|
||||
.first()
|
||||
|
||||
if thumbnail and thumbnail.expiration > datetime.utcnow():
|
||||
cache = fs.FileSystem()
|
||||
if cache.get_cache_file_path(thumbnail.filename, fs.CACHE_TYPE_THUMBNAILS):
|
||||
return send_from_directory(cache.get_cache_dir(fs.CACHE_TYPE_THUMBNAILS), thumbnail.filename)
|
||||
|
||||
elif thumbnail:
|
||||
book = calibre_db.get_book(thumbnail.book_id)
|
||||
return get_book_cover_internal(book, use_generic_cover_on_failure=True)
|
||||
|
||||
else:
|
||||
return get_cover_on_failure(True)
|
||||
|
||||
|
||||
def get_book_cover_internal(book, use_generic_cover_on_failure, resolution=None):
|
||||
if book and book.has_cover:
|
||||
|
||||
|
|
|
@ -139,3 +139,19 @@ def book_cover_cache_id(book, resolution=None):
|
|||
timestamp = int(book.last_modified.timestamp() * 1000)
|
||||
cache_bust = str(book.uuid) + '_' + str(timestamp)
|
||||
return cache_bust if not resolution else cache_bust + '_' + str(resolution)
|
||||
|
||||
|
||||
@jinjia.app_template_filter('get_book_thumbnails')
|
||||
def get_book_thumbnails(book_id, thumbnails=None):
|
||||
return list(filter(lambda t: t.book_id == book_id, thumbnails)) if book_id > -1 and thumbnails else list()
|
||||
|
||||
|
||||
@jinjia.app_template_filter('get_book_thumbnail_srcset')
|
||||
def get_book_thumbnail_srcset(thumbnails):
|
||||
srcset = list()
|
||||
for thumbnail in thumbnails:
|
||||
timestamp = int(thumbnail.generated_at.timestamp() * 1000)
|
||||
cache_id = str(thumbnail.uuid) + '_' + str(timestamp)
|
||||
url = url_for('web.get_cached_cover_thumbnail', cache_id=cache_id)
|
||||
srcset.append(url + ' ' + str(thumbnail.resolution) + 'x')
|
||||
return ', '.join(srcset)
|
||||
|
|
|
@ -20,17 +20,17 @@ from __future__ import division, print_function, unicode_literals
|
|||
|
||||
from .services.background_scheduler import BackgroundScheduler
|
||||
from .tasks.database import TaskReconnectDatabase
|
||||
from .tasks.thumbnail import TaskCleanupCoverThumbnailCache, TaskGenerateCoverThumbnails
|
||||
from .tasks.thumbnail import TaskSyncCoverThumbnailCache, TaskGenerateCoverThumbnails
|
||||
|
||||
|
||||
def register_jobs():
|
||||
scheduler = BackgroundScheduler()
|
||||
|
||||
# Generate 100 book cover thumbnails every 5 minutes
|
||||
scheduler.add_task(user=None, task=lambda: TaskGenerateCoverThumbnails(limit=100), trigger='interval', minutes=5)
|
||||
scheduler.add_task(user=None, task=lambda: TaskGenerateCoverThumbnails(limit=100), trigger='cron', minute='*/5')
|
||||
|
||||
# Cleanup book cover cache every day at 4am
|
||||
scheduler.add_task(user=None, task=lambda: TaskCleanupCoverThumbnailCache(), trigger='cron', hour=4)
|
||||
# Cleanup book cover cache every 6 hours
|
||||
scheduler.add_task(user=None, task=lambda: TaskSyncCoverThumbnailCache(), trigger='cron', minute='15', hour='*/6')
|
||||
|
||||
# Reconnect metadata.db every 4 hours
|
||||
scheduler.add_task(user=None, task=lambda: TaskReconnectDatabase(), trigger='interval', hours=4)
|
||||
scheduler.add_task(user=None, task=lambda: TaskReconnectDatabase(), trigger='cron', minute='5', hour='*/4')
|
||||
|
|
|
@ -59,6 +59,10 @@ class TaskGenerateCoverThumbnails(CalibreTask):
|
|||
books_without_thumbnails = self.get_books_without_thumbnails(thumbnail_book_ids)
|
||||
|
||||
count = len(books_without_thumbnails)
|
||||
if count == 0:
|
||||
# Do not display this task on the frontend if there are no covers to update
|
||||
self.self_cleanup = True
|
||||
|
||||
for i, book in enumerate(books_without_thumbnails):
|
||||
for resolution in self.resolutions:
|
||||
expired_thumbnail = self.get_expired_thumbnail_for_book_and_resolution(
|
||||
|
@ -71,6 +75,7 @@ class TaskGenerateCoverThumbnails(CalibreTask):
|
|||
else:
|
||||
self.create_book_thumbnail(book, resolution)
|
||||
|
||||
self.message(u'Generating cover thumbnail {0} of {1}'.format(i, count))
|
||||
self.progress = (1.0 / count) * i
|
||||
|
||||
self._handleSuccess()
|
||||
|
@ -181,12 +186,12 @@ class TaskGenerateCoverThumbnails(CalibreTask):
|
|||
|
||||
@property
|
||||
def name(self):
|
||||
return "GenerateCoverThumbnails"
|
||||
return "ThumbnailsGenerate"
|
||||
|
||||
|
||||
class TaskCleanupCoverThumbnailCache(CalibreTask):
|
||||
def __init__(self, task_message=u'Cleaning up cover thumbnail cache'):
|
||||
super(TaskCleanupCoverThumbnailCache, self).__init__(task_message)
|
||||
class TaskSyncCoverThumbnailCache(CalibreTask):
|
||||
def __init__(self, task_message=u'Syncing cover thumbnail cache'):
|
||||
super(TaskSyncCoverThumbnailCache, self).__init__(task_message)
|
||||
self.log = logger.create()
|
||||
self.app_db_session = ub.get_new_session_instance()
|
||||
self.calibre_db = db.CalibreDB(expire_on_commit=False)
|
||||
|
@ -199,14 +204,23 @@ class TaskCleanupCoverThumbnailCache(CalibreTask):
|
|||
# This case will happen if a user deletes the cache dir or cached files
|
||||
if self.app_db_session:
|
||||
self.expire_missing_thumbnails(cached_thumbnail_files)
|
||||
self.progress = 0.33
|
||||
self.progress = 0.25
|
||||
|
||||
# Delete thumbnails in the database if the book has been removed
|
||||
# This case will happen if a book is removed in Calibre and the metadata.db file is updated in the filesystem
|
||||
if self.app_db_session and self.calibre_db:
|
||||
book_ids = self.get_book_ids()
|
||||
self.delete_thumbnails_for_missing_books(book_ids)
|
||||
self.progress = 0.66
|
||||
self.progress = 0.50
|
||||
|
||||
# Expire thumbnails in the database if their corresponding book has been updated since they were generated
|
||||
# This case will happen if the book was updated externally
|
||||
if self.app_db_session and self.cache:
|
||||
books = self.get_books_updated_in_the_last_day()
|
||||
book_ids = list(map(lambda b: b.id, books))
|
||||
thumbnails = self.get_thumbnails_for_updated_books(book_ids)
|
||||
self.expire_thumbnails_for_updated_book(books, thumbnails)
|
||||
self.progress = 0.75
|
||||
|
||||
# Delete extraneous cached thumbnail files
|
||||
# This case will happen if a book was deleted and the thumbnail OR the metadata.db file was changed externally
|
||||
|
@ -261,9 +275,40 @@ class TaskCleanupCoverThumbnailCache(CalibreTask):
|
|||
for file in extraneous_files:
|
||||
self.cache.delete_cache_file(file, fs.CACHE_TYPE_THUMBNAILS)
|
||||
|
||||
def get_books_updated_in_the_last_day(self):
|
||||
return self.calibre_db.session\
|
||||
.query(db.Books)\
|
||||
.filter(db.Books.has_cover == 1)\
|
||||
.filter(db.Books.last_modified > datetime.utcnow() - timedelta(days=1, hours=1))\
|
||||
.all()
|
||||
|
||||
def get_thumbnails_for_updated_books(self, book_ids):
|
||||
return self.app_db_session\
|
||||
.query(ub.Thumbnail)\
|
||||
.filter(ub.Thumbnail.book_id.in_(book_ids))\
|
||||
.all()
|
||||
|
||||
def expire_thumbnails_for_updated_book(self, books, thumbnails):
|
||||
thumbnail_ids = list()
|
||||
for book in books:
|
||||
for thumbnail in thumbnails:
|
||||
if thumbnail.book_id == book.id and thumbnail.generated_at < book.last_modified:
|
||||
thumbnail_ids.append(thumbnail.id)
|
||||
|
||||
try:
|
||||
self.app_db_session\
|
||||
.query(ub.Thumbnail)\
|
||||
.filter(ub.Thumbnail.id.in_(thumbnail_ids)) \
|
||||
.update({"expiration": datetime.utcnow()}, synchronize_session=False)
|
||||
self.app_db_session.commit()
|
||||
except Exception as ex:
|
||||
self.log.info(u'Error expiring thumbnails for updated books: ' + str(ex))
|
||||
self._handleError(u'Error expiring thumbnails for updated books: ' + str(ex))
|
||||
self.app_db_session.rollback()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return "CleanupCoverThumbnailCache"
|
||||
return "ThumbnailsSync"
|
||||
|
||||
|
||||
class TaskClearCoverThumbnailCache(CalibreTask):
|
||||
|
@ -318,4 +363,4 @@ class TaskClearCoverThumbnailCache(CalibreTask):
|
|||
|
||||
@property
|
||||
def name(self):
|
||||
return "ClearCoverThumbnailCache"
|
||||
return "ThumbnailsClear"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||
<div class="cover">
|
||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
{% macro book_cover_image(book, book_title) -%}
|
||||
<img
|
||||
srcset="{{ url_for('web.get_cached_cover', cache_id=book|book_cover_cache_id(1)) }} 1x,
|
||||
{{ url_for('web.get_cached_cover', cache_id=book|book_cover_cache_id(2)) }} 2x"
|
||||
src="{{ url_for('web.get_cached_cover', cache_id=book|book_cover_cache_id) }}"
|
||||
alt="{{ book_title }}"
|
||||
/>
|
||||
{% macro book_cover_image(book, thumbnails) -%}
|
||||
{%- set book_title = book.title if book.title else book.name -%}
|
||||
{% set srcset = thumbnails|get_book_thumbnail_srcset if thumbnails|length else '' %}
|
||||
{%- if srcset|length -%}
|
||||
<img
|
||||
srcset="{{ srcset }}"
|
||||
src="{{ url_for('web.get_cached_cover', cache_id=book|book_cover_cache_id) }}"
|
||||
alt="{{ book_title }}"
|
||||
/>
|
||||
{%- else -%}
|
||||
<img src="{{ url_for('web.get_cached_cover', cache_id=book|book_cover_cache_id) }}" alt="{{ book_title }}" />
|
||||
{%- endif -%}
|
||||
{%- endmacro %}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% if book %}
|
||||
<div class="col-sm-3 col-lg-3 col-xs-12">
|
||||
<div class="cover">
|
||||
{{ book_cover_image(book, book.title) }}
|
||||
{{ book_cover_image(book, book.id|get_book_thumbnails(thumbnails)) }}
|
||||
</div>
|
||||
{% if g.user.role_delete_books() %}
|
||||
<div class="text-center">
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-3 col-lg-3 col-xs-5">
|
||||
<div class="cover">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9 col-lg-9 book-meta">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<div class="cover">
|
||||
{% if entry.has_cover is defined %}
|
||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<div class="col-sm-3 col-lg-2 col-xs-6 book sortable" {% if entry[0].sort %}data-name="{{entry[0].series[0].name}}"{% endif %} data-id="{% if entry[0].series[0].name %}{{entry[0].series[0].name}}{% endif %}">
|
||||
<div class="cover">
|
||||
<a href="{{url_for('web.books_list', data=data, sort_param='new', book_id=entry[0].series[0].id )}}">
|
||||
{{ book_cover_image(entry[0], entry[0].name) }}
|
||||
{{ book_cover_image(entry[0], entry[0].id|get_book_thumbnails(thumbnails)) }}
|
||||
<span class="badge">{{entry.count}}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
|
||||
<div class="cover">
|
||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
|
@ -83,7 +83,7 @@
|
|||
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
|
||||
<div class="cover">
|
||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<div class="cover">
|
||||
{% if entry.has_cover is defined %}
|
||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<div class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||
<div class="cover">
|
||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||
{{ book_cover_image(entry, entry.title) }}
|
||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
|
|
89
cps/web.py
89
cps/web.py
|
@ -49,9 +49,10 @@ from . import constants, logger, isoLanguages, services
|
|||
from . import babel, db, ub, config, get_locale, app
|
||||
from . import calibre_db, shelf
|
||||
from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
|
||||
from .helper import check_valid_domain, render_task_status, \
|
||||
get_cc_columns, get_book_cover, get_cached_book_cover, get_download_link, send_mail, generate_random_password, \
|
||||
send_registration_mail, check_send_to_kindle, check_read_formats, tags_filters, reset_password
|
||||
from .helper import check_valid_domain, render_task_status, get_cc_columns, get_book_cover, get_cached_book_cover, \
|
||||
get_cached_book_cover_thumbnail, get_thumbnails_for_books, get_thumbnails_for_book_series, get_download_link, \
|
||||
send_mail, generate_random_password, send_registration_mail, check_send_to_kindle, check_read_formats, \
|
||||
tags_filters, reset_password
|
||||
from .pagination import Pagination
|
||||
from .redirect import redirect_back
|
||||
from .usermanagement import login_required_if_no_ano
|
||||
|
@ -386,16 +387,18 @@ def render_books_list(data, sort, book_id, page):
|
|||
db.Books,
|
||||
db.Books.ratings.any(db.Ratings.rating > 9),
|
||||
order)
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
id=book_id, title=_(u"Top Rated Books"), page="rated")
|
||||
id=book_id, title=_(u"Top Rated Books"), page="rated", thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
elif data == "discover":
|
||||
if current_user.check_visibility(constants.SIDEBAR_RANDOM):
|
||||
entries, __, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, [func.randomblob(2)])
|
||||
pagination = Pagination(1, config.config_books_per_page, config.config_books_per_page)
|
||||
thumbnails = get_thumbnails_for_books(entries)
|
||||
return render_title_template('discover.html', entries=entries, pagination=pagination, id=book_id,
|
||||
title=_(u"Discover (Random Books)"), page="discover")
|
||||
title=_(u"Discover (Random Books)"), page="discover", thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
elif data == "unread":
|
||||
|
@ -433,8 +436,9 @@ def render_books_list(data, sort, book_id, page):
|
|||
else:
|
||||
website = data or "newest"
|
||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, order)
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=_(u"Books"), page=website)
|
||||
title=_(u"Books"), page=website, thumbnails=thumbnails)
|
||||
|
||||
|
||||
def render_hot_books(page):
|
||||
|
@ -458,8 +462,9 @@ def render_hot_books(page):
|
|||
ub.delete_download(book.Downloads.book_id)
|
||||
numBooks = entries.__len__()
|
||||
pagination = Pagination(page, config.config_books_per_page, numBooks)
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=_(u"Hot Books (Most Downloaded)"), page="hot")
|
||||
title=_(u"Hot Books (Most Downloaded)"), page="hot", thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -490,12 +495,14 @@ def render_downloaded_books(page, order):
|
|||
.filter(db.Books.id == book.id).first():
|
||||
ub.delete_download(book.id)
|
||||
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html',
|
||||
random=random,
|
||||
entries=entries,
|
||||
pagination=pagination,
|
||||
title=_(u"Downloaded books by %(user)s",user=current_user.nickname),
|
||||
page="download")
|
||||
page="download",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -521,9 +528,10 @@ def render_author_books(page, author_id, order):
|
|||
author_info = services.goodreads_support.get_author_info(author_name)
|
||||
other_books = services.goodreads_support.get_other_books(author_info, entries)
|
||||
|
||||
thumbnails = get_thumbnails_for_books(entries)
|
||||
return render_title_template('author.html', entries=entries, pagination=pagination, id=author_id,
|
||||
title=_(u"Author: %(name)s", name=author_name), author=author_info,
|
||||
other_books=other_books, page="author")
|
||||
other_books=other_books, page="author", thumbnails=thumbnails)
|
||||
|
||||
|
||||
def render_publisher_books(page, book_id, order):
|
||||
|
@ -535,8 +543,10 @@ def render_publisher_books(page, book_id, order):
|
|||
[db.Series.name, order[0], db.Books.series_index],
|
||||
db.books_series_link,
|
||||
db.Series)
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id,
|
||||
title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher")
|
||||
title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -548,8 +558,10 @@ def render_series_books(page, book_id, order):
|
|||
db.Books,
|
||||
db.Books.series.any(db.Series.id == book_id),
|
||||
[order[0]])
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||
title=_(u"Series: %(serie)s", serie=name.name), page="series")
|
||||
title=_(u"Series: %(serie)s", serie=name.name), page="series",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -561,8 +573,10 @@ def render_ratings_books(page, book_id, order):
|
|||
db.Books.ratings.any(db.Ratings.id == book_id),
|
||||
[order[0]])
|
||||
if name and name.rating <= 10:
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||
title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)), page="ratings")
|
||||
title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)), page="ratings",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -574,8 +588,10 @@ def render_formats_books(page, book_id, order):
|
|||
db.Books,
|
||||
db.Books.data.any(db.Data.format == book_id.upper()),
|
||||
[order[0]])
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||
title=_(u"File format: %(format)s", format=name.format), page="formats")
|
||||
title=_(u"File format: %(format)s", format=name.format), page="formats",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -588,8 +604,10 @@ def render_category_books(page, book_id, order):
|
|||
db.Books.tags.any(db.Tags.id == book_id),
|
||||
[order[0], db.Series.name, db.Books.series_index],
|
||||
db.books_series_link, db.Series)
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
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")
|
||||
title=_(u"Category: %(name)s", name=name.name), page="category",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -607,8 +625,9 @@ def render_language_books(page, name, order):
|
|||
db.Books,
|
||||
db.Books.languages.any(db.Languages.lang_code == name),
|
||||
[order[0]])
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name,
|
||||
title=_(u"Language: %(name)s", name=lang_name), page="language")
|
||||
title=_(u"Language: %(name)s", name=lang_name), page="language", thumbnails=thumbnails)
|
||||
|
||||
|
||||
def render_read_books(page, are_read, as_xml=False, order=None):
|
||||
|
@ -652,8 +671,10 @@ def render_read_books(page, are_read, as_xml=False, order=None):
|
|||
else:
|
||||
name = _(u'Unread Books') + ' (' + str(pagination.total_count) + ')'
|
||||
pagename = "unread"
|
||||
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=name, page=pagename)
|
||||
title=name, page=pagename, thumbnails=thumbnails)
|
||||
|
||||
|
||||
def render_archived_books(page, order):
|
||||
|
@ -676,8 +697,9 @@ def render_archived_books(page, order):
|
|||
|
||||
name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')'
|
||||
pagename = "archived"
|
||||
thumbnails = get_thumbnails_for_books(entries + random)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=name, page=pagename)
|
||||
title=name, page=pagename, thumbnails=thumbnails)
|
||||
|
||||
|
||||
def render_prepare_search_form(cc):
|
||||
|
@ -710,6 +732,7 @@ def render_prepare_search_form(cc):
|
|||
|
||||
def render_search_results(term, offset=None, order=None, limit=None):
|
||||
entries, result_count, pagination = calibre_db.get_search_results(term, offset, order, limit)
|
||||
thumbnails = get_thumbnails_for_books(entries)
|
||||
return render_title_template('search.html',
|
||||
searchterm=term,
|
||||
pagination=pagination,
|
||||
|
@ -718,7 +741,8 @@ def render_search_results(term, offset=None, order=None, limit=None):
|
|||
entries=entries,
|
||||
result_count=result_count,
|
||||
title=_(u"Search"),
|
||||
page="search")
|
||||
page="search",
|
||||
thumbnails=thumbnails)
|
||||
|
||||
|
||||
# ################################### View Books list ##################################################################
|
||||
|
@ -748,6 +772,7 @@ def books_table():
|
|||
return render_title_template('book_table.html', title=_(u"Books List"), page="book_table",
|
||||
visiblility=visibility)
|
||||
|
||||
|
||||
@web.route("/ajax/listbooks")
|
||||
@login_required
|
||||
def list_books():
|
||||
|
@ -780,6 +805,7 @@ def list_books():
|
|||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
return response
|
||||
|
||||
|
||||
@web.route("/ajax/table_settings", methods=['POST'])
|
||||
@login_required
|
||||
def update_table_settings():
|
||||
|
@ -834,6 +860,7 @@ def publisher_list():
|
|||
charlist = calibre_db.session.query(func.upper(func.substr(db.Publishers.name, 1, 1)).label('char')) \
|
||||
.join(db.books_publishers_link).join(db.Books).filter(calibre_db.common_filters()) \
|
||||
.group_by(func.upper(func.substr(db.Publishers.name, 1, 1))).all()
|
||||
|
||||
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist,
|
||||
title=_(u"Publishers"), page="publisherlist", data="publisher")
|
||||
else:
|
||||
|
@ -865,8 +892,10 @@ def series_list():
|
|||
.join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \
|
||||
.group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all()
|
||||
|
||||
thumbnails = get_thumbnails_for_book_series(entries)
|
||||
return render_title_template('grid.html', entries=entries, folder='web.books_list', charlist=charlist,
|
||||
title=_(u"Series"), page="serieslist", data="series", bodyClass="grid-view")
|
||||
title=_(u"Series"), page="serieslist", data="series", bodyClass="grid-view",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -1150,13 +1179,16 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
|||
else:
|
||||
offset = 0
|
||||
limit_all = result_count
|
||||
|
||||
thumbnails = get_thumbnails_for_books(entries)
|
||||
return render_title_template('search.html',
|
||||
adv_searchterm=searchterm,
|
||||
pagination=pagination,
|
||||
entries=q[offset:limit_all],
|
||||
result_count=result_count,
|
||||
title=_(u"Advanced Search"), page="advsearch")
|
||||
|
||||
title=_(u"Advanced Search"),
|
||||
page="advsearch",
|
||||
thumbnails=thumbnails)
|
||||
|
||||
|
||||
@web.route("/advsearch", methods=['GET'])
|
||||
|
@ -1171,10 +1203,9 @@ def advanced_search_form():
|
|||
|
||||
|
||||
@web.route("/cover/<int:book_id>")
|
||||
@web.route("/cover/<int:book_id>/<int:resolution>")
|
||||
@login_required_if_no_ano
|
||||
def get_cover(book_id, resolution=1):
|
||||
return get_book_cover(book_id, resolution)
|
||||
def get_cover(book_id):
|
||||
return get_book_cover(book_id)
|
||||
|
||||
|
||||
@web.route("/cached-cover/<string:cache_id>")
|
||||
|
@ -1183,6 +1214,12 @@ def get_cached_cover(cache_id):
|
|||
return get_cached_book_cover(cache_id)
|
||||
|
||||
|
||||
@web.route("/cached-cover-thumbnail/<string:cache_id>")
|
||||
@login_required_if_no_ano
|
||||
def get_cached_cover_thumbnail(cache_id):
|
||||
return get_cached_book_cover_thumbnail(cache_id)
|
||||
|
||||
|
||||
@web.route("/robots.txt")
|
||||
def get_robots():
|
||||
return send_from_directory(constants.STATIC_DIR, "robots.txt")
|
||||
|
@ -1591,6 +1628,7 @@ def show_book(book_id):
|
|||
if media_format.format.lower() in constants.EXTENSIONS_AUDIO:
|
||||
audioentries.append(media_format.format.lower())
|
||||
|
||||
thumbnails = get_thumbnails_for_books([entries])
|
||||
return render_title_template('detail.html',
|
||||
entry=entries,
|
||||
audioentries=audioentries,
|
||||
|
@ -1602,7 +1640,8 @@ def show_book(book_id):
|
|||
is_archived=is_archived,
|
||||
kindle_list=kindle_list,
|
||||
reader_list=reader_list,
|
||||
page="book")
|
||||
page="book",
|
||||
thumbnails=thumbnails)
|
||||
else:
|
||||
log.debug(u"Error opening eBook. File does not exist or file is not accessible")
|
||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error")
|
||||
|
|
Loading…
Reference in New Issue
Block a user