Skip to content

feat(search): unified library search across books, series, authors, narrators#680

Open
kevinheneveld wants to merge 1 commit into
Listenarrs:canaryfrom
kevinheneveld:feat/unified-library-search
Open

feat(search): unified library search across books, series, authors, narrators#680
kevinheneveld wants to merge 1 commit into
Listenarrs:canaryfrom
kevinheneveld:feat/unified-library-search

Conversation

@kevinheneveld

Copy link
Copy Markdown
Contributor

What this adds

Unified library search — searching what you already own, not the outward-facing "Add new" metadata search.

  • The header search now matches across four dimensions at once — Books / Series / Authors / Narrators — grouping suggestions by kind. Each suggestion links where you'd expect: books to the detail page, the rest to their collection page.
  • Enter (or a new "See all results" row) opens a dedicated results page at /search (LibrarySearchView) listing every match in sectioned groups.
  • Matching logic lives in utils/librarySearch, shared by the overlay and the page and keyed off a shared normalizer so a suggestion's count always matches the page it links to. Entirely client-side over the loaded library, with the distinct-name index memoized so typing stays responsive. Non-person narrator credits ("Full Cast", "Various", uncredited) are excluded so the library doesn't sprout pseudo-pages.

It also repairs a currently-dangling navigation: the header already did router.push({ name: 'search' }), but no route named search exists on the current tree (content/SearchView.vue is orphaned), so that push silently failed. This PR makes it resolve.

This is coordinated with in-flight work — not a blind feature drop

I checked this against the open FE PRs before opening it. Calling out the overlaps explicitly so review is easy:

On timing

I know the current iteration is scoped to critical bugs and reviewer bandwidth is tight, so no rush expected on my end. The reason I'm raising it now rather than sitting on it: the router (#679) and the architecture issues (#677/#678) are about to reshape the files this touches, and #673 is already duplicating the normalizer — so coordinating now is cheaper than rebasing a stale branch later. Totally fine to park this until the next iteration opens up; I mainly want the overlap visible so nobody rebuilds it.

Testing

  • vue-tsc type-check: clean.
  • Full FE unit suite: 387 passed, 1 skipped (unchanged from base).
  • 9 new tests for librarySearch (book/series/author/narrator matching, normalization, non-person-narrator exclusion, counts).

Files

File Change
fe/src/utils/librarySearch.ts new — shared matching/faceting
fe/src/views/library/LibrarySearchView.vue new — /search results page
fe/src/__tests__/librarySearch.spec.ts new — unit tests
fe/src/utils/textUtils.ts +normalizeCollectionText (see #673 note), +isNonPersonNarrator
fe/src/router/index.ts +/search route
fe/src/App.vue header overlay: grouped suggestions + "See all results"

…arrators

Expand the header search to match the owned library on all four dimensions at
once, grouping suggestions by kind (each linking to the book detail or the
relevant collection page). Enter — or a new "See all results" row — opens a
dedicated results page at /search (LibrarySearchView) that lists every match in
sectioned Books / Series / Authors / Narrators groups. This searches what you
already have; it is distinct from the outward-facing "Add new" metadata search.

This also wires up the `/search` route the header was already pushing to: the
existing `selectSuggestion` did `router.push({ name: 'search' })`, but no route
named `search` existed on the current tree (content/SearchView.vue is orphaned),
so that navigation silently failed. The new route makes it resolve.

Matching logic lives in utils/librarySearch (shared by the header overlay and
the results page) and is keyed by a shared normalizer (utils/textUtils
normalizeCollectionText) so a suggestion's count matches the page it links to.
Entirely client-side over the loaded library, with the distinct-name index
memoized so typing stays responsive. Non-person narrator credits ("Full Cast",
"Various", uncredited) are excluded so the library doesn't sprout pseudo pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant