Skip to content

v2.2.0 — Bazarr-parity force/ignore controls, per-title ignore, and a deep pass on reliability

Choose a tag to compare

@github-actions github-actions released this 22 Jun 12:53
7d3ea2e

CRITICAL — do not use this release. Its container entrypoint runs a recursive chown -R /data over the mounted volume, destroying ownership of a shared media library (and any co-located service, e.g. Nextcloud) on upgrade — see #369. Upgrade to v2.2.1, which only ever reconciles subarr's own files.


Bazarr-parity force/ignore controls, per-title ignore, and a deep pass on reliability. This release closes the long-running #317 trio — blacklist a bad sub, fill forced-only gaps, and find the controls that were scattered across the app — adds per-title ignore, and hardens the queue, database, Plex client, and event loop after heavy real-world use.

Added

  • Blacklist a bad Bazarr sub, with a history panel (#317 Slice A). When a provider-downloaded subtitle is broken, you can now blacklist it so Bazarr stops re-fetching the same release. A shared Blacklist panel opens from Aftercare (on the "this sub is bad" row) and from the Library tree (on any video file), lists that file's Bazarr download history, and blacklists the offending provider sub through Bazarr's existing API. Built and verified against the live Bazarr /api/episodes/history schema. Only real provider downloads are blacklistable — manual uploads are left alone.
  • Transcribe a full sub anyway on forced-only files (#317 Slice B). Files whose only embedded subtitle is forced-only were shown but skipped (the "subgen will skip (forced-only)" chip). Each such row now gets a "Transcribe full sub" button that tells subgen to ignore the forced-only track for that one file and generate a complete subtitle — no global IGNORE_FORCED_SUBTITLES flip. The request rides the normal pending queue, so GPU throttling, provenance, and the Bazarr scan trigger all still apply, and it survives a restart (the flag is persisted). Requires the subarr-subgen image shipping patch v4.15 (ghcr.io/coaxk/subarr-subgen:2026.05.3-r10 or newer); on older subgen the bucket keeps the old "set the global knob" guidance.
  • A home for the scattered subtitle controls (#317 Slice C). Force, ignore, and language controls live in the spots where you actually use them — but they were hard to find as a set. A new "Other subtitle controls" directory card on the Rules page names each family in plain terms and links to where it lives (forced subtitles to Coverage, ignored titles to Library, language rules to Settings and Review, audio-language review to Review). Plus a few cross-links where the instinct lands, like Settings language rules to Review and the Coverage forced-only bucket to the hub. Nothing was moved or duplicated — it's signposting only.
  • Per-title ignore, inline (#316). Tell subarr "I don't want subs here" directly on a Library tree row or from the Review surface. Ignoring a folder suppresses the whole series prefix; ignoring a file suppresses just that file. Ignored rows are visibly muted, and descendants of an ignored folder show "ignored ↑" instead of a redundant control. Offered on real titles only, not category roots or sidecars.
  • Bulk Swap / Dismiss for track-mismatch shows (#310). After the Review TV/Movies split, track-mismatch rows still had to be handled one at a time. Select-all now covers them, and the bulk bar offers Swap all and Dismiss all. Each swap is re-validated server-side against a live probe, per-file failures (non-MKV, unflagged, already-correct) are reported rather than fatal, and the coverage cache refreshes once at the end. (This also fixed a latent bug where single-file track swaps were always 502-ing on a wrong Path import.)
  • Per-sweep reading-speed bar in the Tuning Lab (#314). The CPS (characters-per-second) threshold the readability judge scores against is now tunable per sweep, with a "Reading-speed bar (CPS)" field (Comfortable / Critical, prefilled 20/25). Every recipe in a run is judged against the same bar so rankings stay meaningful. Aftercare's own CPS flagging stays at the 20/25 default — tuning lives in the Lab.
  • Aftercare bulk-acknowledge (#313). A first-run library audit can produce thousands of aftercare items, and they could only be cleared one click at a time. An "Acknowledge all" button now clears every pending item (respecting the current source filter) in a single pass. The confirm dialog spells out the scope and reminds you that subtitle files are untouched.
  • Review split into TV Shows and Movies (#309). The audio-language Review list is now grouped into separate TV Shows and Movies sections instead of one flat list.
  • Database backup on demand, with a deep integrity check (#291). The Health page gains a DB maintenance card: "Back up database now" writes a clean, defragmented, timestamped copy (atomic VACUUM INTO, keeping the 5 most recent) and "Run full integrity check" runs a deep PRAGMA integrity_check. If the database-integrity health pill goes unhealthy, a callout surfaces right there urging a backup before you make changes. Advisory only — nothing is write-blocked.

Fixed

  • The UI no longer freezes under load (#308). A dogfood report of sluggishness traced to /api/queue doing a synchronous directory scan plus a stat per sibling file for every skipped row, on every poll — over a NAS mount that froze the single event loop ~1.5s every few seconds, stalling every concurrent request. That filesystem work (and the dashboard's full probe-table load) now runs off the event loop, and a new event-loop stall monitor stays in as standing observability. Live result: the recurring multi-second stalls went to zero. A related idle-state fix skips the docker-logs read in /api/queue when nothing is processing (#307).
  • Database durability hardening (#291, #302). Closed a migration race, re-issue WAL mode correctly, and warn on NFS-backed databases where SQLite locking is unreliable.
  • Plex client robustness (#290, #300, #295). Added connection pooling and a circuit breaker so a flaky Plex doesn't hang requests, with breaker open/recover logged, a non-JSON contract for base _post/_put, and a Radarr movieId fan-out fix.
  • Queue and provenance reconciliation (#287, #301, #297). Orphaned SUBMITTED queue rows are reconciled when the feeder boots, and open provenance rows are de-duplicated with a correct first-stamp on completion.
  • Telemetry hardening (#289, #296). The telemetry payload is now shape-locked and the task-health reporter is supervised so it can't fail silently.
  • Auth hardening (#292, #293). Added a password-length DoS cap, equalized login timing to resist user-enumeration, and improved setup-race logging.
  • Logs page tells you when it can't reach Docker (#328). Instead of an empty or confusing view, the Logs page now shows a clear panel when the Docker socket is unavailable.
  • httpx no longer floods the info log (#325). Routine health-poll 200s were spamming the info log; they're now quiet.
  • Onboarding is re-enterable (#318, #320). You can re-enter the onboarding flow to reconfigure instead of being locked out after first setup.
  • Smaller fixes. Indent Gaps TV shows under their "TV Shows" header (#312); the aftercare repeats chip only flags at the backend threshold (#315); the coverage-cache health threshold now accounts for refresh build time (#303); prune orphan update-checker product rows, including the stale vanilla-subgen row (#306); coverage Radarr lookup by id with a capped Sonarr fan-out (#286); arena delete now cancels the live task and blocks resurrection (#283); path and subgen-client robustness (#285, #288); plus arena concurrency hardening and a documented pre-merge review policy (#284).

Internal

  • SPA bundles are now auto-rebuilt by a pre-commit hook, closing the recurring bundle-drift problem (#332).