Skip to content

Commit df6c417

Browse files
committed
Bugfix: fix some issues with kobo sync
Kobo sync's logic is incorrect, and looks like it pretty much always has been. This is seen on initial sync of a freshly reset device against c-w configured to sync all shelves. I have 1500+ books to sync, but c-w syncs only about 250 or so before saying it's done. That's two full batches of 100, followed by a partial batch. The problem is in the way the query performs paging. On the first pass it discovers all the books that need to be synced. On the second pass it does pretty well. Third pass, it does badly. All this is because of the way it currently detects which books have been modified since last sync. As it goes through the sync, this query result set gets progressively smaller, incorrectly. I've tried to repair the logic, and what I get now works perfectly for my case. I'm not 100% sure it's exactly right but it's doing a lot better now for both initial sync and maintenance sync.
1 parent 4e67a56 commit df6c417

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

cps/kobo.py

+21-14
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,20 @@ def HandleSyncRequest():
146146
if not current_user.role_download():
147147
log.info("Users need download permissions for syncing library to Kobo reader")
148148
return abort(403)
149+
149150
sync_token = SyncToken.SyncToken.from_headers(request.headers)
150151
log.info("Kobo library sync request received")
151152
log.debug("SyncToken: {}".format(sync_token))
152153
log.debug("Download link format {}".format(get_download_url_for_book('[bookid]', '[bookformat]')))
153154
if not current_app.wsgi_app.is_proxied:
154155
log.debug('Kobo: Received unproxied request, changed request port to external server port')
155156

157+
# Produce an equivalent curl command to assist with debugging
158+
#curl = f"curl -X{request.method} '{request.url}'"
159+
#for key, value in request.headers.items():
160+
# curl += f" -H'{key}: {value}'"
161+
#log.debug(f"curl: {curl}")
162+
156163
# if no books synced don't respect sync_token
157164
if not ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.user_id == current_user.id).count():
158165
sync_token.books_last_modified = datetime.min
@@ -172,6 +179,8 @@ def HandleSyncRequest():
172179

173180
only_kobo_shelves = current_user.kobo_only_shelves_sync
174181

182+
log.debug("Kobo Sync: books last modified: {}".format(sync_token.books_last_modified))
183+
175184
if only_kobo_shelves:
176185
changed_entries = calibre_db.session.query(db.Books,
177186
ub.ArchivedBook.last_modified,
@@ -182,11 +191,14 @@ def HandleSyncRequest():
182191
ub.ArchivedBook.user_id == current_user.id))
183192
.filter(db.Books.id.notin_(calibre_db.session.query(ub.KoboSyncedBooks.book_id)
184193
.filter(ub.KoboSyncedBooks.user_id == current_user.id)))
185-
.filter(ub.BookShelf.date_added > sync_token.books_last_modified)
194+
.filter(or_(
195+
ub.BookShelf.date_added > sync_token.books_last_modified,
196+
db.Books.last_modified > sync_token.books_last_modified,
197+
))
186198
.filter(db.Data.format.in_(KOBO_FORMATS))
187199
.filter(calibre_db.common_filters(allow_show_archived=True))
200+
.order_by(db.Books.last_modified)
188201
.order_by(db.Books.id)
189-
.order_by(ub.ArchivedBook.last_modified)
190202
.join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id)
191203
.join(ub.Shelf)
192204
.filter(ub.Shelf.user_id == current_user.id)
@@ -205,10 +217,11 @@ def HandleSyncRequest():
205217
.filter(db.Data.format.in_(KOBO_FORMATS))
206218
.order_by(db.Books.last_modified)
207219
.order_by(db.Books.id))
220+
log.debug("Kobo Sync: changed entries: {}".format(changed_entries.count()))
208221

209222
reading_states_in_new_entitlements = []
210223
books = changed_entries.limit(SYNC_ITEM_LIMIT)
211-
log.debug("Books to Sync: {}".format(len(books.all())))
224+
log.debug("Kobo Sync: selected to sync: {}".format(len(books.all())))
212225
for book in books:
213226
formats = [data.format for data in book.Books.data]
214227
if 'KEPUB' not in formats and config.config_kepubifypath and 'EPUB' in formats:
@@ -240,12 +253,6 @@ def HandleSyncRequest():
240253
new_books_last_modified = max(
241254
book.Books.last_modified.replace(tzinfo=None), new_books_last_modified
242255
)
243-
try:
244-
new_books_last_modified = max(
245-
new_books_last_modified, book.date_added
246-
)
247-
except AttributeError:
248-
pass
249256

250257
new_books_last_created = max(ts_created, new_books_last_created)
251258
kobo_sync_status.add_synced_books(book.Books.id)
@@ -262,20 +269,19 @@ def HandleSyncRequest():
262269
book_count = changed_entries.count()
263270
# last entry:
264271
cont_sync = bool(book_count)
265-
log.debug("Remaining books to Sync: {}".format(book_count))
272+
log.debug("Kobo Sync: remaining books to sync: {}".format(book_count))
266273
# generate reading state data
267274
changed_reading_states = ub.session.query(ub.KoboReadingState)
268275

276+
log.debug("Kobo Sync: rstate last modified: {}".format(sync_token.reading_state_last_modified))
269277
if only_kobo_shelves:
270278
changed_reading_states = changed_reading_states.join(ub.BookShelf,
271279
ub.KoboReadingState.book_id == ub.BookShelf.book_id)\
272280
.join(ub.Shelf)\
273281
.filter(current_user.id == ub.Shelf.user_id)\
274282
.filter(ub.Shelf.kobo_sync,
275-
or_(
276-
ub.KoboReadingState.last_modified > sync_token.reading_state_last_modified,
277-
func.datetime(ub.BookShelf.date_added) > sync_token.books_last_modified
278-
)).distinct()
283+
ub.KoboReadingState.last_modified > sync_token.reading_state_last_modified)\
284+
.distinct()
279285
else:
280286
changed_reading_states = changed_reading_states.filter(
281287
ub.KoboReadingState.last_modified > sync_token.reading_state_last_modified)
@@ -284,6 +290,7 @@ def HandleSyncRequest():
284290
and_(ub.KoboReadingState.user_id == current_user.id,
285291
ub.KoboReadingState.book_id.notin_(reading_states_in_new_entitlements)))\
286292
.order_by(ub.KoboReadingState.last_modified)
293+
log.debug("Kobo Sync: changed states: {}".format(changed_reading_states.count()))
287294
cont_sync |= bool(changed_reading_states.count() > SYNC_ITEM_LIMIT)
288295
for kobo_reading_state in changed_reading_states.limit(SYNC_ITEM_LIMIT).all():
289296
book = calibre_db.session.query(db.Books).filter(db.Books.id == kobo_reading_state.book_id).one_or_none()

0 commit comments

Comments
 (0)