feat(search): unified library search across books, series, authors, narrators#680
Open
kevinheneveld wants to merge 1 commit into
Open
feat(search): unified library search across books, series, authors, narrators#680kevinheneveld wants to merge 1 commit into
kevinheneveld wants to merge 1 commit into
Conversation
…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>
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.
What this adds
Unified library search — searching what you already own, not the outward-facing "Add new" metadata search.
/search(LibrarySearchView) listing every match in sectioned groups.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 namedsearchexists on the current tree (content/SearchView.vueis 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:
normalizeCollectionTextinfe/src/utils/textUtils.ts(byte-for-byte the same NFKD→strip-diacritics→lowercase→collapse helper). That's a duplicate-export collision if both land as-is. I'd suggest landing one of them and having the other consume it — I'm happy to drop mine and rebase onto fix: normalise author group keys to prevent duplicate author cards (#672) #673's, or vice-versa, whatever's easier for the maintainers. This PR adds one more helper alongside it (isNonPersonNarrator) which is search-specific.fe/src/views/library/AudiobooksView.vue. This PR deliberately does not touch that file. Browse-by-narrator (which does touch it) is intentionally split into a separate follow-up so it doesn't collide with feat(library): clickable list-view column headers for sorting (#625) #674/fix(library): stabilize list-view virtual scroller (#675) #676; I'd rather land those first.services/routerInstance.tsout ofrouter/index.ts. This PR's only router change is a single additive route block, so it rebases onto that refactor trivially. Happy to sequence after Stabilize dependency restores and frontend build validation #679 lands.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-tsctype-check: clean.librarySearch(book/series/author/narrator matching, normalization, non-person-narrator exclusion, counts).Files
fe/src/utils/librarySearch.tsfe/src/views/library/LibrarySearchView.vue/searchresults pagefe/src/__tests__/librarySearch.spec.tsfe/src/utils/textUtils.tsnormalizeCollectionText(see #673 note), +isNonPersonNarratorfe/src/router/index.ts/searchroutefe/src/App.vue