3333from sqlalchemy import func
3434from sqlalchemy .sql .expression import and_ , or_
3535from sqlalchemy .exc import StatementError
36+ from sqlalchemy .orm import joinedload
3637from sqlalchemy .sql import select
3738import requests
3839
@@ -232,14 +233,20 @@ def HandleSyncRequest():
232233
233234 log .debug ("Kobo Sync: books last modified: {}" .format (sync_token .books_last_modified ))
234235
236+ rstate_join = and_ (
237+ db .Books .id == ub .KoboReadingState .book_id ,
238+ ub .KoboReadingState .user_id == current_user .id ,
239+ )
235240 if only_kobo_shelves :
236241 changed_entries = calibre_db .session .query (db .Books ,
237242 ub .ArchivedBook .last_modified ,
238243 ub .BookShelf .date_added ,
239- ub .ArchivedBook .is_archived )
244+ ub .ArchivedBook .is_archived ,
245+ ub .KoboReadingState )
240246 changed_entries = (changed_entries
241247 .join (db .Data ).outerjoin (ub .ArchivedBook , and_ (db .Books .id == ub .ArchivedBook .book_id ,
242248 ub .ArchivedBook .user_id == current_user .id ))
249+ .outerjoin (ub .KoboReadingState , rstate_join )
243250 .filter (db .Books .id .notin_ (calibre_db .session .query (ub .KoboSyncedBooks .book_id )
244251 .filter (ub .KoboSyncedBooks .user_id == current_user .id )))
245252 .filter (or_ (
@@ -257,37 +264,50 @@ def HandleSyncRequest():
257264 and_ (ub .Shelf .user_id == current_user .id , ub .Shelf .kobo_sync == True ),
258265 db .Books .id .in_ (magic_shelf_book_ids ) if magic_shelf_book_ids else False
259266 ))
267+ .options (joinedload (db .Books .authors ),
268+ joinedload (db .Books .publishers ),
269+ joinedload (db .Books .series ),
270+ joinedload (db .Books .languages ),
271+ joinedload (db .Books .comments ),
272+ joinedload (db .Books .data ))
260273 .distinct ())
261274 else :
262275 changed_entries = calibre_db .session .query (db .Books ,
263276 ub .ArchivedBook .last_modified ,
264- ub .ArchivedBook .is_archived )
277+ ub .ArchivedBook .is_archived ,
278+ ub .KoboReadingState )
265279 changed_entries = (changed_entries
266280 .join (db .Data ).outerjoin (ub .ArchivedBook , and_ (db .Books .id == ub .ArchivedBook .book_id ,
267281 ub .ArchivedBook .user_id == current_user .id ))
282+ .outerjoin (ub .KoboReadingState , rstate_join )
268283 .filter (db .Books .id .notin_ (calibre_db .session .query (ub .KoboSyncedBooks .book_id )
269284 .filter (ub .KoboSyncedBooks .user_id == current_user .id )))
270285 .filter (calibre_db .common_filters (allow_show_archived = True ))
271286 .filter (db .Data .format .in_ (KOBO_FORMATS ))
272287 .order_by (db .Books .last_modified )
273- .order_by (db .Books .id ))
288+ .order_by (db .Books .id )
289+ .options (joinedload (db .Books .authors ),
290+ joinedload (db .Books .publishers ),
291+ joinedload (db .Books .series ),
292+ joinedload (db .Books .languages ),
293+ joinedload (db .Books .comments ),
294+ joinedload (db .Books .data )))
274295 log .debug ("Kobo Sync: changed entries: {}" .format (changed_entries .count ()))
275296
276297 reading_states_in_new_entitlements = []
277298 books = changed_entries .limit (SYNC_ITEM_LIMIT )
278299 log .debug ("Kobo Sync: selected to sync: {}" .format (len (books .all ())))
279300 for book in books :
280301 formats = [data .format for data in book .Books .data ]
281- if 'KEPUB' not in formats and config .config_kepubifypath and 'EPUB' in formats :
282- helper .convert_book_format (book .Books .id , config .get_book_path (), 'EPUB' , 'KEPUB' , current_user .name )
283302
284- kobo_reading_state = get_or_create_reading_state ( book .Books . id )
303+ kobo_reading_state = book .KoboReadingState # None when no record exists yet
285304 entitlement = {
286305 "BookEntitlement" : create_book_entitlement (book .Books , archived = (book .is_archived == True )),
287306 "BookMetadata" : get_metadata (book .Books ),
288307 }
289308
290- if kobo_reading_state .last_modified > sync_token .reading_state_last_modified :
309+ if (kobo_reading_state is not None
310+ and kobo_reading_state .last_modified > sync_token .reading_state_last_modified ):
291311 entitlement ["ReadingState" ] = get_kobo_reading_state_response (book .Books , kobo_reading_state )
292312 new_reading_state_last_modified = max (new_reading_state_last_modified , kobo_reading_state .last_modified )
293313 reading_states_in_new_entitlements .append (book .Books .id )
@@ -581,28 +601,32 @@ def _get_cover_image_id(book):
581601
582602def get_metadata (book ):
583603 download_urls = []
584- kepub = [data for data in book .data if data .format == 'KEPUB' ]
585604
586- for book_data in kepub if len (kepub ) > 0 else book .data :
587- if book_data .format not in KOBO_FORMATS :
588- continue
589- for kobo_format in KOBO_FORMATS [book_data .format ]:
590- # log.debug('Id: %s, Format: %s' % (book.id, kobo_format))
591- try :
592- if get_epub_layout (book , book_data ) == 'pre-paginated' :
593- kobo_format = 'EPUB3FL'
594- download_urls .append (
595- {
596- "Format" : kobo_format ,
597- "Size" : book_data .uncompressed_size ,
598- "Url" : get_download_url_for_book (book .id , book_data .format ),
599- # The Kobo forma accepts platforms: (Generic, Android)
600- "Platform" : "Generic" ,
601- # "DrmType": "None", # Not required
602- }
603- )
604- except (zipfile .BadZipfile , FileNotFoundError ) as e :
605- log .error (e )
605+ kepub_data = next ((d for d in book .data if d .format == 'KEPUB' ), None )
606+ epub_data = next ((d for d in book .data if d .format == 'EPUB' ), None )
607+
608+ if kepub_data :
609+ book_data , dl_format , published_format = kepub_data , 'kepub' , 'KEPUB'
610+ elif epub_data and config .config_kepubifypath :
611+ book_data , dl_format , published_format = epub_data , 'kepub' , 'KEPUB'
612+ elif epub_data :
613+ book_data , dl_format , published_format = epub_data , 'epub' , 'EPUB3'
614+ else :
615+ book_data = None
616+
617+ if book_data :
618+ try :
619+ if get_epub_layout (book , book_data ) == 'pre-paginated' :
620+ published_format = 'EPUB3FL'
621+ except (zipfile .BadZipfile , FileNotFoundError ) as e :
622+ log .error (e )
623+ download_urls .append ({
624+ "Format" : published_format ,
625+ "Size" : book_data .uncompressed_size ,
626+ "Url" : get_download_url_for_book (book .id , dl_format ),
627+ "Platform" : "Generic" ,
628+ "DrmType" : "None" ,
629+ })
606630
607631 book_uuid = book .uuid
608632 cover_image_id = _get_cover_image_id (book )
@@ -634,11 +658,12 @@ def get_metadata(book):
634658 }
635659 metadata .update (get_author (book ))
636660
637- if get_series (book ):
638- name = get_series (book )
661+ series_name = get_series (book )
662+ if series_name :
663+ name = series_name
639664 try :
640665 metadata ["Series" ] = {
641- "Name" : get_series ( book ) ,
666+ "Name" : series_name ,
642667 "Number" : get_seriesindex (book ), # ToDo Check int() ?
643668 "NumberFloat" : float (get_seriesindex (book )),
644669 # Get a deterministic id based on the series name.
@@ -1044,8 +1069,10 @@ def get_ub_read_status(kobo_read_status):
10441069
10451070
10461071def get_or_create_reading_state (book_id ):
1047- book_read = ub .session .query (ub .ReadBook ).filter (ub .ReadBook .book_id == book_id ,
1048- ub .ReadBook .user_id == int (current_user .id )).one_or_none ()
1072+ book_read = ub .session .query (ub .ReadBook ).filter (
1073+ ub .ReadBook .book_id == book_id ,
1074+ ub .ReadBook .user_id == int (current_user .id ),
1075+ ).one_or_none ()
10491076 if not book_read :
10501077 book_read = ub .ReadBook (user_id = current_user .id , book_id = book_id )
10511078 if not book_read .kobo_reading_state :
@@ -1123,7 +1150,7 @@ def HandleCoverImageRequest(book_uuid, width, height, Quality, isGreyscale):
11231150 else :
11241151 resolution = COVER_THUMBNAIL_SMALL
11251152 except ValueError :
1126- log .error ("Requested height %s of book %s is invalid" % (book_uuid , height ))
1153+ log .error ("Requested height %s of book %s is invalid" % (height , book_uuid ))
11271154 resolution = COVER_THUMBNAIL_SMALL
11281155 book_cover = helper .get_book_cover_with_uuid (book_uuid , resolution = resolution )
11291156 if book_cover :
0 commit comments