Commit Graph

36 Commits

Author SHA1 Message Date
neon 4d453c82ca fix(books): measure audiobook durations when Book Dock files them
Book Dock finalize, which also files book requests, left each audio file's
duration empty until the next library scan. The player derives progress only
from those, so a filed audiobook stayed at 0% and never reached Continue
Listening. Finalize now measures them once metadata is applied.

Refs #1757
2026-10-12 03:44:40 +00:00
neon 995cc24cc5 fix(books): extract chapters from attached audiobooks
Preserve embedded chapters and total duration when audio joins an EPUB-primary book.

Fixes #1532
2026-09-26 05:52:29 +00:00
neon e28bd67fa3 feat(cover): give books with both media separate ebook and audiobook covers
Keep one cover slot per medium and show the one each surface needs: the
library's shape for the face, square art on audio screens, the ebook slot
for Kobo and OPDS. Legacy covers convert on upgrade or on first read, and a
write that names no slot keeps working for released iOS builds. Also read
the dev client origin from one constant.
2026-09-23 19:55:25 +00:00
neon 970b152529 fix(cover): rebuild book thumbnails that went missing beside a cover (#1482)
A cover refresh skipped thumbnail generation whenever the stored cover
source was custom, so re-extract reported success while /thumbnail kept
404ing. Generate the missing thumbnail from the custom cover, and repair
any other gap lazily on the first thumbnail request.

Fixes #1475
2026-09-21 14:15:14 -06:00
neon b0b21b2b78 fix(kobo): version cover ids from the cover, not the metadata row
Any write to book_metadata bumped updated_at and minted a fresh
CoverImageId, so a device holding that cover locally fell back to the
placeholder offline. Stamp cover_updated_at at each cover write instead;
migration 0080 backfills it from updated_at so no id churns on upgrade.

Also trims the DECIMAL(10,2) scale Booklore hands back for a series
index, which sorted 2.50 after 2.9. Closes #943.
2026-08-27 17:36:32 +00:00
neon 0c02795a1c fix(metadata): merge embedded chapters across every file of an audiobook
Extraction reads one file, and each file of a multi-file audiobook embeds
its own chapters starting at zero, so later files had no chapters and the
first file's last chapter ran to the end of the book. Scanning now probes
every audio file in playback order and offsets each file's chapters by the
files before it, rebuilding books whose stored list stops short.

Closes #1146
2026-08-25 21:45:16 +00:00
neon b264ef1132 fix(series): preserve exact series index labels
Treat series positions as validated string labels so values such as 5.10 retain their exact representation across storage, metadata providers, file formats, and clients.

Closes #1119
2026-08-24 21:40:41 +00:00
neon 6a441f4452 fix(metadata): read narrators from OPF and keep them for audiobooks
Creators and contributors with MARC role nrt now populate narrators, in both
EPUB2 opf:role and EPUB3 refines form. The audio-specific pass also stops being
skipped when a sidecar OPF outranks an audio winner, so chapters and narrators
survive an opfFile-first library, and it runs first so an OPF that names
narrators wins over the composer tag.

Closes #1081
2026-08-24 03:44:08 +00:00
neon 10152999d1 fix(kobo): render fixed-layout comics full screen on the device
Detect the OPF rendition:layout declaration and announce pre-paginated books
as EPUB3FL instead of KEPUB, which is what selects the device's fixed-layout
renderer. Kepub conversion is left alone so KoboSpan progress sync still works.
The flag is stored per file and backfilled during the sync reconcile pass, so
existing libraries converge without a rescan.

Closes #1044
2026-08-24 02:46:47 +00:00
neon 18d4d6cfc2 fix(server): match entity names that carry non-collapsed whitespace
Author, narrator, genre and tag names written before whitespace normalization existed can hold
a non-breaking space, tab, newline or doubled space. HTML collapses all of those, so the name
renders correctly in the UI while the ILIKE search predicate never matches it; unaccent() does
not touch whitespace either. Re-entering an identical name by hand fixed a single book because
the write path canonicalizes the row it reuses, but nothing ever ran for untouched books.

Collapse stored names to the form normalizeMetadataTextSql() produces, merging rows that collide
once collapsed and remapping every junction and content-filter reference before a duplicate is
dropped. Case variants are left alone, since search is already case-insensitive. Close the two
write paths that still produced un-collapsed names, and normalize the typed search term so a
pasted non-breaking space still matches.

Also carries staged client appearance work: the surface brightness picker and related controls.

Closes #1014
2026-08-16 01:55:34 +00:00
neon 563086328d feat(series): track expected series length and surface library completeness
Record how many books a series holds from Hardcover, ComicVine, RanobeDB,
Amazon and embedded ComicInfo metadata, storing it on the series row. Show
an ownership meter beside read progress on series detail, and extend gap
detection to report entries past the highest owned index instead of stopping
there. Allow the total to be set by hand in the book metadata editor.

Automated sources only ever raise the stored total so the result does not
depend on scan order; the manual field is the way to lower or clear it.

Closes #801
2026-08-03 00:54:26 +00:00
Gideon VanRiette 4baad41ed1 fix(metadata): extract and write back comicvine id for comics (#842)
* fix(metadata): extract and write back comicvine id for comics

ComicVine references were never read from a comic's embedded
ComicInfo.xml on import, even though every other provider id
(Goodreads, Amazon, Hardcover, Google Books, OpenLibrary, Kobo)
already round-trips through the same <Web>/Notes fields. This
affected Book Dock import, direct upload, and library scanning
alike, since they share the same extractor. Write-back had the
same gap: a comicvineId resolved via search/auto-fill was never
persisted back into the file.

Closes #840

* fix(metadata): keep comicvine id off the contested Web slot and source-check notes

ComicInfo has a single Web element and buildComicInfoXml writes the first
provider id in COMIC_INFO_PROVIDER_ID_KEYS order into it. The other six
providers are also in COMIC_INFO_MANAGED_NOTES_KEYS, so losing that slot costs
them nothing; comicvineId had no second channel, so a write-back for a book
that also carried a goodreads/amazon/hardcover/google/openlibrary/kobo id
dropped the id from the file entirely and clobbered any ComicVine URL that was
already there. Add comicvineId to the managed notes keys, which also makes the
existing managed-note read precedence reachable from our own writes.

ComicTagger emits "[Issue ID N]" for whichever talker produced the tag, naming
the source separately as "using info from <source>". Matching the bare marker
attributed Metron and other non-ComicVine issue ids to ComicVine and wrote them
back out as fabricated comicvine.gamespot.com URLs. Require the Comic Vine
source in the same sentence.

Also anchor the Web URL scan to a path segment so a segment ending in 4000-,
such as "14000-777", is no longer read as an issue id.

---------

Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-07-30 18:31:27 -06:00
neon 5290e63375 refactor(metadata): await metadata score calculations on metadata changes
Ensure metadata score calculations are awaited when book metadata or covers are saved or updated, and add concurrency queuing for on-demand score recalculations.
2026-07-27 06:13:54 +00:00
neon 06286d49b1 fix(metadata): persist hardcover and open library ids during book dock import
Pass external provider IDs (including Hardcover and Open Library IDs) from book dock metadata selection through ingest and finalization so they are saved to book metadata on import.

Closes #704
2026-07-16 05:45:36 +00:00
neon eac0917d22 fix(metadata): improve Libro.fm metadata integration
Persist Libro.fm identifiers across metadata refresh, editing, file round trips, and provider links. Enable explicitly selected audiobook providers during Auto-fill and retain AudNexus ASINs as Audible identifiers.
2026-07-12 07:06:42 +00:00
neon bc7f1f58bc fix(server): normalize and deduplicate narrator names
Narrator names and sort names are now normalized to remove duplicate
internal whitespace and leading/trailing spaces. Names are deduplicated
case-insensitively when saved to prevent duplicate metadata entries that
are visually identical or very similar in the UI.

Closes #553
2026-07-05 21:12:34 +00:00
neon 2af4895e69 feat(metadata): store and write hardcover edition IDs
Adds hardcoverEditionId to the database schema and shared types, enabling it to be stored as first-class metadata. Updates the file metadata parsers and writers (EPUB, PDF, CBZ) to read and embed this ID, and exposes it in the frontend metadata editor.

Closes #420
2026-06-25 18:55:22 +00:00
neon f1a7ba6070 fix(cover): refresh cached cover URLs
Update cover mutation paths to bump the book timestamp used for cover cache busting, and carry per-book collapsed-series cover versions so child covers do not reuse a representative book timestamp.
2026-06-20 20:52:43 +00:00
neon dc82774291 fix(scanner): populate per-file audio duration on upload
The upload paths saved only the aggregate book_metadata duration, leaving book_files.durationSeconds
null so the player summed to zero. Extract and aggregate per-file duration on new uploads and added
audio files, matching the scanner.

Ref #330
2026-06-14 22:50:01 +00:00
neon b1dff917ad feat(books): add jump rail navigation to book listings (#318)
Add server-backed jump buckets so large library, collection, and smart-scope listings can jump directly to sorted sections without loading every row up front.

Closes #163
2026-06-11 23:16:58 -06:00
neon efa300cecc fix(metadata): restore RanobeDB file metadata and links #207 #210
Preserve RanobeDB IDs through write-back, file import, and load-from-file so saved metadata survives round trips.

Expose saved RanobeDB sources in the book detail surfaces with the provider icon and database link.

Closes #207
Closes #210
2026-06-03 16:40:09 +00:00
Chris Mansell 06657a56a5 feat(books): write metadata directly to audiobook files (#219)
- Extend file write pipeline to write metadata fields directly into audiobook files.
- Map metadata fields to standard audio tag mappings and run ffmpeg to embed tags and cover art for M4B, M4A, MP3, and FLAC files.
- Update UI in edit metadata tab to show file write status and highlight written fields.

Handle edge cases in metadata extraction, file write-back status checks, and comic XML building. This ensures narrators are not incorrectly populated when they match the author/artist, preserves audibleId during chapter extraction, prevents whitespace issue numbers from breaking the XML, and improves the UI to clearly show why write-back is disabled.
2026-06-03 10:03:52 -06:00
neon 45f252a7e6 fix(metadata): extract metadata from sidecar opf files
Ensure .opf sidecar files are processed alongside book files during
library scans and their metadata is extracted properly.

Closes #200
2026-06-02 12:53:21 -06:00
neon 13a3ade043 feat: validate and normalize book published year to 1000-2200 range 2026-04-12 17:28:10 -06:00
neon e6186c09df test: add comprehensive unit tests and increase coverage thresholds 2026-04-10 09:26:37 -06:00
neon 02a0d711c3 chore: improve drizzle queries 2026-04-09 05:14:28 -06:00
neon 9f6b7d4f2b feat: enhance PDF metadata extraction and refactor book cover storage 2026-04-08 20:32:38 -06:00
neon bab3813ff8 feat(metadata): add per-field locking to protect fields from overwrites 2026-04-03 21:31:02 -06:00
neon 649dab6c34 fix(metadata): harden extraction, relation transactions, and cover 2026-04-01 06:18:20 -06:00
neon af9424f04a feat: add audiobook progress and refactor metadata extraction 2026-03-28 07:39:23 -06:00
neon ac7b896c6e feat(metadata): add ComicVine provider with shared relevance scoring 2026-03-23 13:19:08 -06:00
neon 2117b729d5 feat(reader): add audiobook reader with narrator and Audible metadata
- add audiobook reader with playback queue, progress tracking, and audio settings
- add narrator support with DB schema, module, and metadata extraction
- add Audible and Audnexus metadata providers with mappers and tests
- improve scanner with file classification, walk utilities, and file-event processing
- extend upload validator and processor for audio formats
2026-03-21 16:14:55 -06:00
neon 9adf7fc85b fix(metadata): enforce genre provider scope and update resolver tests 2026-03-18 12:04:20 -06:00
neon aa2456fbf8 feat(authors): add auto-enrichment queue, worker safety, and live status 2026-03-13 08:14:45 -06:00
neon c9221f92be feat(metadata): add configurable metadata score with filter support 2026-03-13 03:05:51 -06:00
neon b64aa519ef chore: migrate server tests from Jest to Vitest 2026-03-11 13:07:31 -06:00