Repository navigation
Connect in the app: Scan a QR code first and say where the QR is; Find on LibriVox follows a fetch past the page - #297
Merged
Merged
Conversation
A new user moving from Audiobookshelf found the app asking for a username and password: the address field and Continue were the main action, Scan a QR code sat below as an outline button, and nothing said where the QR is. The scanner's hint pointed at the server's connect page, which asks for an invite code first. In the app, Scan a QR code is now the screen's one primary (full width, lg), above the address field under "Or enter the server address" (its Continue secondary). The lead and the scanner's hint say where the QR is: the admin console under People > your name > Pair a device, or the invite page. The sign-in step offers "No password? Scan a QR code instead" in the app, and the invite code's hint says no password is needed. The web keeps its layout. All six locales use the console's own words for People and Pair a device; STYLEGUIDE.md records the pattern. Part of #264.
…e Bridge lapses Leaving Find on LibriVox (or closing the work) before a fetch ended stopped following it, so the Library showed the new book only after a resume or its stale time. A root listener, LibrivoxFetchWatcher, now holds every fetch a row follows (in memory) and is its one poller; when one ends it asks the works again and, for a done one, reads the library's lists again and the works once more after 2 s on a module timer, so the recheck survives the row unmounting too. Rows read the job without polling. A watch stops on a 404, a refusal or a sign-out. The rest of the L6 review's follow-ups: - a /server read again while the Bridge's heartbeat has lapsed keeps the open page, its search and followed fetches, says the Bridge is away and holds Add back (notAdmin and metadataOff still close it); - a failed /server read with nothing kept says so with Retry instead of leaving the skeleton up; - a link without ?connection= is the default connection's (useCid), here and in Find shows, instead of "Only an admin can add"; - Cancel sits under the fetch's status, where Add was, instead of floating 560 px into a full-width row; the status shares JobStatusLayout with Generate's (same look there); - librivoxSearch drops its unused lang/limit, parseFindLibrivoxParams its unused connectionId; - the podcast directory search keeps its results when reading the same search again fails, like Find on LibriVox. Part of #293.
…ult connection The watcher's own suite and the search's each mock the other half, so nothing failed if RootListeners stopped rendering it: the root services test now asserts it under RootListeners and the web's RootServices. Find shows gets the link-without-?connection= case Find on LibriVox has. CONVENTIONS drops the search's removed lang/limit and says what a lapsed heartbeat does to the watcher: /server's bridge flag is true only while the Bridge is online, so its reads pause and the watch is kept. Part of #293.
JobStatusLayout had an actionBelow mode with one caller, which rendered the action exactly where children already go. The fetch status now passes its Cancel as children, so action only ever means the title's end. The tone union is exported once (JobStatusTone) instead of being spelled in the layout and in the fetch's looks, and lineLines and bridgeAway are required: every caller passes them, and an optional bridgeAway could be forgotten. Part of #293.
The watcher dropped a watch on its own list of statuses (400, 401, 403) while the poll it mirrors stops on isSignedOutError and isNotInLibraryError. A change to one would have left a watch mounted with a poll that never asks again. The watcher now uses the same two predicates, with a 404 kept as an end (the works are asked again) rather than a refusal. Also drops the test-only reset helper (the tests set the store, as they do the session), and corrects the poll interval's comment: the watcher asks it active now, not the focused page. Part of #293.
A queued fetch reached the watcher only through the row's state and an effect. Add asks the metadata service before it queues, so a page left in that window got its answer with the row gone: the job ran unwatched and its end never read the Library again, which is the case the watcher is for. The row now hands the job over as the answer arrives. A work opened again shows its last answer first, which can still name a fetch that has ended. The row handed it back and the watcher ran its end a second time (the works and up to six lists read again). A job the row already reads as ended is no longer handed over. Part of #293.
Find on LibriVox now stays open through a lapsed heartbeat, but only Add was held back. Cancel is gated on the bridge capability, which the server drops with the heartbeat, so it was an enabled button that sent nothing and said nothing (the row swallows a never-sent cancel, which was right when the page closed with the flag). It is disabled with Add until the Bridge is back. Part of #293.
The sign-in step's Scan a QR code instead opened the scanner with nothing of the reconnect it was part of, so the pairing that followed ran as a new sign-in. For a server that was reset that matters twice: reconnecting another person's connection (Household's Sign in again) left their dead identity flagged and put the new connection in the profile of whoever was listening, and a code naming another of the connection's addresses stored that address, so the dead identity was never matched and stayed beside a duplicate. A code or a password typed on the same step did neither. The step now tells the scanner which connection it re-pairs. The scanner keeps that only for a code of one of the connection's own addresses (any other server is a new connection, as before): an invite code's sign-in step gets it as its reconnect, and a pairing code's connect screen takes it from memory by the code's token, never from a route param a link could set. The pairing then uses the connection's own proxy headers, as a typed reconnect does. Part of #264.
An invite link's code signs in as the step opens. The scan link stayed live meanwhile: the camera opened, the first sign-in finished under it, and a code scanned then started a second sign-in for another session. Part of #264.
The page now stays open when the Bridge's heartbeat lapses, but nothing read /server again on an open page (its answer is fresh for five minutes and has no interval). A Bridge that came back seconds later left Add and Cancel disabled and the followed fetches' reads skipped until the app was left and opened again. While away, the page asks every minute with the app in the foreground. Part of #293.
The watcher drops a watch whose read is refused, and the row no longer polls. A token revoked mid-download (a 401) dropped the watch; once signed in again the job was read once, still running, and the row showed that progress for ever, with nothing to notice the end. The row now hands the fetch over with each answer that reads it open, which changes nothing while it is watched. The row and the watcher also share one reading of a job's answer (gone, the job, ended) instead of a copy each: the row decides what to hand over by the rule the watcher ends on. Part of #293.
parseFindShowsParams still returned a connectionId nothing read, while the page takes its connection from its scope and falls back to the default one. The twin LibriVox parser had already lost the field. The two pages' comments now name the pages that share the fallback (book and series), not every content page: the browse and account pages do not fall back. Part of #293.
The sign-in step told the scanner which connection it re-pairs through a route param, and a link opens that route too (audiosilo://connect/scan), so a link could name a connection to re-pair: on a server that was reset, the connection retired and the profile the new sign-in lands in. The connect screen already refused to take it from its own params for that reason. Both scan buttons now open the scanner through openScanner, which holds the reconnect in memory for the scanner to take once; opening it without one clears what an earlier opener left. The connect screen checks the held reconnect against the code's address again as it pairs (the token alone matched before, so the same token at another address kept it), and the flow's layout drops whatever nothing took when the flow is left. Part of #264.
A scanned code kept its reconnect for any of the connection's addresses, the home address among them. Another server can answer at the same private address on another network (a friend's house on the same subnet). Its code scanned from the reconnect's sign-in step read as this server reset: the connection was retired and the other server's session stored at its public address. A sign-in typed on that step never goes to a home address that has not answered as this server. The reconnect is now kept for the address the connection was paired at or its away address only. A code naming a home address it was not paired at is a new connection, as one scanned from the first step is. Part of #264.
The mock's selector built a new object at every call for a job not asked or not read yet, so React logged that getSnapshot should be cached and a watch on an id with no seeded read ran to the update depth limit. Part of #293.
A Find on LibriVox link without ?connection= reads its library id on the default server, and when that server had no such books library the page silently put Add on the server's first books library. It now shows the broken-link sentence instead, so a fetch only ever goes to a library the link or the picker named. Find shows never picked another library, but it gets the same refusal rather than a page whose every follow fails. While the libraries load nothing is refused. The "add a books library first" line is gone: a server with none now refuses the link. Part of #293.
The libraries are cached at startup, so a library added since was refused with the broken-link sentence until the background read landed. Both Find pages now refuse only when the list is not being read again; meanwhile LibriVox holds Add back. The LibriVox refusal also returns before the form and the results are built. Part of #293.
This was referenced Nov 14, 2026
Owner
Author
|
Device run (release APK of this branch, installed as app.audiosilo.dev), all five checks PASS:
The Pixel's camera showed only black in this setup, so the actual scans in checks 3 to 5 ran on a Pixel 9 Pro emulator, with the real QR shown on the emulator's virtual scene. That emulator ran the same APK. A real scan through a phone camera still needs someone to point a phone at a code. No errors in logcat or the console. |
KodeStar
added a commit
to KodeStar/audiosilo-docs
that referenced
this pull request
Nov 14, 2026
…vites on a phone, and LibriVox fetch changes (#306) Closes #278, #304. Docs for KodeStar/audiosilo-server#384, KodeStar/audiosilo-frontend#297 and KodeStar/audiosilo-bridge#70. ## User Guide - **New page "Move over from Audiobookshelf"** (`getting-started/coming-from-audiobookshelf.md`), linked from first-run step 5, the sidebar and Features. It covers: - Audiobookshelf's `metadata.json`, which is off by default ("Store metadata with item"; Audiobookshelf writes a book's file only when it saves a change to it); - the import, Match automatically, and what unmatched means; - adding a missing book, layout differences, and running both side by side. - **Pairing:** - `connecting.md` leads with: install the app, tap Scan a QR code, and where the QR is for an admin and for someone invited. - The camera claim is fixed in `first-run.md`, `connecting.md` and `account.md`: the phone's camera opens the web player, or for an invite the invite page. - New troubleshooting entry: "Scanning the QR code opened a web page". - **Invites** (`admin/users-and-invites.md`): the 7-day default, Share, the optional password, the three notices, the phone invite page and the store links. - **Matching** (`health.md`, `books.md`): the community database has gaps; link to "add a missing book". - **LibriVox:** - a fetch is followed after you leave the page; - the Bridge-away notice and the bad-link page; - the matched, kept and unmatched notifications; - sections are kept through an archive.org outage, and abandoned downloads are cleared after 7 days. - **Proxy headers** (`remote-access.md`): a set goes to the one https address it was entered for. A plain-HTTP home address never gets them. ## Developer Docs - `bridge/librivox.md`: `adopted` (false only when this run placed the folder), the outage rule, meta refusals failing fast, a parked fetch freeing the lane slot, the sweep, the server id in the state, and the fold by `adopted`. - `api/reference.md`: the redeem payload's `admin`; `links` `ios`/`android`/`apk`; librivox.fetch `title` and `adopted`; `librivox_match`. - Also updated: the contract mirror and the data model, auth, web UI and frontend pages. ## Screenshots - Regenerated against the PR branches: - `admin/invite.png` - `setup/abs.png` - `setup/phone.png` - `server/connect-page.png` - the new `server/phone-connect-invite.png`, taken in an iPhone context - `web-player/connect*.png` - `web-player/find-librivox.png`, now taken in capture-web (#304) - The capture-web path ran for real through the shared helpers. - The native app's connect screen is not in the pipeline (web only). ## Review /simplify plus one `/code-review high --fix`; the console strings match server commit 0f7420f. Gate: `npm run build` green (links and anchors checked); old anchors kept.
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.
Closes #264, #293 (except its "not verified live" items, covered below).
Connect (#264)
A new user's app asked for a username and password, and nothing said the QR was the easy way or where to find it.
Find on LibriVox (#293)
/serverevery 60 s while away./serverread shows Retry instead of a skeleton.?connection=uses the default connection (Find shows too). A link naming a library that server doesn't have shows "This link doesn't point to anything here." once the library list has settled, instead of adding to the first books library.JobStatusLayoutwith Generate). Unused params are gone, and directory search keeps its results when a re-read fails.Review and verification
/code-review high --fixpasses on the whole branch, then one fix round. Gate green afternpm ci: tsc, lint, prettier, 7785 tests.Pairs with KodeStar/audiosilo-server (feat/new-user-b) and KodeStar/audiosilo-docs (docs/new-user-b, to follow).