mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-09-27 22:05:56 +01:00
Per discussion #1372, where you said you were fine with this specific implementation: check whether metadata.db exists, read it if so, and show a check mark saying the book is already there. Searching for a book you already own gives no hint that you own it, so the easiest way to end up with a second copy is to not remember you have the first. This reads a Calibre `metadata.db`, read only, and marks matching results with an **In library** badge in the card, list and compact views and in the details dialog. Off by default. It sits in Settings, General beside the existing Library URL, with a test button that reports how many books it indexed. No HTTP call, no token, nothing written back. Matching runs most to least confident: a shared external id, then an ISBN compared in both ISBN-10 and ISBN-13 form, then fuzzy title tokens plus the author surname. The check fails open, so an unreadable database degrades the badge and never blocks a search, and entries are cached for ten minutes with an early refresh when the file changes, so a large library costs one read rather than one per search. `text_match.py` is new and shared by the index and the provider, so title, author and ISBN matching stays consistent in one place. ## On the provider interface `library_index` talks only to a `LibraryProvider` protocol and knows nothing about Calibre. That is deliberate but it is not speculative generality, it is what let me send you the Calibre half on its own: I run an Audiobookshelf provider on the same interface in my fork, which is where the audiobook side of the badge comes from. I have left that out because it is a new service integration rather than something already in the codebase, which is the line your non-goals draw. Happy to send it separately if you ever want it, and equally happy for the answer to be no. Adding a library is a module with the `LibraryProvider` shape plus one line in `all_providers()`. ## Verification - `tests/core/test_library_index.py`: id, ISBN and fuzzy matching, per-content-type provider selection, fail-open on provider errors, stale-cache reuse, TTL and fingerprint refresh, per-provider cache isolation, and the test-connection path including unsaved form values. - `tests/core/test_text_match.py`: ISBN variants and token matching. - `src/frontend/src/tests/libraryBadge.test.ts` and the added cases in `bookTransformers.test.ts`. - Python suite (3269) and frontend suite (206) green, plus ruff, ruff format, basedpyright, vulture, tsc, oxlint, oxfmt and the production build.
2.1 KiB
2.1 KiB
Library Check
Shelfmark can mark search results you already own, so you do not download a second copy of a book that is already on your shelf. The check is read only and off by default.
Calibre
Point Shelfmark at the metadata.db of a Calibre library (Calibre, Calibre-Web,
Calibre-Web-Automated, anything that keeps the standard Calibre format) and it reads the
database directly. No HTTP call, no API token, and nothing is ever written back.
- Mount the library folder into the container read only, for example
/path/to/calibre-library:/calibre-library:ro. Mount the folder rather than the file so the-waland-shmsidecars are visible, otherwise a library that is being written to can read as out of date. - In Settings, General, turn on Mark books already in your Calibre library.
- Leave Calibre metadata.db path at
/calibre-library/metadata.dbunless you mounted it somewhere else. - Press Test Calibre library. It reports how many books it indexed.
A result that matches the library then carries an In library badge in the card, list and compact views, and in the details dialog.
How a match is decided
In order of confidence:
- An external id the metadata provider and the library agree on.
- An ISBN, compared in both ISBN-10 and ISBN-13 form.
- Fuzzy title tokens plus the author surname, the same rule the rest of the app uses for book matching.
Behaviour worth knowing
- It fails open. If the database cannot be read, Shelfmark logs a warning, reuses the last successful read if it has one, and otherwise treats the book as not owned. A broken path degrades the badge, it never blocks a search.
- Results are cached for ten minutes, and refreshed early when the database file changes, so a large library costs one read rather than one per search.
- Ebooks only. A Calibre library holds ebooks, so the badge answers for ebooks. The
provider interface in
shelfmark/core/library_providers/takes more libraries: add a module with theLibraryProvidershape and list it inall_providers(). Nothing above that function knows which libraries exist.