Skip to content

feature: calibre content server connector - #123

Open
benjitobz wants to merge 8 commits into
Chaptarr:developfrom
benjitobz:feature/calibre-content-server-connector
Open

feature: calibre content server connector#123
benjitobz wants to merge 8 commits into
Chaptarr:developfrom
benjitobz:feature/calibre-content-server-connector

Conversation

@benjitobz

@benjitobz benjitobz commented Sep 3, 2026

Copy link
Copy Markdown

Description

Adds a Calibre Content Server notification connection that mirrors ebooks from Chaptarr to an external calibre content server. It's deliberately a one-way mirror: Chaptarr pushes books and its own deletions outward, but changes made on the content server are never pulled back, and a book deleted there may be pushed again later. The settings help text states this explicitly, since that asymmetry is the main thing a user needs to understand.

Fixes # — n/a (feature)

Related External PRs

CWA: crocodilestick/Calibre-Web-Automated#1530
CWA-NG: new-usemame/Calibre-Web-NextGen#2210

Database Migration

NO. Connection settings live in the notification definition's existing JSON settings blob; no schema change.

How was this tested?

Docker (linux/amd64) on an Ubuntu server host, image built with Dockerfile.build. The mirror target was a separate calibre Docker container running its content server, configured as a connection in Chaptarr.

Scenarios ran against the live setup:

  1. Import → push
    Added a book in Chaptarr and let it download; on import it was pushed into the calibre content server.
  2. Book delete → mirrored
    Deleting the book in Chaptarr removed the corresponding record from the content server.
  3. File delete → mirrored
    Deleting the pushed book file in Chaptarr likewise removed it from the content server.
  4. Deletes gated
    With Allow Edits & Deletes disabled, the record was left in place on the content server instead of being removed.
  5. One-way mirror confirmed
    Deleting the book directly in calibre did not remove it from Chaptarr — the book remained tracked, as documented.
  6. Re-push re-adds
    The Re-push action on the book page sent the book back into the content server after it had been removed there.
  7. Re-push is idempotent
    Running Re-push again on a book already present did not create a duplicate record — the existing record was matched and updated.

Screenshots (UI changes only)

image image

@benjitobz
benjitobz force-pushed the feature/calibre-content-server-connector branch 2 times, most recently from dcfa11d to ba8175a Compare September 5, 2026 00:21
Mirror books to a second Calibre content server: push on import, optionally on
library scan pickups, and reflect Chaptarr's own edits and deletions.

The connection is one-way. Deleting a book on the content server is not read
back, and the server that backs a Chaptarr root folder is refused outright,
because Chaptarr manages that library directly and would duplicate into it.

A freshly added record carries the file's embedded metadata until the
canonical write lands, so its mirror id is remembered across that window - a
second push arriving inside it would otherwise fail the author and title
lookup and add the book again. The cover is reconciled against the monitored
edition before it is sent.
A book the connections missed had no way back short of re-importing it. Add a
resend action on the book page and over a selection in the book editor, driven
by one command that takes a list, so a stale id in a selection cannot abort
the rest of the batch.
@benjitobz
benjitobz force-pushed the feature/calibre-content-server-connector branch from 3641874 to 4092aaa Compare September 7, 2026 13:49
The other file-bound toolbar actions grey out when a book is missing; the
resend sat enabled and did nothing.
benjitobz and others added 5 commits September 8, 2026 16:28
Hydrate editions before the resend cover reconcile so it actually runs,
serialize resolve-or-add per book and connection so concurrent formats
cannot create two mirror records, and invalidate the cached mirror id on
every whole-record delete instead of only book deletes.
Implements the IExternalLibraryEditTarget seam so sources like the
Grimmory forwarder can land descriptive metadata and covers on the
mirror record, gated on Push Library Edits. Title and authors stay
Chaptarr's, and the changes dict is built by hand so absent fields
are omitted rather than erased.
Cut the reviewer narration on PushExternalLibraryEdit down to the two
things the code cannot show: title and authors stay Chaptarr's, and absent
payload fields are left out rather than blanked on the mirror. The notes on
the delete-books/0 write probe and on the title-matching rules that gate
deletions stay.

Import NzbDrone.Core.MediaFiles instead of qualifying BookFile inline in
five signatures and on the NotificationBase override, sort the using block
in RePushBookService, and give the identifier assignments the same block
form as the rest of the file.

Drop the per-access try/catch in the BookFileAdded handler: the sibling
handler in this file reads BookFile.Edition.Book directly, and the event
aggregator already wraps and logs every handler call.

Remove the stray note on CalibreChanges.Series, which sat between the
attribute and the property and described the opposite of what
NullValueHandling.Include does.
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