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