Files
shelfmark/docs/hardcover-sync.md
T
48ae3dbef4 feat: optional Hardcover wishlist sync with automated downloading (1 of 5) (#1516)
This replaces #1047, which @InfiniteAvenger opened and calibrain offered
to re-review. It is Caleb's feature commit with his authorship kept,
rebased onto current main, with small fixes, tests and a docs page on
top. Everything is opt-in and off by default, so nothing changes for
anyone who doesn't turn it on.

What it adds is a **Settings, Hardcover Sync** tab with three parts that
can be switched on separately:

- **Shelf sync**: a Hardcover shelf (Want to Read by default) is pulled
into requests on a schedule, or with a Sync now button. Requests carry
the Hardcover metadata and cover.
- **Automatic downloads**: synced requests are approved and a release is
picked from a source priority list. A strict title, author and format
match (plus a seeder minimum for torrents) decides, so anything without
a confident match stays pending for manual review.
- **Skip books you already own**: sync and automatic downloads ask
whichever libraries are enabled under Library Check (Calibre today) and
skip a book that is already there.

On top of Caleb's commit I made the request owner a lookup instead of
assuming user id 1, sent synced cover URLs through the proxy when the
request is created, got ruff and basedpyright clean, and added tests and
`docs/hardcover-sync.md`. His commit also had its own Audiobookshelf
settings and a Test library connection button, written before the
library check was split into providers. The button would have raised a
TypeError against the current `test_connection`, so those settings are
gone from this tab and an Audiobookshelf provider comes as a separate
PR, which is the part of #1047 that is missing here (for now
anyways...).

I've run this daily for about a couple of weeks. Ruff, basedpyright and
the backend suite pass (4426 passed).

This is 1 of 5. As calibrain suggested, the rest are stacked on this
one, each saying which number it is.

Closes
https://github.com/calibrain/shelfmark/pull/1047#issuecomment-6302071588

---------

Co-authored-by: InfiniteAvenger <calebewest02@gmail.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 20:27:47 -04:00

6.3 KiB

Hardcover Sync

Configure in Settings → Hardcover Sync.

Hardcover Sync pulls books from your Hardcover reading shelves into Shelfmark as requests, optionally downloads them without an admin picking a release, and can skip books you already own in a library you have set up under Library Check. Every part is opt-in and off by default; the tab does nothing until you enable it.

Capabilities

Shelf sync

On a schedule, Shelfmark reads the selected Hardcover shelf (by default Want to Read) through the Hardcover metadata provider and creates a pending request for each book that is not already known. Requests carry Hardcover's metadata, including the cover, and are owned by the lowest-id admin account.

A book is skipped when:

  • a request with the same Hardcover book id already exists, in any status
  • a download with the same title and author is already in the download history
  • the library check (below) says it is already in your library
  • a pending request with the same title, author, and content type already exists

Automatic downloads

When enabled, each pending request that came from Hardcover is searched across your release sources in the configured priority order. The first source that yields a strict match wins, and the best candidate from that source is queued through the normal request fulfilment path, so it appears in the activity view and download history exactly like a request an admin approved.

A release is a strict match only when all of the following hold:

  • at least 85% of the significant title words appear in the release title
  • the author's surname appears in the release title, indexer name, or author field
  • the release is an audiobook: an audiobook format (m4b, mp3, or your configured audiobook formats), or "audiobook"/"unabridged" in the title. Ebook-only formats such as epub and pdf are rejected
  • for torrents, seeders meet Minimum seeders; other protocols ignore this check

Among matching releases from the winning source, m4b outranks mp3, then more seeders, then larger size. If no source produces a confident match the request stays pending for manual review; nothing is guessed.

Library check

Both shelf sync and automatic downloads ask the libraries you have enabled under Library Check whether the book is already there, for the content type being requested, and skip it if so. There is no separate switch on this tab. A library that is not enabled, or that does not hold the requested content type, never causes a skip.

The check fails open: a library that cannot be read is logged and the book is treated as not owned, so processing continues.

Settings

Key Label Default Notes
HARDCOVER_SYNC_ENABLED Enable scheduled sync Off Runs shelf sync on the interval below
HARDCOVER_SYNC_TOKEN Hardcover API Token — Leave blank to reuse the Hardcover metadata provider's token
HARDCOVER_SYNC_STATUSES Shelves to sync Want to Read Hardcover reading status to pull from
HARDCOVER_SYNC_CONTENT_TYPE Request as Audiobooks Content type given to synced requests and targeted by automatic downloads
HARDCOVER_SYNC_INTERVAL Sync interval 6 Combined with the unit below
HARDCOVER_SYNC_INTERVAL_UNIT Interval unit Hours Minutes or hours. The effective interval never drops below 60 seconds
AUTO_DOWNLOAD_ENABLED Enable automatic downloads Off Auto-approve and queue strict matches for Hardcover requests
AUTO_DOWNLOAD_SOURCE_PRIORITY Source priority All usable sources Drag to order. Sources you disable here, or that are not configured, are skipped
AUTO_DOWNLOAD_MIN_SEEDERS Minimum seeders (torrents) 1 Torrent releases below this are ignored

One action button sits at the bottom of the tab:

  • Sync now runs a sync and automatic-download pass immediately using the saved settings. Sync runs even when scheduled sync is off; automatic downloads still require their own toggle.

Request Flow

  1. Shelf sync creates a pending request per new Hardcover book, with cover, year, and subtitle where Hardcover has them.
  2. If automatic downloads are enabled, the request is searched source by source and the first strict match is queued through the normal fulfil path. The request becomes fulfilled and its delivery state is tracked like any other.
  3. If no source yields a confident match, the request stays pending in the admin queue for manual review, exactly as if a user had requested the book.

Only requests whose provider is Hardcover are considered for automatic downloads, and requests that have already been dispatched are left alone.

Scheduler

The scheduler starts with the app and waits 60 seconds before its first cycle. Each cycle runs a shelf sync (when scheduled sync is enabled) followed by an automatic-download pass (when that is enabled), then sleeps for the configured interval. Intervals shorter than 60 seconds are raised to 60 seconds so a typo cannot hammer the Hardcover API. When neither toggle is on the scheduler idles.

Only one run happens at a time. If a scheduled cycle is in progress, Sync now reports that a sync is already running.

Troubleshooting

Sync adds nothing and the log says "no Hardcover token configured" — set Hardcover API Token on this tab, or configure the token on the Hardcover metadata provider. A sync without a usable token counts as an error and creates no requests.

Requests appear but nothing downloads — check Enable automatic downloads is on, that Source priority contains at least one configured source that supports audiobooks, and look for no strict match lines in the log. Lowering Minimum seeders helps on quiet trackers; loosening the title or author match is deliberately not an option.

Books you own keep being added — enable the library check for the format you request (see Library Check) and use its test button. Because the check fails open, a library that cannot be read only produces a log warning rather than blocking the sync.

Too many requests at once — the first sync of a large shelf creates one request per book, and the per-user pending limit from Users & Requests does not apply to synced requests. Start with a shelf you are happy to see in the queue in full.