From a3f17deb17bcc7201eae42e517d28c70e3af8257 Mon Sep 17 00:00:00 2001 From: alfred82santa Date: Sat, 6 Feb 2021 20:29:43 +0100 Subject: [PATCH 1/6] Added options in order to synchronize only selected shelf on Kobo device --- cps/kobo.py | 68 ++++++++++++++++++++++++----------- cps/shelf.py | 6 ++++ cps/templates/shelf_edit.html | 5 +++ cps/ub.py | 10 ++++++ 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/cps/kobo.py b/cps/kobo.py index d019e918..f114706f 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -82,6 +82,7 @@ CONNECTION_SPECIFIC_HEADERS = [ "transfer-encoding", ] + def get_kobo_activated(): return config.config_kobo_sync @@ -152,30 +153,35 @@ def HandleSyncRequest(): # in case of external changes (e.g: adding a book through Calibre). calibre_db.reconnect_db(config, ub.app_DB_path) - if sync_token.books_last_id > -1: - changed_entries = ( - calibre_db.session.query(db.Books, ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) - .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) - .filter(db.Books.last_modified >= sync_token.books_last_modified) - .filter(db.Books.id>sync_token.books_last_id) - .filter(db.Data.format.in_(KOBO_FORMATS)) - .order_by(db.Books.last_modified) - .order_by(db.Books.id) - .limit(SYNC_ITEM_LIMIT) - ) - else: - changed_entries = ( - calibre_db.session.query(db.Books, ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) + changed_entries = ( + calibre_db.session.query(db.Books, ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) .filter(db.Books.last_modified > sync_token.books_last_modified) .filter(db.Data.format.in_(KOBO_FORMATS)) .order_by(db.Books.last_modified) .order_by(db.Books.id) - .limit(SYNC_ITEM_LIMIT) + ) + + if sync_token.books_last_id > -1: + changed_entries = changed_entries.filter(db.Books.id > sync_token.books_last_id) + + only_kobo_shelfs = ( + calibre_db.session.query(ub.Shelf) + .filter(ub.Shelf.user_id == current_user.id) + .filter(ub.Shelf.kobo_sync) + .count() + ) > 0 + + if only_kobo_shelfs: + changed_entries = ( + changed_entries.join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) + .join(ub.Shelf) + .filter(ub.Shelf.kobo_sync) + .distinct() ) reading_states_in_new_entitlements = [] - for book in changed_entries: + for book in changed_entries.limit(SYNC_ITEM_LIMIT): formats = [data.format for data in book.Books.data] if not 'KEPUB' in formats and config.config_kepubifypath and 'EPUB' in formats: helper.convert_book_format(book.Books.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.nickname) @@ -238,7 +244,7 @@ def HandleSyncRequest(): }) new_reading_state_last_modified = max(new_reading_state_last_modified, kobo_reading_state.last_modified) - sync_shelves(sync_token, sync_results) + sync_shelves(sync_token, sync_results, only_kobo_shelfs=only_kobo_shelfs) sync_token.books_last_created = new_books_last_created sync_token.books_last_modified = new_books_last_modified @@ -392,7 +398,7 @@ def get_metadata(book): book_uuid = book.uuid metadata = { - "Categories": ["00000000-0000-0000-0000-000000000001",], + "Categories": ["00000000-0000-0000-0000-000000000001", ], # "Contributors": get_author(book), "CoverImageId": book_uuid, "CrossRevisionId": book_uuid, @@ -599,7 +605,7 @@ def HandleTagRemoveItem(tag_id): # Add new, changed, or deleted shelves to the sync_results. # Note: Public shelves that aren't owned by the user aren't supported. -def sync_shelves(sync_token, sync_results): +def sync_shelves(sync_token, sync_results, only_kobo_shelfs=False): new_tags_last_modified = sync_token.tags_last_modified for shelf in ub.session.query(ub.ShelfArchive).filter(func.datetime(ub.ShelfArchive.last_modified) > sync_token.tags_last_modified, @@ -615,8 +621,28 @@ def sync_shelves(sync_token, sync_results): } }) - for shelf in ub.session.query(ub.Shelf).filter(func.datetime(ub.Shelf.last_modified) > sync_token.tags_last_modified, - ub.Shelf.user_id == current_user.id): + extra_filters = [] + if only_kobo_shelfs: + for shelf in ub.session.query(ub.Shelf).filter( + func.datetime(ub.Shelf.last_modified) > sync_token.tags_last_modified, + ub.Shelf.user_id == current_user.id, + not ub.Shelf.kobo_sync + ): + sync_results.append({ + "DeletedTag": { + "Tag": { + "Id": shelf.uuid, + "LastModified": convert_to_kobo_timestamp_string(shelf.last_modified) + } + } + }) + extra_filters.append(ub.Shelf.kobo_sync) + + for shelf in ub.session.query(ub.Shelf).filter( + func.datetime(ub.Shelf.last_modified) > sync_token.tags_last_modified, + ub.Shelf.user_id == current_user.id, + *extra_filters + ): if not shelf_lib.check_shelf_view_permissions(shelf): continue diff --git a/cps/shelf.py b/cps/shelf.py index 5c6037ac..bde61e00 100644 --- a/cps/shelf.py +++ b/cps/shelf.py @@ -239,6 +239,12 @@ def create_edit_shelf(shelf, title, page, shelf_id=False): shelf.is_public = 1 else: shelf.is_public = 0 + + if "kobo_sync" in to_save: + shelf.kobo_sync = True + else: + shelf.kobo_sync = False + if check_shelf_is_unique(shelf, to_save, shelf_id): shelf.name = to_save["title"] # shelf.last_modified = datetime.utcnow() diff --git a/cps/templates/shelf_edit.html b/cps/templates/shelf_edit.html index 934efe2b..98acbdf8 100644 --- a/cps/templates/shelf_edit.html +++ b/cps/templates/shelf_edit.html @@ -13,6 +13,11 @@ {{_('Share with Everyone')}} +
+ +
{% endif %} {% if shelf.id != None %} diff --git a/cps/ub.py b/cps/ub.py index 1969ef53..e540f107 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -268,6 +268,7 @@ class Shelf(Base): name = Column(String) is_public = Column(Integer, default=0) user_id = Column(Integer, ForeignKey('user.id')) + kobo_sync = Column(Boolean, default=False) books = relationship("BookShelf", backref="ub_shelf", cascade="all, delete-orphan", lazy="dynamic") created = Column(DateTime, default=datetime.datetime.utcnow) last_modified = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow) @@ -504,6 +505,15 @@ def migrate_Database(session): for book_shelf in session.query(BookShelf).all(): book_shelf.date_added = datetime.datetime.now() session.commit() + + try: + session.query(exists().where(Shelf.kobo_sync)).scalar() + except exc.OperationalError: + with engine.connect() as conn: + + conn.execute("ALTER TABLE shelf ADD column 'kobo_sync' BOOLEAN DEFAULT false") + session.commit() + try: # Handle table exists, but no content cnt = session.query(Registration).count() From 8fe762709bb16a54df47e769a54c859d2017296a Mon Sep 17 00:00:00 2001 From: alfred82santa Date: Sat, 6 Feb 2021 21:15:36 +0100 Subject: [PATCH 2/6] Fix mistake --- cps/kobo.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cps/kobo.py b/cps/kobo.py index f114706f..567e202e 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -165,14 +165,14 @@ def HandleSyncRequest(): if sync_token.books_last_id > -1: changed_entries = changed_entries.filter(db.Books.id > sync_token.books_last_id) - only_kobo_shelfs = ( + only_kobo_shelves = ( calibre_db.session.query(ub.Shelf) .filter(ub.Shelf.user_id == current_user.id) .filter(ub.Shelf.kobo_sync) .count() ) > 0 - if only_kobo_shelfs: + if only_kobo_shelves: changed_entries = ( changed_entries.join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) .join(ub.Shelf) @@ -244,7 +244,7 @@ def HandleSyncRequest(): }) new_reading_state_last_modified = max(new_reading_state_last_modified, kobo_reading_state.last_modified) - sync_shelves(sync_token, sync_results, only_kobo_shelfs=only_kobo_shelfs) + sync_shelves(sync_token, sync_results, only_kobo_shelves=only_kobo_shelves) sync_token.books_last_created = new_books_last_created sync_token.books_last_modified = new_books_last_modified @@ -605,7 +605,7 @@ def HandleTagRemoveItem(tag_id): # Add new, changed, or deleted shelves to the sync_results. # Note: Public shelves that aren't owned by the user aren't supported. -def sync_shelves(sync_token, sync_results, only_kobo_shelfs=False): +def sync_shelves(sync_token, sync_results, only_kobo_shelves=False): new_tags_last_modified = sync_token.tags_last_modified for shelf in ub.session.query(ub.ShelfArchive).filter(func.datetime(ub.ShelfArchive.last_modified) > sync_token.tags_last_modified, @@ -622,7 +622,7 @@ def sync_shelves(sync_token, sync_results, only_kobo_shelfs=False): }) extra_filters = [] - if only_kobo_shelfs: + if only_kobo_shelves: for shelf in ub.session.query(ub.Shelf).filter( func.datetime(ub.Shelf.last_modified) > sync_token.tags_last_modified, ub.Shelf.user_id == current_user.id, From 69b7d947741a6d602809d9d690a6d987a788a49f Mon Sep 17 00:00:00 2001 From: alfred82santa Date: Sun, 7 Feb 2021 00:19:24 +0100 Subject: [PATCH 3/6] Fixes and remove shelf kobo sync flag when kobo sync disabled --- cps/shelf.py | 12 +++++++----- cps/templates/shelf_edit.html | 9 ++++++--- cps/ub.py | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cps/shelf.py b/cps/shelf.py index bde61e00..c8cf1dc2 100644 --- a/cps/shelf.py +++ b/cps/shelf.py @@ -30,7 +30,7 @@ from flask_login import login_required, current_user from sqlalchemy.sql.expression import func, true from sqlalchemy.exc import OperationalError, InvalidRequestError -from . import logger, ub, calibre_db, db +from . import logger, ub, calibre_db, db, config from .render_template import render_title_template from .usermanagement import login_required_if_no_ano @@ -240,10 +240,8 @@ def create_edit_shelf(shelf, title, page, shelf_id=False): else: shelf.is_public = 0 - if "kobo_sync" in to_save: + if config.config_kobo_sync and "kobo_sync" in to_save: shelf.kobo_sync = True - else: - shelf.kobo_sync = False if check_shelf_is_unique(shelf, to_save, shelf_id): shelf.name = to_save["title"] @@ -269,7 +267,11 @@ def create_edit_shelf(shelf, title, page, shelf_id=False): ub.session.rollback() log.debug_or_exception(e) flash(_(u"There was an error"), category="error") - return render_title_template('shelf_edit.html', shelf=shelf, title=title, page=page) + return render_title_template('shelf_edit.html', + shelf=shelf, + title=title, + page=page, + kobo_sync_enabled=config.config_kobo_sync) def check_shelf_is_unique(shelf, to_save, shelf_id=False): diff --git a/cps/templates/shelf_edit.html b/cps/templates/shelf_edit.html index 98acbdf8..246e45ec 100644 --- a/cps/templates/shelf_edit.html +++ b/cps/templates/shelf_edit.html @@ -13,10 +13,13 @@ {{_('Share with Everyone')}} + {% endif %} + {% if kobo_sync_enabled %}
- +
{% endif %} diff --git a/cps/ub.py b/cps/ub.py index e540f107..b773bbe9 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -498,6 +498,7 @@ def migrate_Database(session): conn.execute("ALTER TABLE shelf ADD column 'created' DATETIME") conn.execute("ALTER TABLE shelf ADD column 'last_modified' DATETIME") conn.execute("ALTER TABLE book_shelf_link ADD column 'date_added' DATETIME") + conn.execute("ALTER TABLE shelf ADD column 'kobo_sync' BOOLEAN DEFAULT false") for shelf in session.query(Shelf).all(): shelf.uuid = str(uuid.uuid4()) shelf.created = datetime.datetime.now() From 2b7c1345ee9915fd97f498bf23a0d789d3e36535 Mon Sep 17 00:00:00 2001 From: alfred82santa Date: Sun, 7 Feb 2021 00:21:51 +0100 Subject: [PATCH 4/6] Fix disable shelf kobo sync --- cps/shelf.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/cps/shelf.py b/cps/shelf.py index c8cf1dc2..46468cc3 100644 --- a/cps/shelf.py +++ b/cps/shelf.py @@ -21,20 +21,20 @@ # along with this program. If not, see . from __future__ import division, print_function, unicode_literals -from datetime import datetime + import sys +from datetime import datetime -from flask import Blueprint, request, flash, redirect, url_for +from flask import Blueprint, flash, redirect, request, url_for from flask_babel import gettext as _ -from flask_login import login_required, current_user +from flask_login import current_user, login_required +from sqlalchemy.exc import InvalidRequestError, OperationalError from sqlalchemy.sql.expression import func, true -from sqlalchemy.exc import OperationalError, InvalidRequestError -from . import logger, ub, calibre_db, db, config +from . import calibre_db, config, db, logger, ub from .render_template import render_title_template from .usermanagement import login_required_if_no_ano - shelf = Blueprint('shelf', __name__) log = logger.create() @@ -240,8 +240,11 @@ def create_edit_shelf(shelf, title, page, shelf_id=False): else: shelf.is_public = 0 - if config.config_kobo_sync and "kobo_sync" in to_save: - shelf.kobo_sync = True + if config.config_kobo_sync: + if "kobo_sync" in to_save: + shelf.kobo_sync = True + else: + shelf.kobo_sync = False if check_shelf_is_unique(shelf, to_save, shelf_id): shelf.name = to_save["title"] @@ -358,8 +361,8 @@ def order_shelf(shelf_id): shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() result = list() if shelf and check_shelf_view_permissions(shelf): - result = calibre_db.session.query(db.Books)\ - .join(ub.BookShelf,ub.BookShelf.book_id == db.Books.id , isouter=True) \ + result = calibre_db.session.query(db.Books) \ + .join(ub.BookShelf, ub.BookShelf.book_id == db.Books.id, isouter=True) \ .add_columns(calibre_db.common_filters().label("visible")) \ .filter(ub.BookShelf.shelf == shelf_id).order_by(ub.BookShelf.order.asc()).all() return render_title_template('shelf_order.html', entries=result, @@ -368,7 +371,7 @@ def order_shelf(shelf_id): def change_shelf_order(shelf_id, order): - result = calibre_db.session.query(db.Books).join(ub.BookShelf,ub.BookShelf.book_id == db.Books.id)\ + result = calibre_db.session.query(db.Books).join(ub.BookShelf, ub.BookShelf.book_id == db.Books.id) \ .filter(ub.BookShelf.shelf == shelf_id).order_by(*order).all() for index, entry in enumerate(result): book = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \ @@ -408,13 +411,13 @@ def render_show_shelf(shelf_type, shelf_id, page_no, sort_param): page = 'shelfdown.html' result, __, pagination = calibre_db.fill_indexpage(page_no, pagesize, - db.Books, - ub.BookShelf.shelf == shelf_id, - [ub.BookShelf.order.asc()], - ub.BookShelf,ub.BookShelf.book_id == db.Books.id) + db.Books, + ub.BookShelf.shelf == shelf_id, + [ub.BookShelf.order.asc()], + ub.BookShelf, ub.BookShelf.book_id == db.Books.id) # delete chelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web - wrong_entries = calibre_db.session.query(ub.BookShelf)\ - .join(db.Books, ub.BookShelf.book_id == db.Books.id, isouter=True)\ + wrong_entries = calibre_db.session.query(ub.BookShelf) \ + .join(db.Books, ub.BookShelf.book_id == db.Books.id, isouter=True) \ .filter(db.Books.id == None).all() for entry in wrong_entries: log.info('Not existing book {} in {} deleted'.format(entry.book_id, shelf)) From 6014b04b2a6ab5cd4790a827005d9727431a80c7 Mon Sep 17 00:00:00 2001 From: alfred82santa Date: Mon, 8 Feb 2021 20:10:12 +0100 Subject: [PATCH 5/6] Use BookShelf added_date as date reference --- cps/kobo.py | 79 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/cps/kobo.py b/cps/kobo.py index 567e202e..141d745d 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -153,32 +153,42 @@ def HandleSyncRequest(): # in case of external changes (e.g: adding a book through Calibre). calibre_db.reconnect_db(config, ub.app_DB_path) - changed_entries = ( - calibre_db.session.query(db.Books, ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) - .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) - .filter(db.Books.last_modified > sync_token.books_last_modified) - .filter(db.Data.format.in_(KOBO_FORMATS)) - .order_by(db.Books.last_modified) - .order_by(db.Books.id) - ) - - if sync_token.books_last_id > -1: - changed_entries = changed_entries.filter(db.Books.id > sync_token.books_last_id) - only_kobo_shelves = ( - calibre_db.session.query(ub.Shelf) - .filter(ub.Shelf.user_id == current_user.id) - .filter(ub.Shelf.kobo_sync) - .count() - ) > 0 + calibre_db.session.query(ub.Shelf) + .filter(ub.Shelf.user_id == current_user.id) + .filter(ub.Shelf.kobo_sync) + .count() + ) > 0 if only_kobo_shelves: changed_entries = ( - changed_entries.join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) + calibre_db.session.query(db.Books, + ub.ArchivedBook.last_modified, + ub.BookShelf.date_added, + ub.ArchivedBook.is_archived) + .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) + .filter(or_(db.Books.last_modified > sync_token.books_last_modified, + ub.BookShelf.date_added > sync_token.books_last_modified)) + .filter(db.Data.format.in_(KOBO_FORMATS)) + .order_by(db.Books.id) + .order_by('last_modified') + .join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) .join(ub.Shelf) .filter(ub.Shelf.kobo_sync) .distinct() ) + else: + changed_entries = ( + calibre_db.session.query(db.Books, ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) + .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) + .filter(db.Books.last_modified > sync_token.books_last_modified) + .filter(db.Data.format.in_(KOBO_FORMATS)) + .order_by(db.Books.last_modified) + .order_by(db.Books.id) + ) + + if sync_token.books_last_id > -1: + changed_entries = changed_entries.filter(db.Books.id > sync_token.books_last_id) reading_states_in_new_entitlements = [] for book in changed_entries.limit(SYNC_ITEM_LIMIT): @@ -197,7 +207,14 @@ def HandleSyncRequest(): new_reading_state_last_modified = max(new_reading_state_last_modified, kobo_reading_state.last_modified) reading_states_in_new_entitlements.append(book.Books.id) - if book.Books.timestamp > sync_token.books_last_created: + ts_created = book.Books.timestamp + + try: + ts_created = max(ts_created, book.date_added) + except AttributeError: + pass + + if ts_created > sync_token.books_last_created: sync_results.append({"NewEntitlement": entitlement}) else: sync_results.append({"ChangedEntitlement": entitlement}) @@ -205,7 +222,14 @@ def HandleSyncRequest(): new_books_last_modified = max( book.Books.last_modified, new_books_last_modified ) - new_books_last_created = max(book.Books.timestamp, new_books_last_created) + try: + new_books_last_modified = max( + new_books_last_modified, book.date_added + ) + except AttributeError: + pass + + new_books_last_created = max(ts_created, new_books_last_created) max_change = (changed_entries .from_self() @@ -608,10 +632,10 @@ def HandleTagRemoveItem(tag_id): def sync_shelves(sync_token, sync_results, only_kobo_shelves=False): new_tags_last_modified = sync_token.tags_last_modified - for shelf in ub.session.query(ub.ShelfArchive).filter(func.datetime(ub.ShelfArchive.last_modified) > sync_token.tags_last_modified, - ub.ShelfArchive.user_id == current_user.id): - new_tags_last_modified = max(shelf.last_modified, new_tags_last_modified) - + for shelf in ub.session.query(ub.ShelfArchive).filter( + func.datetime(ub.ShelfArchive.last_modified) > sync_token.tags_last_modified, + ub.ShelfArchive.user_id == current_user.id + ): sync_results.append({ "DeletedTag": { "Tag": { @@ -638,11 +662,12 @@ def sync_shelves(sync_token, sync_results, only_kobo_shelves=False): }) extra_filters.append(ub.Shelf.kobo_sync) - for shelf in ub.session.query(ub.Shelf).filter( - func.datetime(ub.Shelf.last_modified) > sync_token.tags_last_modified, + for shelf in ub.session.query(ub.Shelf).join(ub.BookShelf).filter( + or_(func.datetime(ub.Shelf.last_modified) > sync_token.tags_last_modified, + ub.BookShelf.date_added > sync_token.tags_last_modified), ub.Shelf.user_id == current_user.id, *extra_filters - ): + ).distinct().order_by(func.datetime(ub.Shelf.last_modified).asc()): if not shelf_lib.check_shelf_view_permissions(shelf): continue From 24bbf226a14304db30c7ed95ec3567fdde3e3a59 Mon Sep 17 00:00:00 2001 From: alfred82santa Date: Sun, 14 Mar 2021 11:29:23 +0100 Subject: [PATCH 6/6] Sync reading state only for books on kobo shelves --- cps/kobo.py | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/cps/kobo.py b/cps/kobo.py index 141d745d..19122314 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -171,7 +171,7 @@ def HandleSyncRequest(): ub.BookShelf.date_added > sync_token.books_last_modified)) .filter(db.Data.format.in_(KOBO_FORMATS)) .order_by(db.Books.id) - .order_by('last_modified') + .order_by(ub.ArchivedBook.last_modified) .join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) .join(ub.Shelf) .filter(ub.Shelf.kobo_sync) @@ -253,11 +253,36 @@ def HandleSyncRequest(): books_last_id = -1 # generate reading state data + changed_reading_states = ub.session.query(ub.KoboReadingState) + + if only_kobo_shelves: + changed_reading_states = ( + changed_reading_states.join(ub.BookShelf, ub.KoboReadingState.book_id == ub.BookShelf.book_id) + .join(ub.Shelf) + .filter( + ub.Shelf.kobo_sync, + or_( + func.datetime(ub.KoboReadingState.last_modified) > sync_token.reading_state_last_modified, + ub.BookShelf.date_added > sync_token.books_last_modified + ) + ) + ).distinct() + + else: + changed_reading_states = ( + changed_reading_states.filter( + func.datetime(ub.KoboReadingState.last_modified) > sync_token.reading_state_last_modified + ) + ) changed_reading_states = ( - ub.session.query(ub.KoboReadingState) - .filter(and_(func.datetime(ub.KoboReadingState.last_modified) > sync_token.reading_state_last_modified, - ub.KoboReadingState.user_id == current_user.id, - ub.KoboReadingState.book_id.notin_(reading_states_in_new_entitlements)))) + changed_reading_states.filter( + and_( + ub.KoboReadingState.user_id == current_user.id, + ub.KoboReadingState.book_id.notin_(reading_states_in_new_entitlements) + ) + ) + ) + for kobo_reading_state in changed_reading_states.all(): book = calibre_db.session.query(db.Books).filter(db.Books.id == kobo_reading_state.book_id).one_or_none() if book: