🐳 Docker Image
Pull the Docker image:
docker pull ghcr.io/drallgood/audiobookshelf-hardcover-sync:v3.6.0Or use the latest tag for the most recent release:
docker pull ghcr.io/drallgood/audiobookshelf-hardcover-sync:latest🔍 Image Details
- Digest: ``
- Source: View on GitHub
Changelog
[v3.6.0] - 2026-09-01
Fixed
- 53 FINISHED Books Re-Synced Every Cycle (689 → 5 API calls): Root cause: a milliseconds-vs-seconds comparison in the second incremental check (
book.Progress.FinishedAtis in milliseconds from Audiobookshelf,bookState.LastUpdatedis in seconds fromtime.Now().Unix()).1778435826287 > 1788206781was alwaystrue, so every FINISHED book passed theactivityChangedgate on every cycle. Supporting fixes required:HandleFinishedBooknow stores100.0as state progress (not raw listening percentage like30.0) so the first incremental check's progress comparison matches correctly; thenothing to doearly-exit branch now setssuccess=trueso the deferredUpdateBook/SetHasProgressSecondsactually fires;HasProgressSecondspropagates to the base key even when no progress/status change occurs, auto-migrating existing state files. Books synced dropped from 53 to 1 (the single actively-listened book). Daily API calls dropped from ~25k to <10. (#167) - Books Processed UI showing wrong count / BooksTotal not visible:
GetSummary()created a copy of theSyncSummarystruct but forgot to include theBooksTotalfield — the copy always hadBooksTotal=0, so the status endpoint fell back toTotalBooksProcessedwhich counted up during sync. The UI summary fetch was overridingbooks_totalwithtotal_books_processed. Fixed theGetSummarycopy, bothlast_sync_summaryconstruction sites in the multiuser service, and the UI fetch logic.books_totalis now pre-counted from library items at sync start, so it shows345/345immediately. (#167) - HandleFinishedBook Read Insert Before Status: Swapped the order: insert/update reads first, then set status to FINISHED, then clean up blank reads. The old order triggered Hardcover to auto-create a blank finished read row, hiding the real read from the activity stream. (#167)
- Blank Read Accumulation Across Sync Cycles: Added shared
deleteBlankReadshelper and wired it into all four status-transition paths (IN_PROGRESS update/read, IN_PROGRESS create, COMPLETED, FINISHED). Reread transitions left auto-created blank reads with no progress/seconds/finished_at. (#167) - Rereads Stuck at READ (Update Path): The update path unconditionally skipped IN_PROGRESS status updates. Added
hcBook.BookStatusIDcheck: only skips when already IN_PROGRESS (2). (#167) - Stale User Book Cache (6h TTL) Blocking Transitions: Added
InvalidateByUserBook()after everyUpdateUserBookStatussuccess to prevent staleBookStatusID: 2from persisting across cycles. (#167) - Rate Limiter Backoff Compounding: Daily limit check used
r.rate * 4, compounding exponentially. Fixed withmax(DefaultRate*10, r.rate)andbackoffUntilguard. (#167) - Rate Limiter Thresholds Lowered: Daily backoff from 10%→1%, warning from 20%→5%. (#167)
Changed
- API Call Reduction in handleInProgressBook:
GetUserBookReadscalls reduced from 3 to 1 per book by fetching all reads once and reusing throughout the function. Removed second-chance fetch block. (#167) - IETF Rate Limit Headers: Parses new
RateLimit/RateLimit-Policyheaders, backward-compatible with legacyX-RateLimit-*. Daily limit tracking with automatic slowdown. (#167)