diff --git a/cps/__init__.py b/cps/__init__.py
index f6df9636..68947905 100644
--- a/cps/__init__.py
+++ b/cps/__init__.py
@@ -179,12 +179,6 @@ def get_locale():
return negotiate_locale(preferred or ['en'], _BABEL_TRANSLATIONS)
-@babel.timezoneselector
-def get_timezone():
- user = getattr(g, 'user', None)
- return user.timezone if user else None
-
-
from .updater import Updater
updater_thread = Updater()
diff --git a/cps/db.py b/cps/db.py
index 68e02b81..3dd2907d 100644
--- a/cps/db.py
+++ b/cps/db.py
@@ -940,7 +940,10 @@ class CalibreDB:
return title.strip()
conn = conn or self.session.connection().connection.connection
- conn.create_function("title_sort", 1, _title_sort)
+ try:
+ conn.create_function("title_sort", 1, _title_sort)
+ except OperationalError:
+ pass
@classmethod
def dispose(cls):
diff --git a/cps/editbooks.py b/cps/editbooks.py
index 8e815fd4..1d61c8dd 100755
--- a/cps/editbooks.py
+++ b/cps/editbooks.py
@@ -1132,6 +1132,7 @@ def upload():
link = '{}'.format(url_for('web.show_book', book_id=book_id), escape(title))
upload_text = _(u"File %(file)s uploaded", file=link)
WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(title)))
+ helper.add_book_to_thumbnail_cache(book_id)
if len(request.files.getlist("btn-upload")) < 2:
if current_user.role_edit() or current_user.role_admin():
diff --git a/cps/helper.py b/cps/helper.py
index 9d8a1d3b..77317343 100644
--- a/cps/helper.py
+++ b/cps/helper.py
@@ -60,7 +60,7 @@ from .subproc_wrapper import process_wait
from .services.worker import WorkerThread, STAT_WAITING, STAT_FAIL, STAT_STARTED, STAT_FINISH_SUCCESS, STAT_ENDED, \
STAT_CANCELLED
from .tasks.mail import TaskEmail
-from .tasks.thumbnail import TaskClearCoverThumbnailCache
+from .tasks.thumbnail import TaskClearCoverThumbnailCache, TaskGenerateCoverThumbnails
log = logger.create()
@@ -715,9 +715,10 @@ def get_book_cover(book_id, resolution=None):
return get_book_cover_internal(book, use_generic_cover_on_failure=True, resolution=resolution)
-def get_book_cover_with_uuid(book_uuid, use_generic_cover_on_failure=True):
+# Called only by kobo sync -> cover not found should be answered with 404 and not with default cover
+def get_book_cover_with_uuid(book_uuid, resolution=None):
book = calibre_db.get_book_by_uuid(book_uuid)
- return get_book_cover_internal(book, use_generic_cover_on_failure)
+ return get_book_cover_internal(book, use_generic_cover_on_failure=False, resolution=resolution)
def get_book_cover_internal(book, use_generic_cover_on_failure, resolution=None):
@@ -1079,5 +1080,10 @@ def get_download_link(book_id, book_format, client):
def clear_cover_thumbnail_cache(book_id):
WorkerThread.add(None, TaskClearCoverThumbnailCache(book_id))
+
def delete_thumbnail_cache():
WorkerThread.add(None, TaskClearCoverThumbnailCache(-1))
+
+
+def add_book_to_thumbnail_cache(book_id):
+ WorkerThread.add(None, TaskGenerateCoverThumbnails(book_id))
diff --git a/cps/kobo.py b/cps/kobo.py
index d02660b2..f2a3b2f8 100644
--- a/cps/kobo.py
+++ b/cps/kobo.py
@@ -45,7 +45,7 @@ import requests
from . import config, logger, kobo_auth, db, calibre_db, helper, shelf as shelf_lib, ub, csrf, kobo_sync_status
-from .constants import sqlalchemy_version2
+from .constants import sqlalchemy_version2, COVER_THUMBNAIL_SMALL
from .helper import get_download_link
from .services import SyncToken as SyncToken
from .web import download_required
@@ -915,10 +915,8 @@ def get_current_bookmark_response(current_bookmark):
@kobo.route("/////image.jpg", defaults={'Quality': ""})
@kobo.route("//////image.jpg")
@requires_kobo_auth
-def HandleCoverImageRequest(book_uuid, width, height,Quality, isGreyscale):
- book_cover = helper.get_book_cover_with_uuid(
- book_uuid, use_generic_cover_on_failure=False
- )
+def HandleCoverImageRequest(book_uuid, width, height, Quality, isGreyscale):
+ book_cover = helper.get_book_cover_with_uuid(book_uuid, resolution=COVER_THUMBNAIL_SMALL)
if not book_cover:
if config.config_kobo_proxy:
log.debug("Cover for unknown book: %s proxied to kobo" % book_uuid)
diff --git a/cps/tasks/thumbnail.py b/cps/tasks/thumbnail.py
index 3601ff93..0d824e7c 100644
--- a/cps/tasks/thumbnail.py
+++ b/cps/tasks/thumbnail.py
@@ -64,9 +64,10 @@ def get_best_fit(width, height, image_width, image_height):
class TaskGenerateCoverThumbnails(CalibreTask):
- def __init__(self, task_message=''):
+ def __init__(self, book_id=-1, task_message=''):
super(TaskGenerateCoverThumbnails, self).__init__(task_message)
self.log = logger.create()
+ self.book_id = book_id
self.app_db_session = ub.get_new_session_instance()
self.calibre_db = db.CalibreDB(expire_on_commit=False)
self.cache = fs.FileSystem()
@@ -77,31 +78,20 @@ class TaskGenerateCoverThumbnails(CalibreTask):
def run(self, worker_thread):
if self.calibre_db.session and use_IM and self.stat != STAT_CANCELLED and self.stat != STAT_ENDED:
+ if self.book_id < 0:
+ self.create_book_cover_thumbnails(self.book_id)
+ self._handleSuccess()
+ self.app_db_session.remove()
+ return
self.message = 'Scanning Books'
books_with_covers = self.get_books_with_covers()
count = len(books_with_covers)
total_generated = 0
for i, book in enumerate(books_with_covers):
- generated = 0
- book_cover_thumbnails = self.get_book_cover_thumbnails(book.id)
# Generate new thumbnails for missing covers
- resolutions = list(map(lambda t: t.resolution, book_cover_thumbnails))
- missing_resolutions = list(set(self.resolutions).difference(resolutions))
- for resolution in missing_resolutions:
- generated += 1
- self.create_book_cover_thumbnail(book, resolution)
-
- # Replace outdated or missing thumbnails
- for thumbnail in book_cover_thumbnails:
- if book.last_modified > thumbnail.generated_at:
- generated += 1
- self.update_book_cover_thumbnail(book, thumbnail)
-
- elif not self.cache.get_cache_file_exists(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS):
- generated += 1
- self.update_book_cover_thumbnail(book, thumbnail)
+ generated = self.create_book_cover_thumbnails(book)
# Increment the progress
self.progress = (1.0 / count) * i
@@ -139,7 +129,29 @@ class TaskGenerateCoverThumbnails(CalibreTask):
.filter(or_(ub.Thumbnail.expiration.is_(None), ub.Thumbnail.expiration > datetime.utcnow())) \
.all()
- def create_book_cover_thumbnail(self, book, resolution):
+ def create_book_cover_thumbnails(self, book):
+ generated = 0
+ book_cover_thumbnails = self.get_book_cover_thumbnails(book.id)
+
+ # Generate new thumbnails for missing covers
+ resolutions = list(map(lambda t: t.resolution, book_cover_thumbnails))
+ missing_resolutions = list(set(self.resolutions).difference(resolutions))
+ for resolution in missing_resolutions:
+ generated += 1
+ self.create_book_cover_single_thumbnail(book, resolution)
+
+ # Replace outdated or missing thumbnails
+ for thumbnail in book_cover_thumbnails:
+ if book.last_modified > thumbnail.generated_at:
+ generated += 1
+ self.update_book_cover_thumbnail(book, thumbnail)
+
+ elif not self.cache.get_cache_file_exists(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS):
+ generated += 1
+ self.update_book_cover_thumbnail(book, thumbnail)
+ return generated
+
+ def create_book_cover_single_thumbnail(self, book, resolution):
thumbnail = ub.Thumbnail()
thumbnail.type = constants.THUMBNAIL_TYPE_COVER
thumbnail.entity_id = book.id