Detail page:
- collapse Chapters section behind header toggle (73-chapter pages no
longer push content below the fold)
- square cover frames throughout (audiobook covers are Audible-style 1:1,
not 2:3 book portrait)
- narrator picker dropdown when multiple narrations of the same book exist
- clickable genre badges (route to /audiobooks?genre=X)
- reordered so credits/rails sit above the chapter list
- Play-from-Start button forces remount via playToken counter (was a
no-op when player was already at position 0)
- regression test for the Play-from-Start fix
Mini bar / Now Listening:
- mini bar respects --app-sidebar-offset so it stops getting covered by
the desktop sidebar
- Now Listening adds overflow scroll + a labeled "Back to player" button
so controls are never inaccessible on short viewports
Library page:
- infinite scroll (replaces Previous/Next pagination)
- genre filter chip with X-to-clear
Scanner:
- 8-worker parallel reconcile (env SILO_AUDIOBOOK_SCAN_WORKERS to override)
- file-path-first dedup so cleaned titles don't collapse separate
narrations
- title cleanup at write time (strips "Read by X" / "(unabridged)"
suffixes; original tag preserved in original_title)
- audiobook_series upsert from tag-derived series_name/series_position
- secondary dedup check (author + narrator + year + duration ±0.5% +
title-prefix) so two folders of the same book attach to one row
Backend detail handler:
- new fetchAlsoByAuthor, fetchInSeries (with series row > 1 entry guard),
fetchSimilar (embedding-first with shared-genre fallback),
fetchOtherNarrations (regex-strips narrator suffix to group siblings)
- audiobookDetailResponse gained also_by_author, in_series,
similar_audiobooks, other_narrations fields
- list endpoint accepts a genre query param
Embeddings:
- BuildEmbeddingText branches on item.Type == "audiobook" to use
author/narrator credits instead of cast/director/writer
- mediaTypeLabel helper centralizes movie / "TV series" / audiobook
- ListEmbeddingTextCandidates SQL mirrors the Go branching exactly
- ItemsNeedingEmbedding and TotalMediaItemCount loosen status='matched'
gate to also include audiobooks (which don't go through TMDB match)
- FindSimilar gains a mediaType filter so cross-type results never appear
- callers in similar.go and personal.go pass the source item's type
Collections:
- MediaAudiobook MediaKind + audiobook(s) case in templateEligibleForLibrary
(stops offering broken movie/TV templates to audiobook libraries)
- useAddItemToCollection hook (user + admin/library endpoints)
- AddToCollectionDialog wired into audiobook detail and movie/series
ActionBar overflow menu
- ManualCollectionItemsEditor gained a search-and-add panel with
debounced live results
- QueryDefinition.media_scope, QuerySortRelevanceScope, ALL_MEDIA_SCOPES
extended to include "audiobook"
- CatalogFilterBar gained an Audiobooks media scope option
- parseCatalogMediaScope (backend) accepts "audiobook"
Migrations:
- 145_audiobook_series: per-book series_name/series_index with a
best-effort title-pattern backfill for the existing corpus
- 146_audiobook_title_cleanup: strips narrator suffix / (unabridged)
noise from existing titles, preserving raw in original_title
Scripts:
- scripts/dedup_audiobooks.py: one-shot merge for "Title" vs
"Title: Subtitle" duplicates, file-path-stable, dry-run by default
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Third feature-detected rail on the detail page. When the backend
returns similar_audiobooks (server-side embedding similarity, ranked
top-N), the rail mounts above Also-by-author and In-series, with the
subtitle 'Based on listening patterns' to give the recommendation
source a little provenance. Frontend has no embedding logic — purely a
display path that lights up the moment the API exposes the field.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Frontend gains a feature-detected display path for two relationship
rails. Detail responses may now carry also_by_author and in_series.
When present, the detail page mounts Also-by-author followed by
In-series, with the current book highlighted inside the series strip.
When the backend omits them — which is the case today — the rails are
not rendered, so this lands as zero visible change until the backend
ships the data.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundles 21 in-progress files spanning scanner, image cache, ABS API
handlers, podcast/audiobook scan, cover enrichment, metadata sync
task, and an interim pass at the audiobook detail page (DetailHero
adoption + fixed-bottom player). Committed as a single baseline so
the upcoming UI redesign (per the 2026-05-24 plan) starts from a
clean working tree. Not split into logical commits because this
captures pre-existing local work, not a curated change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add request domain, repository, service, and reconcile task
- Add Radarr/Sonarr fulfillment adapters and TMDB discovery
- Expose user and admin request APIs with quota and approval rules
- Add web UI for browsing, requesting, and admin queue management
- Migration 139 introduces media_requests and related tables
TypeScript types match the JSON shapes from the new
/api/v1/audiobooks endpoints (list, detail, progress). Three hooks:
useAudiobookLibrary (list), useAudiobook (detail), and
useReportAudiobookProgress (mutation that invalidates the detail
query on success so progress updates reflect immediately).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Wire introdb marker fetching into playback and Jellyfin compat
- Persist and expose recap/preview markers alongside intro and credits
- Add new playback/profile settings for recap and preview behavior
- Wire introdb marker fetching into playback and Jellyfin compat
- Persist and expose recap/preview markers alongside intro and credits
- Add new playback/profile settings for recap and preview behavior
- Add admin job support for collection defaults applies
- Keep preview synchronous while real applies run via the job queue
- Show collection apply job status in the admin UI
- Add admin job support for collection defaults applies
- Keep preview synchronous while real applies run via the job queue
- Show collection apply job status in the admin UI