Added
- Post-import drop folder for external library tools (#941) — a new way to hand finished downloads to a tool that owns your library (Calibre-Web-Automated, Calibre auto-ingest, Storyteller). With Import Mode set to External, Bindery now renames each completed download into a configurable drop folder (copy or hardlink — never a move, so torrents keep seeding) instead of leaving it in the download directory, then reconciles the managed copy the external tool produces on the next library scan. Previously this was impossible: normal modes wrote into the library and the CWA mirror (so the file landed in both places and CWA fought Bindery over the library dir), while plain External mode left the file unrenamed in the download dir. Configurable layout (
flatfile in the folder root vstemplated{Author}/{Title}/…tree) and placement (copy/hardlink) under Settings → General → File Naming. New settingsimport.drop_folder/import.drop_layout/import.drop_link_mode; the existingcwa.ingest_pathmirror is unchanged for the "Bindery owns the library" topology. Fixes the recurring CWA ingest-routing reports and is the foundation for Storyteller pair-gated handoff (#942). See docs/DEPLOYMENT.md → "Handing off to another library tool". - Outbound proxy support (#986) — route Bindery's remote-facing outbound HTTP through an
http/https/socks5proxy viaBINDERY_OUTBOUND_PROXY(e.g. a VPN container's Privoxy on:8118, orsocks5://gluetun:1080), the same capability Sonarr/Radarr expose. In scope: indexer searches, metadata/cover providers, webhook notifications, and the telemetry ping; download clients and OIDC discovery stay direct. LAN / loopback / single-label destinations (e.g. a Dockerprowlarr/jackett) are dialled direct by default so a local indexer manager stays reachable — tune withBINDERY_OUTBOUND_PROXY_BYPASS_LOCAL(defaulttrue) andBINDERY_OUTBOUND_PROXY_NO_PROXY(comma-separated hosts / domain suffixes / CIDRs). Parsed once at startup into a shared, proxy-aware transport ininternal/httpsec; credentials travel in the URL userinfo and are never logged. Env-var only — no new dependency (stdlib dials all three schemes). - Refresh metadata for every author (#863) — a one-click "Refresh all metadata" background job on the Authors page that re-fetches each author's metadata and catalogue, with progress that survives a page reload. Useful after a first import to backfill descriptions, covers, and missing books.
- Per-indexer priority is now editable in the UI (#1009) — the add/edit indexer form exposes the priority the searcher already uses to break ties when the same release is found on multiple indexers (e.g. prefer your Usenet indexers over torrent ones). Manually-added indexers previously had no way to set it, so it was stuck at 0; default is unchanged.
Changed
- Loopback URLs are now allowed for admin-configured service endpoints — download clients, indexers, Prowlarr, the Audiobookshelf base URL, and the Calibre plugin URL now accept
http://127.0.0.1:…/localhost(newPolicyLANLoopbackSSRF tier). Previously the SSRF guard blocked all loopback with no escape hatch, which made a legitimate, common topology impossible: a companion service bound to127.0.0.1, or both containers onnetwork_mode: host, could not be reached (e.g. SABnzbd on127.0.0.1:50155was rejected with "url not allowed: points to loopback address"). These endpoints are admin-only and CSRF-gated, so the loopback block bought ~no security. Untrusted paths are unchanged: proxied cover images and outbound webhooks still block loopback, and link-local + cloud-metadata (e.g.169.254.169.254) remain blocked everywhere. The release/torrent download URLs returned by indexers also still block loopback (a malicious indexer must not be able to point Bindery at internal services).
Fixed
- Transmission: indexer links that redirect to a magnet now work (#1006) — public trackers (The Pirate Bay, Knaben, …) surfaced via Prowlarr/Jackett often serve an
http(s)download link that 30x-redirects to amagnet:URI. Bindery fetched that link with Go's HTTP client, which tried to follow the redirect and failed withunsupported protocol scheme "magnet", so the grab never reached Transmission. The Transmission client now follows redirects manually (re-validating each hop against the SSRF policy) and hands a redirected magnet straight to Transmission'sfilenamearg — matching how the qBittorrent client already behaves (internal/downloader/transmission/client.go). - Library scan now records a result on early returns (#965) — when the library directory was literally unset, or the book listing failed mid-scan,
ScanLibraryreturned without persisting anything, so the Settings → General "Library Scan" section kept showing a stale prior scan instead of reflecting the failure (and the #962 "no files found" warning never fired for an unset directory). Both paths now persist a scan result carrying ascan_errormessage ("library directory not configured" / "scan failed: …") that the UI renders the same way as other scan-outcome warnings. Additive, backward-compatible result field (scan_error); the matching logic is unchanged (internal/importer/scanner.go). - Retired the dead CSV
searchOnAddcolumn (#966) — after CSV import began always fetching each author's catalogue (#963), the optional thirdsearchOnAddcolumn no longer gated anything and never triggered downloads. It is now dropped from the documented format and treated as ignored. The parser stays lenient, so existing users' three-column files keep importing unchanged; the dead field/plumbing is removed (internal/migrate/csv.go). - Backlist books no longer show a misleading "Wanted" pill (#977) —
statusandmonitoredare orthogonal (every book startsstatus=wanted; backlist siblings are added unmonitored), but the status pill renderedstatusalone, so an unmonitored backlist book read "Wanted" while correctly never appearing on the Wanted page (which listsstatus=wanted AND monitored). A sharedbookStatusBadgehelper now makes the pill monitored-aware across the book detail page, book lists, and author rows:wanted+ monitored → "Wanted";wanted+ unmonitored → "Not monitored" (muted). No status/model/DB change. - Authors and Books pages now reach past the first 100 entries (#1010) — the list, search, sort, and filters are applied server-side and paginated, so libraries with more than 100 authors or books are fully browsable. Previously only the first page loaded, author/book name search was limited to that page, and the footer always read "1–100 of 100". Author/book name search is now matched on the server (book search also matches the author's name).