Skip to content

Audiobookshelf: send ebookLocation so ABS's reader resumes in place - #24

Merged
itsthisjustin merged 1 commit into
crosspoint-reader:mainfrom
jvanantwerp4507:abs-ebook-location
Oct 11, 2026
Merged

itsthisjustin merged 1 commit into
crosspoint-reader:mainfrom
jvanantwerp4507:abs-ebook-location

Conversation

@jvanantwerp4507

Copy link
Copy Markdown
Contributor

Audiobookshelf: send ebookLocation so ABS's reader resumes in place

Problem

After a sync, ABS shows the right percentage, but clicking Read opens the EPUB at page one. ABS's built-in reader resumes only from mediaProgress.ebookLocation, and only when that value is an epubcfi(...) (see client/components/readers/EpubReader.vue, savedEbookLocation). The connector sent only progress, plus currentTime/duration for audiobooks.

Change

Push (device → ABS)

  • Resolve the device's KOReader XPath against the item's own EPUB (GET /api/items/:id/ebook) using the existing epubPosition helper, and send ebookLocation (CFI) and ebookProgress alongside the existing fields. ABS applies these directly through MediaProgress.applyProgressUpdate → this.set(payload).
  • Store the EPUB map per book with withEpubMap, as the BookOrbit connector does, so each book is downloaded once.
  • Remember items with no EPUB (404/400) for an hour, so audio-only books don't trigger an extra request on every push.
  • If the EPUB or position can't be resolved, still save the percentage, exactly as before.

Pull (ABS → device)

  • For ebook-only items (no audio duration), read ebookProgress instead of progress, and map ebookLocation back to an exact XPath with epubXPath, so reading in ABS's web reader syncs back to the device. Previously these changes were never picked up.
  • Items with audio keep the listening position unchanged (the audiobook ↔ ebook sync).

Tests

New test/audiobookshelf-ebook.test.ts (9 tests):

  • XPath → CFI on push, with a round-trip back to the same XPath
  • audio-only items: progress still saved, and the missing EPUB is requested only once
  • no XPath sent, an unresolvable XPath, and finishing a book
  • pull: ebook-only CFI → XPath, audio items unchanged, and an unplaceable CFI falls back to the percentage

Full suite passes: 39 files, 584 tests.

Tested live

Xteink X4 running CrossPoint → self-hosted crosspoint-sync → Audiobookshelf v2.37.1 behind SWAG. After Upload Local on the device, Read in ABS opens on the page being read.

🤖 Generated with Claude Code

ABS's built-in EPUB reader resumes only from mediaProgress.ebookLocation
(an epubcfi), so after a sync "Read" always opened at page one even though
the progress percentage was correct.

Push: resolve the device's KOReader XPath against the item's EPUB
(GET /api/items/:id/ebook) with the existing epubPosition helper and send
ebookLocation + ebookProgress alongside progress/currentTime. The EPUB map
is stored per book via withEpubMap, items with no EPUB are remembered for
an hour so audio-only books don't trigger a lookup on every push, and any
failure still lands the percentage.

Pull: for ebook-only items (no audio duration), read ebookProgress instead
of progress and map ebookLocation back to an exact XPath with epubXPath, so
reading in ABS's web reader syncs to the device. Items with audio keep the
listening position as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VSu9p45TgStCPnzV4mSRYc
@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0e62ff80-9d5d-4763-b286-5d0b48953883

📥 Commits

Reviewing files that changed from the base of the PR and between 4cc7cd0 and 360c015.


📒 Files selected for processing (2)
  • src/connectors/audiobookshelf.ts
  • test/audiobookshelf-ebook.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📜 Recent review details
🔇 Additional comments (2)
test/audiobookshelf-ebook.test.ts (1)

1-172: LGTM!


src/connectors/audiobookshelf.ts (1)

276-277: 🎯 Functional Correctness

Audiobookshelf v2.37.1 does not define a numeric default for ebookProgress. Its update method assigns fields supplied by the client and does not assign omitted fields. Therefore, the earlier connector and clients that omit ebookProgress do not establish ebookProgress: 0. An explicitly supplied zero can be a valid start position, so the proposed fallback could discard intentional progress.



📝 Walkthrough

Walkthrough

Audiobookshelf progress sync now supports EPUB positions. Pushes include ebook progress and, when an unfinished event has a resolvable XPath position, an EPUB CFI. Pulls map ebook CFIs to XPath positions when possible.

Changes

Audiobookshelf EPUB Position Sync

Layer / File(s) Summary
EPUB resolution and push integration
src/connectors/audiobookshelf.ts, test/audiobookshelf-ebook.test.ts
The connector resolves unfinished-event XPath positions against the item EPUB and sends a resolved CFI with ebookProgress. Responses with status 400 or 404 are cached as no-EPUB results for one hour. Tests cover successful resolution, missing EPUBs, and omitted locations.
Pull ebook progress
src/connectors/audiobookshelf.ts, test/audiobookshelf-ebook.test.ts
For items without audio, the connector reads ebookProgress and maps a valid CFI to an XPath unless the item is known to lack an EPUB. Audio-backed items continue to use listening progress. Tests cover mapped positions and fallback progress when a CFI cannot be placed.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Connector as Audiobookshelf connector
  participant Helpers as EPUB position helpers
  participant API as Audiobookshelf API
  Connector->>Helpers: Resolve XPath against item EPUB
  Helpers->>API: Fetch item EPUB
  API-->>Helpers: Return EPUB data
  Helpers-->>Connector: Return resolved CFI
  Connector->>API: PATCH ebookProgress and resolved ebookLocation
Loading

Suggested reviewers: itsthisjustin


Merge Risk: ⚪ Minimal · up to 360c0

The change adds EPUB position sync to Audiobookshelf, with fallback to percentage-only progress when an EPUB or position cannot be resolved. No concrete merge-blocking risk was identified.

Pre-merge checks | Passed 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary change: sending Audiobookshelf ebookLocation so the reader resumes at the correct position.
Description check Passed The description directly explains the push and pull EPUB synchronization changes, fallback behavior, tests, and live validation.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@itsthisjustin
itsthisjustin merged commit a55b5c2 into crosspoint-reader:main Oct 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants