diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1071cdf..e80348d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -12,7 +12,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors # Upstream Contributors (janeczku/calibre-web) - OzzieIsaacs (anon) (2794 commits) -- Ozzie Isaacs (anon) (269 commits) +- Ozzie Isaacs (anon) (272 commits) - cbartondock (96 commits) - idalin (69 commits) - cervinko (68 commits) @@ -38,10 +38,10 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors - kyos (anon) (18 commits) - quarz12 (18 commits) - Thore Schillmann (anon) (18 commits) +- webysther (16 commits) - mapi68 (15 commits) - ok11 (13 commits) - pwr (13 commits) -- webysther (13 commits) - Kyosfonica (11 commits) - otapi (11 commits) - andy29485 (10 commits) @@ -281,6 +281,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors - robochud (1 commits) - ruben-herold (1 commits) - ryanlong1004 (1 commits) +- sakuyamaij (1 commits) - sartoshi-foot-dao (1 commits) - schnabelewobski (1 commits) - shsm0520 (1 commits) @@ -315,7 +316,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors - zhiyue (1 commits) # Fork Contributors (crocodilestick/calibre-web-automated) -- crocodilestick (1045 commits) +- crocodilestick (1047 commits) - jmarmstrong1207 (73 commits) - demitrix (30 commits) - sirwolfgang (29 commits) @@ -335,6 +336,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors - Calychas (3 commits) - ceruleandeep (anon) (3 commits) - deadbone (3 commits) +- github-actions[bot] (3 commits) - PulsarFTW (3 commits) - stewie83 (3 commits) - zikasak (3 commits) @@ -344,7 +346,6 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors - coissac (2 commits) - doxxx (2 commits) - FennyFatal (2 commits) -- github-actions[bot] (2 commits) - itsmarcy (2 commits) - JamesRy96 (2 commits) - Olen (2 commits) diff --git a/cps/kobo.py b/cps/kobo.py index 514a67c..e421633 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -126,6 +126,28 @@ def convert_to_kobo_timestamp_string(timestamp): return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") +def get_magic_shelf_book_ids_for_kobo(user_id): + if not config.config_kobo_sync_magic_shelves: + return set() + + magic_shelves = ub.session.query(ub.MagicShelf).filter_by(user_id=user_id, kobo_sync=True).all() + if not magic_shelves: + return set() + + book_ids = set() + for shelf in magic_shelves: + books, _ = magic_shelf.get_books_for_magic_shelf( + shelf.id, page=1, page_size=None + ) + for book in books: + book_ids.add(book.id) + + if book_ids: + log.debug("Kobo Sync: magic shelf allowed books: %s", len(book_ids)) + + return book_ids + + @kobo.route("/v1/library/sync") @requires_kobo_auth # @download_required @@ -158,7 +180,9 @@ def HandleSyncRequest(): # Two-Way-Sync Deletion Logic + magic_shelf_book_ids = set() if current_user.kobo_only_shelves_sync: + magic_shelf_book_ids = get_magic_shelf_book_ids_for_kobo(current_user.id) try: # Check all books that are on Kobo according to the database synced_books_query = ub.session.query(ub.KoboSyncedBooks.book_id).filter(ub.KoboSyncedBooks.user_id == current_user.id) @@ -169,6 +193,8 @@ def HandleSyncRequest(): .join(ub.Shelf, ub.BookShelf.shelf == ub.Shelf.id) .filter(ub.Shelf.user_id == current_user.id, ub.Shelf.kobo_sync == True)) allowed_book_ids = {item.book_id for item in allowed_books_query} + if magic_shelf_book_ids: + allowed_book_ids |= magic_shelf_book_ids # Spot the difference: books that need to be deleted books_to_delete_ids = synced_book_ids - allowed_book_ids @@ -213,18 +239,21 @@ def HandleSyncRequest(): ub.ArchivedBook.user_id == current_user.id)) .filter(db.Books.id.notin_(calibre_db.session.query(ub.KoboSyncedBooks.book_id) .filter(ub.KoboSyncedBooks.user_id == current_user.id))) - .filter(or_( - ub.BookShelf.date_added > sync_token.books_last_modified, - db.Books.last_modified > sync_token.books_last_modified, - )) + .filter(or_( + ub.BookShelf.date_added > sync_token.books_last_modified, + db.Books.last_modified > sync_token.books_last_modified, + db.Books.id.in_(magic_shelf_book_ids) if magic_shelf_book_ids else False + )) .filter(db.Data.format.in_(KOBO_FORMATS)) .filter(calibre_db.common_filters(allow_show_archived=True)) .order_by(db.Books.last_modified) .order_by(db.Books.id) - .join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) - .join(ub.Shelf) - .filter(ub.Shelf.user_id == current_user.id) - .filter(ub.Shelf.kobo_sync) + .outerjoin(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) + .outerjoin(ub.Shelf, ub.Shelf.id == ub.BookShelf.shelf) + .filter(or_( + and_(ub.Shelf.user_id == current_user.id, ub.Shelf.kobo_sync == True), + db.Books.id.in_(magic_shelf_book_ids) if magic_shelf_book_ids else False + )) .distinct()) else: changed_entries = calibre_db.session.query(db.Books, @@ -297,12 +326,14 @@ def HandleSyncRequest(): log.debug("Kobo Sync: rstate last modified: {}".format(sync_token.reading_state_last_modified)) 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(current_user.id == ub.Shelf.user_id)\ - .filter(ub.Shelf.kobo_sync, - ub.KoboReadingState.last_modified > sync_token.reading_state_last_modified)\ + changed_reading_states = changed_reading_states.outerjoin(ub.BookShelf, + ub.KoboReadingState.book_id == ub.BookShelf.book_id)\ + .outerjoin(ub.Shelf, ub.Shelf.id == ub.BookShelf.shelf)\ + .filter(ub.KoboReadingState.last_modified > sync_token.reading_state_last_modified)\ + .filter(or_( + and_(current_user.id == ub.Shelf.user_id, ub.Shelf.kobo_sync == True), + ub.KoboReadingState.book_id.in_(magic_shelf_book_ids) if magic_shelf_book_ids else False + ))\ .distinct() else: changed_reading_states = changed_reading_states.filter( diff --git a/messages.pot b/messages.pot index 61854de..9ab30a3 100644 --- a/messages.pot +++ b/messages.pot @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: Calibre-Web Automated v4.0.2\n" "Report-Msgid-Bugs-To: https://github.com/crocodilestick/Calibre-Web-" "Automated\n" -"POT-Creation-Date: 2026-01-31 12:15+0100\n" +"POT-Creation-Date: 2026-01-31 13:02+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n"