github vavallee/bindery v0.5.0
v0.5.0 — Audiobook support + Readarr-parity UX + migration paths

latest releases: v1.15.3, v1.15.2, v1.15.1...
one month ago

Audiobook support + Readarr-parity UX + migration paths

Import cleanup

  • Ebook import no longer leaves the SABnzbd job folder behind. After every book file matches bindery's extension set and moves cleanly, the importer removes the source directory — PAR2, NFO, SFV, NZB, and sample leftovers go with it. Partial-failure runs are untouched so the files remain for investigation.
  • Audiobook import handles destination collisions. UniqueDir resolves {Author}/{Title} ({Year}) against the filesystem and appends (2), (3), … when a prior import or manual copy already occupies the slot. Previously MoveDir hard-failed on any collision and the download stuck at Completed forever.
  • SABnzbd history is pruned once bindery owns the files. New DeleteHistory(nzoID, deleteFiles=false) on the SAB client is called after each successful import so completed rows stop accumulating in SAB's UI with stale storage paths.
  • Remote path mapping (BINDERY_DOWNLOAD_PATH_REMAP). When SABnzbd and bindery run in separate containers with the shared storage mounted at different paths, SAB would report a completed job at /downloads/complete/X and bindery would fail to find it under its own mount point — logging no book files found in download and leaving files in SAB's completed dir forever. The new env var accepts comma-separated from:to pairs (e.g. /downloads:/media), applied longest-prefix-first to each path before the importer walks it. Same-filesystem installs leave it unset and see no behaviour change.

Audiobook support

  • Books now carry a media_type (ebook | audiobook) that drives indexer categories, ranking, library destination, and UI badges. Flip per-book inline on the Wanted page or via the Book detail page.
  • Search pipeline: filterCategoriesForMedia narrows indexer queries to the Newznab audio tree (3030) for audiobook books and the books tree (7000 range) for ebooks, with a fallback to the standard category when the indexer's configured set has nothing matching.
  • Ranking applies a −500 media-type-mismatch penalty and +250 for ASIN exact matches parsed from release titles. isAudiobookFormat recognises m4b / m4a / mp3 / flac / ogg.
  • Import pipeline: audiobook grabs move the entire download directory as one unit via MoveDir (multi-part m4b / mp3 + cover art + cue sheet stay together) into BINDERY_AUDIOBOOK_DIR (falls back to BINDERY_LIBRARY_DIR if unset). Naming template defaults to {Author}/{Title} ({Year}) — preserves original filenames inside.
  • Audnex metadata provider (api.audnex.us, no auth) fetches narrator, duration, cover, and description by ASIN. Endpoint: POST /api/v1/book/{id}/enrich-audiobook.
  • Release parser extracts Audible-shaped ASINs (B[0-9A-Z]{9}) from NZB titles; UNABRIDGED / ABRIDGED / RETAIL edition flags now factor into ranking.
  • Raw per-article Usenet postings (.part09.rar, .vol003+004.par2, .sfv, yEnc, [12/22] brackets) filtered out of search results before ranking so multi-part noise no longer buries clean [M4B] releases.

Readarr-parity UX

  • Book and author detail pages at /book/:id and /author/:id — routed, deep-linkable, replace the previous click-opens-modal flow. Book detail hosts cover, metadata, format toggle, ASIN field, audnex enrich button, inline search-and-grab, and per-book history. Author detail shows portrait + stats + description + Monitored/Refresh/Delete actions + their books as a mini grid.
  • Grid / Table view toggle on Books and Authors pages (persists per-page in localStorage). Books table: thumbnail + title, author, year, type, status with responsive column hiding on phones. Authors table: avatar + name, book count, rating, Monitored toggle, inline Refresh/Delete.
  • History page adds Size and Type columns (desktop table + mobile card) — type auto-detected from the release title's format tokens.
  • Books tab: audiobook corner badge on cards; inline <select> per row on Wanted persists media type via PUT /api/v1/book/{id}.

Migration paths

  • POST /api/v1/migrate/csv — upload a newline-separated list of author names or a name,monitored,searchOnAdd CSV. Each name resolved via OpenLibrary.
  • POST /api/v1/migrate/readarr — upload readarr.db. Authors re-resolved via OpenLibrary (Goodreads IDs aren't portable since bookinfo.club is dead); Indexers / Download clients / Blocklist entries port structurally.
  • bindery migrate csv <path> and bindery migrate readarr <path> CLI subcommands — exit with JSON summary.
  • Settings → Import tab with file uploads and per-section result cards showing requested / added / skipped / failures.

Infrastructure

  • development branch joins main in CI — builds push :development + :dev-<sha> images and auto-bump charts/bindery/values.yaml. Point ArgoCD targetRevision at development to follow dev builds.
  • Version badge shows dev-<sha> on development builds, sha-<sha> on main builds, or v0.4.x on tagged releases.
  • File download endpoint (/api/v1/book/{id}/file) now streams a zip when the book's file_path is a directory (audiobook folders come down as a single archive).
  • Background download-status poll tightened from 60s to 15s so imported status lands in near-real-time after SABnzbd finishes.
  • Fixed a rankResults bug where precomputed scores were read from stale indices during the in-place sort — composite ranking effectively fell back to indexer-return order. Now zips score with result and sorts pairs. Regression test added.

Added (smaller)

  • /book/{id}/enrich-audiobook endpoint (audnex).
  • Foreign-language tag filter now word-boundary-anchored (the tag RUSSE no longer substring-matches inside RUSSELL).
  • Book PUT handler accepts mediaType / asin / narrator fields (was silently dropping them).
  • Delete downloaded files from the UI. Book detail page gains a red "Delete file" action that wipes the on-disk file (ebook) or folder (audiobook) and flips the book back to wanted, plus a "Delete book + files" action that removes the record and its files in one go. New endpoints: DELETE /api/v1/book/{id}/file and DELETE /api/v1/book/{id}?deleteFiles=true. A bookFileDeleted history event is recorded so the deletion is auditable.
  • Skip OpenLibrary "works" whose title equals the author's name. An upstream OL data-quality bug occasionally emits works (e.g. OL29342228W for Jared Diamond) where the Work record was never given a title and the API falls back to the author's name. These polluted the Wanted page and produced nonsense destination folders like Jared M. Diamond/Jared M. Diamond (). FetchAuthorBooks now filters them out at ingest time and counts the skips in its summary log.

Don't miss a new bindery release

NewReleases is sending notifications on new releases.