Skip to content

[Step][#1080] Search: Add New's search box and search rules for Repair and Find Match - #1086

Draft
Yoldark34 wants to merge 103 commits into
Listenarrs:canaryfrom
Yoldark34:search/shared-rules
Draft

Yoldark34 wants to merge 103 commits into
Listenarrs:canaryfrom
Yoldark34:search/shared-rules

Conversation

@Yoldark34

@Yoldark34 Yoldark34 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Draft, and only a step. Next step of the Repair epic, #1080, after #1054. The search belongs in the backend later (#1076): this PR only gives Repair and Find Match Add New's search box and gathers the frontend's search rules in one place until then.

Stacked on #1054, the Repair and Find Match book card: until #1054 is merged, the diff below includes its commits. This PR's own changes are its last two commits, rebuilt on #1054's current card, split into components (2026-10-27): #1054's rules (the results' header line, why there are no results said in the middle of the empty list, the answered searches and Retry, the loading and the reveal, the kept room, failed and canceled searches, the highlighted parts) apply to the search box the same way, as written in #1080.

Summary

Repair and Find Match search for a book with separate ASIN, Title and Author fields (#1054), while Add New has one search box that understands a title, an ASIN, or tokens. This PR gives the book card the same search box, and moves Add New's search rules out of its useSearch composable, where they were mixed with its page state, into one shared module that Add New, Repair and Find Match all call: a book is searched by the same rules wherever it is searched.

Changes

Changed

  • The book card's ASIN, Title and Author fields become one search box, read the way Add New's is: a title, an ASIN, or TITLE:, AUTHOR:, ASIN:, SERIES: and ISBN: tokens, with its erase button. It opens on the book's title and author as tokens (TITLE:Primal Hunter, Vol. 7 AUTHOR:Zogarth); in Find Match, on what the files say. The info box says how the box is read.
  • An ASIN alone (bare or ASIN:) is looked up in the region; its records are offered to pick from like any search's; none is said in the middle of the empty list ("No record for … in Audible …"). ASIN: followed by something that isn't an ASIN is a field error (orange), nothing sent, said the same way.
  • Changing the region searches the box again there, the one change that searches by itself; typing only prepares the next search, as on [Step][#1080] Repair: point books at the right Audible record, from the book page and the library #1054. Search, Enter and a region change start the same search; Search becomes Retry after a search until the box or the region changes.
  • The results header and the running search's text read the box as typed (Results for "TITLE:… AUTHOR:…" in France (FR)), or the ASIN (Results for ASIN "B0BK9W82PQ" in …).
  • useSearch (Add New) keeps its page state (searching, status, errors) and calls the shared rules. Add New searches as before; a typed ASIN is now sent in capitals.

Added

  • services/audiobookSearch.ts, the rules of Add New's search:
    • what a query is: ASIN:, ISBN:, TITLE: and AUTHOR: prefixes first, then an ISBN-13, then an ASIN or ISBN-10, else a title;
    • the TITLE:, AUTHOR:, ASIN:, SERIES: and ISBN: tokens (values of several words);
    • where each kind is searched: an ASIN through the metadata endpoint, which tries the enabled metadata sources in their priority order; an ISBN: through the advanced search, a bare ISBN through the simple one; a title through the advanced search;
    • the region, its language filter, and up to 50 results;
    • Audible's metadata for an ASIN turned into a search result.

Removed

  • The card's separate ASIN, Title and Author fields, with their erase buttons and the filled-ASIN priority (an ASIN is now searched by typing it in the box).

Testing

  • audiobookSearch.spec.ts (7 tests): query types, an ASIN read bare or prefixed, the tokens, and which search is called with which region, language and limit (title, ASIN, prefixed and bare ISBN, no language for "all").
  • RepairBooksModal.spec.ts and LibraryImportSearchModal.spec.ts: rewritten for the search box (the token query it opens with, Enter, the region searching again, an ASIN alone taken or refused, Revert, Retry, the answered searches, the reveal, the kept room).
  • Frontend: 765 passed; type-check, eslint and prettier are clean.

Notes

🤖 Generated with Claude Code

@Yoldark34 Yoldark34 changed the title [Step][#1080] Search: Add New's search rules shared with Repair and Find Match [Step][#1080] Search: Add New's search box and search rules for Repair and Find Match Oct 21, 2026
@Yoldark34
Yoldark34 force-pushed the search/shared-rules branch 2 times, most recently from 2fa8f4a to 8cdd383 Compare October 21, 2026 19:58
@Yoldark34
Yoldark34 force-pushed the search/shared-rules branch from 8cdd383 to edaeda0 Compare October 22, 2026 15:26
Yoldark34 and others added 23 commits October 23, 2026 12:56
…he library

A Repair button on the book page and "Repair Selected" in the library open
the Repair dialog. For each book: its ASIN and Region, and Find Match, the
same Find Match as Library Import, opened on the book's title, author and
region. Picking a result takes its ASIN and the region it was found in. An
ASIN typed by hand is checked in its region with the same search before it
is saved. Every region is offered, ordered by the book's current region, the
configured one and US, then alphabetically.

Repairing saves the ASIN as the primary one with its region (identifiers of
the old match are dropped, manual ones kept), rescans the metadata from it,
then offers to Organize the repaired books. Revert per book.

Find Match now also takes a plain target (name, query, author, region)
instead of a Library Import row; Library Import still passes its row and
keeps waiting for its searches before importing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Repair Selected (n)" in the library, like "Delete Selected (n)". The library
button and the Repair button on the book page are orange (the warning color),
like the problems Repair fixes, with dark text and icon to stay readable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The book page's icon buttons get their colors from the shared button styles,
which force every nav icon button that isn't primary or danger to grey. A
warning variant (orange, dark icon) joins primary and danger there, and the
Repair button uses it.

The dialog's info line, selection count and results inherited the page's
dark text color: they now use the same styles as the Organize dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…whole row

Each book has Title and Author fields again, prefilled with its title and
first author. Find Match (or Enter in either field) searches what they hold,
in the selected region; Revert restores them with the ASIN and region.
ASIN, Region, Title, Author and Find Match share the whole row (two columns
on narrow screens).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repair: ASIN, Title, Author, Region, then Find Match. Find Match (shared
with Library Import): each field has its name above it (Title or ASIN,
Author, Region) instead of a placeholder only, in that order; the spinner
sits next to the "Title or ASIN" name while a search runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Another title, author or region describes another record, so the ASIN that
was there no longer matches: it is emptied until Find Match picks the book
again (or its ASIN is typed), and the dialog says so in its note. An empty
ASIN gets its own hint, and Repair waits for one. A record picked in Find
Match keeps its ASIN and region.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each book has a Search button instead of opening Find Match: it searches the
title and author (or an ASIN typed as the title) in the row's region, with
the same search as Library Import's Find Match, and the results open under
the book in the same results list, extracted from Find Match into
FindMatchResults.vue (cover, title, author, series, ASIN, narrators).
Picking one fills the ASIN and region and closes the results.

While a search runs, "Searching ... in <region>" spins under the book and
Search becomes a red "Cancel search" button; canceling goes back to the
fields with nothing to report. A search that fails or takes longer than 30
seconds shows its error with Retry. One book is searched at a time: Search
is disabled on the others ("Another book is being searched"), and Repair
waits for the search to end. Closing the dialog cancels it.

Find Match no longer takes a plain target: Repair no longer opens it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n't move

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or both

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n and the search under the book

Find Match now shows the folder's book in the card the Repair dialog uses for each
book, without the checkbox: the search runs as it opens, the results open under the
book, and "Use this match" takes the picked record or the typed ASIN once its region
is checked to have it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Import use

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One record is selected in the results and fills the title and author; several are
offered to pick from; none is an error under the book, and the book can't be
repaired or matched until its ASIN, title, author or region changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… region counts

Each book card now shows its current record and its new one (checked, an error, or
none yet) and a bar on its left: grey ignored, green matched, red error, with the
legend in the footer. Repair opens with nothing to repair, ticks a book once its new
record is found and says how many are skipped; Find Match's "Use this match" takes
the found record. A typed ASIN is looked up once entered. The long notes become one
line, and the rules show where they apply: "ASIN cleared: the title changed", a
malformed ASIN, the search rules in the Search button's tooltip.

The test stub of ModalFooter renders its left slot, as the real one does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t buttons

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er a failed or empty search

Search turns into Retry while the fields still hold the values of a search that found
nothing or failed, and back to Search once a field changes. An ASIN its region has no
record for keeps Search, to search the title there next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er book

Changing the region looks the ASIN up: one search at a time keeps answers from racing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…- Author - Region

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew read like the summary

Typing an ASIN no longer looks it up: it empties the title and author, which described
the previous record, and Enter or Search looks it up (one record found fills them
again). A malformed ASIN is flagged once the field is left. Current and New use the
summary's text style and its ASIN - Title - Author - Region line; only their state is
coloured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The results show the record the book points at as selected, and once another one is
picked, that one instead; picking keeps the results open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e: Subtitle - Author - Region

The card gets the book's title, subtitle and author and sums the book up once, for
both places.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Yoldark34 and others added 20 commits October 23, 2026 12:56
…' room

New only shows the record picked in the results shown, or its default text.
The header line keeps what was searched and where the answer comes from; a
failed, canceled or refused search (an ASIN that isn't one) empties the
results, and its reason shows over the empty list, once the spinner is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…logs' titles

The Organize dialog Repair opens is its step 3: "Repair Books - Organize -
Step 3/3". Opened on its own, it stays "Organize Files".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…loading state

Repair moves to the results step at once: every book of the dialog, the ones
to repair loading with their old record and the one they get, one repair at
a time. Each card's bottom bar breathes in blue while its book is repaired,
then turns green, orange or red. Organize stays disabled until the repairs
end, a repaired book is ticked for it as soon as it is done, and Close is a
red Cancel meanwhile: the books still waiting are left out at once, the one
being repaired ends first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eled, with what was left out

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the bar orange and is said

The unticked or unmatched books stay behind on step 1. A failed repair, one
done in part or a cancel turns the footer's bar orange as soon as it happens,
and the footer says what went wrong between Close and the skipped count
("Not all repaired: 1 failed, 1 canceled"). The skipped count on step 2
counts its own books: canceled while the repairs run, then left out of
Organize.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… warning, and the selection

The warning's place is kept from the start of step 2, between Close and the
skipped count when the line has room for the longest warning it can show,
on its own line above them otherwise (measured, like step 1's legend). Step
2's bar colours get their own legend, always on its own line above the
buttons. The Selection section moves into RepairSelection, shared by both
steps: on step 2 it counts the books to organize, Select All ticks the
repaired ones, and it waits for the repairs to end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… as far as the buttons need

On the buttons' line it stands centred on the dialog, shifted towards the
side with more room when Cancel or the skipped count and Repair would
overlap it; once even that doesn't fit, it goes above them as before,
centred. Step 2's legend, always above, is centred the same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssage

Repairing, repaired and nothing repaired share one place, only the current
one seen, with the longest these books can bring (all repaired) kept unseen:
the box doesn't grow or shrink when the repairs end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The modal footer's grey Cancel style won over .btn-danger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… them

The Old and New lines stay closed to keep the list short. Show details, on
the right of each book, opens them with the parts that change marked, and
becomes Hide details; its tooltip gives both records on two lines without
opening them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cords

BookRecordDiff draws a record's parts with the ones that differ from the
record it replaces highlighted; the book card's New line and Repair's step 2
both use it. The same record picked again (metadata read anew) has nothing
highlighted. Show details and Select All keep their own width on a phone,
where modal buttons stretch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ep 1's height

Step 2's title reads "Repair process". With one book, the room step 1 took
in the dialog's body (its visible height, less what step 2's footer takes
more) is kept on step 2 by an empty room under the book's row, so the dialog
doesn't shrink when the repair starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ort answer doesn't move the card

With several books, the empty list one result high was a fixed 5rem: a
result without a narrator line came out shorter, one with it a pixel taller,
and what was under the book moved when it answered. The list, its empty room
and an unseen result with every line a result can have now share one place,
as tall as the tallest, from the first search on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both labels share one place, only the current one seen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ord drawn like New

"Repaired in 0.13 s", then the record it now points at through
BookRecordDiff: grey, the parts that changed from before in green, instead
of the bare ASIN and region code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der it; replaced parts in orange

A repaired book's row says how long it took next to its title, and shows
the record it now points at under it, on its own. The old record (Current on
the book card once a record is picked, Old on step 2) shows in orange the
parts the new record replaces; BookRecordDiff takes a replaced flag for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…doesn't grow when its repair ends

First the record the book points at (the one it is to get while it waits,
the one it got once repaired, its old one when the repair failed or was
canceled), drawn like New; then where its repair is or how it ended
("Repaired in 0.5 s"), under it rather than next to the title, for small
screens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… room kept

Before any repair the bar has nothing to show: it takes the dialog's own
colour instead of a grey track, and keeps its room so nothing moves when
Repair starts it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yoldark34
Yoldark34 force-pushed the search/shared-rules branch from edaeda0 to a3af041 Compare October 23, 2026 12:52
Yoldark34 and others added 2 commits October 23, 2026 16:33
…1 loaded afresh

Organize opened as Repair's step 3 offers Back instead of Cancel (until it
has organized): Repair shows again on step 2 as it was left (resume), not
loaded anew. Once the repairs are over, step 2's Close becomes Back: step 1
loaded as when the dialog opens, the books showing what the repairs made of
them; closing the dialog after a repair saved something then refreshes the
page behind (done), even from step 1. The button keeps one size as Cancel,
Canceling… and Back (every label in one place, only the current one seen).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At the row's bottom right, laid over room the row always has (its status
line leaves it free), so showing it moves nothing. It repairs that book
again, the dialog repairing meanwhile: the footer's button is a red Cancel,
Organize waits, and the warning updates when it ends. The repair of one book
moves into repairOne, shared by the repair and Retry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yoldark34
Yoldark34 force-pushed the search/shared-rules branch from a3af041 to 5202496 Compare October 23, 2026 14:59
Yoldark34 and others added 5 commits October 27, 2026 12:38
…oller

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… shared pieces reusable

The book match card and the Repair dialog held their logic, their layout measures and every
style in one file each (1279 and 1002 lines). Split by responsibility, nothing changes on screen
(Repair Books compared pixel for pixel, before and after, in 13 states):
- bookMatch/: the card's components (BookMatchCard, its fields, records and results, the results
  list, legend and record diff), moved from audiobook/
- the card's search: its state and texts in utils/bookSearch, the request (abort, timeout, stale
  answers) in useAbortableRequest, the results reveal in useResultsReveal
- Repair: the books and their repairs in useRepairBooks, the pure rules in utils/repair, the
  footer in RepairFooter (its measures in useRepairFooterLayout), one result in RepairResultCard
- shared: StatusBar (the cards' and dialog's bottom bar), SteadySwap (contents in one place that
  keeps the size of the largest), NoticeBox (the dialogs' info box), ClearableInput

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- no bare id or rows: audiobookId, repairRows, searchingAudiobookId, audiobookIdsToOrganize
- collections are the plural of their element type: searchResults, repairOutcomes, legendEntries
- lookups read valuesByKey: BAR_TONE_BY_STATE, HEADER_TEST_ID_BY_OUTCOME, baseTextByKey
- BookMatch: match → bookMatch; picked, initial, current → pickedSearchResult, initialValues,
  currentRecordKey; Searched → SearchParameters; a shared RecordKey (ASIN + region)
- every boolean is prefixed (is/has/should), props included except the HTML-like visible and
  disabled: isSearchLocked, isRunning, hasTimedOut, shouldKeepResultsRoom, isAsinValid…
- no abbreviations or one-letter names: px → pixels, o/r/i/s/a/n → what they are; component
  refs end in Ref

Nothing changes on screen (Repair Books compared pixel for pixel in 13 states).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Repair and Find Match

Add New's search rules move out of useSearch into services/audiobookSearch.ts: what a
query is (prefixes, ISBN-13, ASIN or ISBN-10, else a title), the TITLE:/AUTHOR:/ASIN:/
SERIES:/ISBN: tokens, where each kind is searched (an ASIN through the metadata sources
in their priority order, an ISBN and a title through the search endpoint), the region,
its language filter and the 50 results. useSearch keeps Add New's page state and calls
them; the book card of Repair and Find Match calls them directly instead of a useSearch
instance.

A step only: the search belongs in the backend later (Listenarrs#1076).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and Author fields

The card's ASIN, Title and Author fields become one search box, read the way Add New's
is: a title, an ASIN, or TITLE:, AUTHOR:, ASIN:, SERIES: and ISBN: tokens, with its
erase button. It opens on the book's title and author as tokens (in Find Match, on what
the files say). Its results are offered to pick from; an ASIN alone (bare or ASIN:) the
region has no record for is an error, and ASIN: with something that isn't an ASIN is a
field error. Changing the region searches the box again there; typing only prepares the
next search. The results header and the running search read the box as typed, or the
ASIN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yoldark34
Yoldark34 force-pushed the search/shared-rules branch from 5202496 to aabbf29 Compare October 27, 2026 14:36
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