fix(library-import): keep every series membership, not just the first - #847
Open
m4bard wants to merge 2 commits into
Open
fix(library-import): keep every series membership, not just the first#847m4bard wants to merge 2 commits into
m4bard wants to merge 2 commits into
Conversation
matchToMetadata collapsed a search result's series array to its first entry and sent only the legacy scalar series/seriesNumber. AudibleBookMetadata already carries SeriesMemberships, and /library/add applies it via AudiobookSeriesMembershipHelper.ApplyToAudiobook, falling back to the single scalar only when no memberships are supplied. So a book in more than one series lost every membership after the first on this path, while the Add New path (AddLibraryModal) preserved them. Build one membership per series entry, ordered, with the first marked primary. The scalar fields stay populated from the primary so nothing downstream changes. The search endpoint's fallback branch fills a series entry's asin with the series name when it cannot re-fetch the book by ASIN. That value used to be discarded because AudibleBookMetadata has no top-level SeriesAsin; a membership would persist it, so only a value shaped like an ASIN is kept.
…ct and fix the unmatched-files mapping Three callers were each doing their own version of the same translation, so they disagreed about what a series is. The walk now lives once in buildSeriesFields, which returns the memberships and the legacy series, seriesNumber and seriesAsin taken off the primary membership, so those can no longer drift apart. matchToMetadata uses it in place of its inline copy, and the ASIN sanity check it needs is now a named looksLikeAsin the query parser uses as well. Two behaviours change on purpose in the course of that: the legacy scalars are read off the first entry that actually has a name rather than off entry zero whatever it holds, and seriesAsin is checked for an ASIN shape before it reaches the scalar, where until now the membership dropped a bogus value while the scalar beside it kept one. _enrichMetadata re-fetches the full product record before the add and was lifting only authors and narrators out of it, leaving the series data at whatever the search match happened to know. It now takes the memberships and the matching legacy fields from that record when it has any, since the product lookup is the better source of both. The unmatched-files bulk add read series[0].title and .part off a response whose entries carry asin, name and position. Those field names are Audnexus names on an Audible-shaped payload, so the read never matched and every add fell back to the series string parsed out of the file tags. It reads the right fields now, keeps every membership and carries the identifier. mapToAudible is exported so the mapping is tested directly instead of through the bulk-add flow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GDr4ZwWYwhX8fAy26Vq5KD
m4bard
force-pushed
the
fix/bug5-library-import-series-memberships
branch
from
September 10, 2026 18:52
93f909c to
10377e7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Library Import collapses a multi-series match to its first series and never populates
seriesMemberships, so the backend falls back to the legacy scalar path and stores one membership. This builds the membership list in the store instead.Full write-up and the hazard I had to guard against are in #846.
Changes
Fixed
matchToMetadatainfe/src/stores/libraryImport.tsmaps every entry of the search result's series array into anAudiobookSeriesMembership, withisPrimaryandsortOrderfollowing the incoming order, and setsseriesMembershipson the metadata when there is at least one.The scalar
series,seriesNumberandseriesAsinfields stay populated from the first entry, so nothing reading them changes behaviour.AudiobookSeriesMembershipHelper.Normalizeonly synthesizes from the scalar when no memberships arrive, so sending the list is enough to take the other path.Guarded
seriesAsinis kept only when it matches/^[A-Z0-9]{10}$/i.This is not cosmetic.
SearchResponseMapper's fallback branch, used when the ASIN re-fetch fails, sets a synthesized entry'sasinto the series name. That is harmless today because the value has nowhere to land and is dropped on the way in. Sending memberships gives it somewhere to land, and it would be persisted intoAudiobookSeriesMembership.SeriesAsin, the column #767 is working to make trustworthy. Making the mapper emit null would be the better fix and belongs in its own change; this keeps the bad value out in the meantime.The second flattening at the add call site is deliberately untouched. It adapts to
SearchResult.Series, which isstring?on the backend, so it is a single-series contract rather than a second instance of the bug.Testing
Two cases added to
fe/src/__tests__/libraryImport.store.spec.ts: that every membership of a multi-series match reaches the add request, and that a series asin which is really the series name is dropped.Verified as real guards in both directions. With only the source change reverted and both tests kept, both fail and the other seven in the file pass. Restored, all nine pass.
Full frontend suite: 597 tests across 89 files, all passing.
vue-tsctype-check clean, prettier and eslint clean on both changed files.Notes
No container reproduction for this one, and I would rather say so than imply parity with the other reports. This is browser-side logic on the path between a search result and the add request; no scan, import action or database state exercises it, so a harness check here would not be testing the thing that is broken.
The multi-series case is real rather than constructed:
B00CQ5WAXWreturnsseriesPrimary"Ayesha" andseriesSecondary"Allan Quatermain" fromapi.audnex.us, verified live rather than taken from a quote.