Skip to content

Audiobookshelf import: name an untrusted certificate, import inside setup, offer Match automatically - #395

Merged
KodeStar merged 9 commits into
mainfrom
feat/abs-import-setup
Nov 14, 2026
Merged

KodeStar merged 9 commits into
mainfrom
feat/abs-import-setup

Conversation

@KodeStar

Copy link
Copy Markdown
Owner

Part 1 of #366 (Audiobookshelf import). Part 2, the identifiers kept as match hints, merged as #393.

What

  • abs_certificate: when Audiobookshelf's https certificate isn't trusted (self-signed or a private CA), Connect, Status and a background fetch now fail with abs_certificate (still 502) instead of abs_unreachable / not_abs. The console shows it under the address field and points at ABS's plain http:// address. Nothing is ever trusted or skipped. Detection is one errors.As on *tls.CertificateVerificationError: Go's client handshake wraps every verify failure (unknown authority, hostname, invalid) in that type. https to an http-only port stays abs_unreachable (http.ErrSchemeMismatch).
  • Import inside setup: ImportFlow (connect, map, review, history) is extracted from Settings > Import and rendered inline in the setup flow's Audiobookshelf step (embedded), replacing the new-tab link. Continue and Skip stay. While a books library is scanning, the step says "Wait for the scan to finish" and Connect is off (from the libraries the flow already polls, so no wire field).
  • Match offer: Matching: Match automatically where people look, Add it for books not found, ASINs the database doesn't know; invite and Bridge job polish #390's UnmatchedPrompt (Match automatically) appears once an import is applied, in the Past imports card, and in the setup step once the scan is done. It links to Health (a new tab from setup) and never starts a run by itself.
  • Keep Audiobookshelf's ASIN and ISBN as match hints (0074 book_hints) #393's identifiers row and the identifier-only apply guard are unchanged inside the extracted flow.

Error-code wire change is additive; no player change.

Tests

Go: a TLS fake gives abs_certificate from Status and Connect. A hostname mismatch with a trusted pool gives it too, and 127.0.0.1 connects as the control. https to an http port stays abs_unreachable, and plain http is unchanged. API: 502 on connect, and error_code on a failed background fetch. Console: the certificate row, ImportFlow inline in the abs step with the scan gate, the offer after an apply and held until the imports are read, and imports-model. Gate: build-admin.sh (1628 tests), go build/vet/test -race, golangci-lint 0.

Verified live

Real Audiobookshelf 2.37.2 in Docker:

  • Certificate error: http connects. Behind a private-CA proxy and a truly self-signed proxy, Connect shows the certificate message under the address field, and curl returns 502 abs_certificate. Switching to http:// connects. The same results came from the Linux binary inside the :edge image (Alpine, Go's own verifier).
  • Setup step: on a fresh server with a slowed first scan (97 s), the gate showed and lifted 0.8 s after the scan ended. Connect, map, fetch, review (the identifiers row read "4 books") and apply all ran inline. Exactly one offer appeared, in Past imports, and it opened Health in a new tab with no match run started. Continue and Skip both moved on.
  • Layout: no sideways scroll at 390 px or on desktop.

Not verified: the image's native-SQLite (CGO) build. The certificate check runs before any database work.

Notes

  • de/es/fr/it/pt text for errors.absCertificate, imports.failure.abs_certificate, setup.abs.import and setup.abs.waitScan is machine-translated and wants a native read.
  • Follow-ups go in one issue (scan gate covers Connect only; no-books-library wording; redirect-to-https hint; offer link icon; the map table is cramped on a phone; two Back buttons while mapping).

Pairs with KodeStar/audiosilo-docs (docs for #366, PR to follow).

An https Audiobookshelf with a self-signed certificate (or one for another
name, or expired) failed the import's connect as abs_unreachable, and /status
read it as not_abs, so the console said the address was wrong. The client now
recognises the handshake's verification errors and answers abs_certificate
(still a 502, and a failed import's error_code), so the console can point at
ABS's plain http:// address instead. Nothing is trusted that wasn't before.

Part of #366.
The connect form shows the new code under the address field with what to do
(use ABS's plain http:// address on the network), and a failed import that met
it says the same as its hint. Words added in all six languages.

Part of #366.
…matching

The abs step only linked to Settings > Import in a new tab, so someone moving
from Audiobookshelf left the flow to do the one thing the step is for. The
import (connect card, review cards, past imports) is now ImportFlow, shared by
Settings > Import and the abs step, which renders it inline (compact: no step
counter of its own) with Continue and Skip as before. While a books library's
first scan runs, Connect waits with a line saying so: the import matches
against the books the scan finds. The libraries the flow already polls say
that; no new field.

Once an import is applied the past imports' card offers Match automatically
(UnmatchedPrompt, shown only while books are unmatched; it never starts a run),
and the abs step offers it once the scan is done; in the flow it opens Health
in a new tab so the step stays open.

Part of #366.
…urns

crypto/tls wraps every verification failure of the server's certificate (unknown authority, another name, expired) in *tls.CertificateVerificationError, so the three x509 targets beside it never matched on their own. One check says the same thing, and CONVENTIONS no longer reads as if there were a second path. The redirect test answers /status with the shared absStatus.

Part of #366.
The prop hides the step counter and also opens the match offer in a new tab: both follow from being hosted in a flow that has its own steps and must stay open, not from being smaller. The old name would have handed new-tab links to any later host that only wanted the tighter layout.

Part of #366.
The abs step and import tests each rebuilt the no-scan progress and Health's summary with n books not matched; both now come from test/fixtures (idle, and a new unmatchedSummary). Drops an assertion on a link label that no longer exists in any language, so it could not fail.

Part of #366.
net/http turns the handshake's tls.RecordHeaderError into ErrSchemeMismatch when the answer was plain HTTP, so the type the import notes named is never what the ABS client returns. The behaviour (abs_unreachable) is unchanged.

Part of #366.
The abs step's test spelled out all fourteen fields of an import that the import tests' own factory already defaulted, so a new required field would need adding in each copy. Both now build on importRow in test/fixtures.

Part of #366.
ImportFlow decides where the offer goes from whether an import is applied, but read that from an empty list while GET /admin/imports was still out. With a scanned library and an applied import the count could arrive first: the offer showed under the connect form, then moved into the past imports' card when the list came. It now waits for the list.

Part of #366.
@KodeStar
KodeStar merged commit c66334c into main Nov 14, 2026
4 checks passed
@KodeStar
KodeStar deleted the feat/abs-import-setup branch November 14, 2026 23:19
KodeStar added a commit to KodeStar/audiosilo-docs that referenced this pull request Nov 14, 2026
…ort inside setup (#310)

Docs for KodeStar/audiosilo-server#366, the Audiobookshelf import. It
covers part 2 (KodeStar/audiosilo-server#393, merged) and part 1
(KodeStar/audiosilo-server#395). **Merge with or after #395**: the
certificate error, the import inside setup, the match offer and
`setup/abs.png` exist only there.

## User Guide
- **admin/import.md**: a new "Match your books after an import" section.
An import's ASINs and ISBNs are match hints. They never become the
book's ASIN and never show in the apps, and the book stays unmatched
until a match is applied (hence the offer). Hints come only from
libraries the token can see. It also covers:
  - undo, and which import owns the hints;
- an identifier-only import refused when it would replace an applied
one;
- the certificate error, with the advice to use Audiobookshelf's plain
http:// address (never trust the certificate);
  - waiting for the scan.
- **getting-started/first-run.md**: step 6 now runs the import inside
the step, says to wait for the scan, and shows the Match automatically
offer.
- **getting-started/coming-from-audiobookshelf.md**: matches the above.
ABS's "Store metadata with item" is off by default
(`server/objects/settings/ServerSettings.js`, `storeMetadataWithItem =
false`, v2.37.2), so that line is unchanged.
- **admin/health.md**: a new "Audiobookshelf's ASINs and ISBNs" section.
A `metadata.json`'s ids are the book's own; an import's are hints. A
wrong hint is settled by matching the book by hand.
- **admin/books.md** ("What matching sends") and **features.md**.

## Developer Docs
- **api/reference.md**:
  - `abs_certificate`, both as a 502 and as an `error_code`;
- the summary's `identifiers {books, asin, isbn, by_title,
already_matched}` and a new "Identifiers (match hints)" section;
  - the apply's 409 `import_not_ready` refusal;
- undo, the match dialog's hint order and `identifier_disagrees` from a
hint.
- **data-model.md**: `book_hints` (0074) and "Match hints from an
import". It gives the QueryFor order: own ids win, an Audiobookshelf
hint goes ahead of tag hints, a tag ASIN goes only when the import gave
no identifier, and a tag ISBN may go beside an ABS ASIN. It also covers
ownership and the LibriVox drop: a book placed from LibriVox drops the
hints at its path, and an adopted folder keeps them.
- **web-ui.md** (the abs step and `UnmatchedPrompt` sites),
**scanner.md** (hints don't count as matched), **bridge/librivox.md**,
**cross-repo-contract.md**, and a listening-imports row in the
documentation mapping table.

## Screenshots
`setup/abs.png` is recaptured against #395's server. It shows the inline
Connect form and the Match automatically offer.

## Checks
`npm run build` is green. The docs review (`/simplify` and `/code-review
high`) applied 15 fixes, each checked against the code
(`internal/matchrun/plan.go` QueryFor, `hints_test.go`, the PR1
console).
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