Changelog
Important
- Credential encryption. The key protecting stored passwords and API keys is now derived from the
sessionSecretwith HKDF. qui re-encrypts every stored credential on first start, so take a database backup before upgrading: an older qui cannot read the new format.
Highlights
- Far fewer requests to qBittorrent on big instances. Startup no longer fires one tracker request per torrent, and an instance whose first capability probe failed no longer stays on that per-torrent path for every refresh after (needs qBittorrent 5.1+), the hardlink index reuses cached file lists instead of re-downloading every torrent's files on each rebuild, reannounce filters candidates before fetching trackers and caps at four jobs per instance, and dead tracker favicon hosts back off up to 24 hours instead of hammering DNS. The live stream also keeps your rows on screen through a short error instead of blanking and reconnecting.
- Orphan scan reaches further, deletes safer. New per-instance switches under Scan Scope: Scan Default Save Path, Including Category Paths, and Delete Abandoned Directories. Stray files in the default save path are finally visible, and empty directories left behind by moves show up in the preview. All three are off by default. A scan that could not reach every path is marked Partial scan and skips automatic cleanup.
- Cross-seed: anime, games, manual season packs. Anime episodes match across numbering schemes (absolute
- 81versusS04E15) via the episode map from a linked Sonarr. Releases split into more than 100 RAR volumes (.s01was read as season 1) now apply. The manual match dialog can assemble a season pack from several episodes you already seed. Matches with 100% overlap no longer sit paused for an hour, the Library Scan card counts honestly with a Cross-seeds added line, and an indexer answering a download with a login page no longer poisons the torrent cache. - BDInfo reports from the Content tab. Every Blu-ray Disc gets a BDInfo action that scans in the background and hands you the Quick Summary and Forum blocks for upload forms (needs Local Filesystem Access).
- Torrent table and Content tab. A new toolbar button stretches the Name column to fill the table so the desktop view stops scrolling sideways (on by default, toggle it off to keep your own Name width), the Toggle columns menu has drag handles for reordering, and the Content tab sorts by Name, Progress, Size, or Priority.
- Automations. New Has Skipped Files condition, the category action can target Uncategorized, a slow or failed preview no longer blocks enabling a workflow (Save without preview), and overnight ranges finally work: System Hour between 20 and 6 wraps past midnight instead of matching nothing. Hardlink and missing-file conditions never match when qui cannot read the files.
- Fixes and polish. Unified view actions on a torrent that exists on several instances no longer fan out to all of them (the cross-seed run API also renames
torrentsAddedtocrossSeedsAdded), the sidebar Clear filters button gets a dropdown for sidebar, column, or filters and search, magnet links opened through the browser honour the instance's save path and TMM settings, log viewer and orphan preview timestamps follow your Date & Time preferences, and manual backups no longer error after visiting Automations.
Want a new look? https://github.com/autobrr/qui-community-themes has 24 community themes (Tokyo Night, Dracula, Gruvbox, Rosé Pine, and more). Drop the .css into your themes dir and hit Refresh under Settings > Themes. Sideloading needs a licence key, PRs with your own theme are welcome!
New Features
- fd4d5b3: feat(arr): read and cache the Sonarr episode map (#2537) (@s0up4200)
- 8a28459: feat(automations): add HAS_SKIPPED_FILES condition (#2518) (@s0up4200)
- 6670558: feat(crossseed): assemble season packs from manually selected episodes (#2641) (@s0up4200)
- 709d09d: feat(crossseed): search and match anime episodes through the episode map (#2541) (@s0up4200)
- cc63654: feat(orphanscan): preview every directory a run removes (#2666) (@ColinHebert)
- 7b6398c: feat(orphanscan): scan beyond torrent save paths and clean up empty directories (#2588) (@ColinHebert)
- 13fcc97: feat(security): HKDF-derive the credential key and version ciphertext (#2652) (@com6056)
- 7102e59: feat(torrents): BDInfo Disc reports in the Content tab (#2570) (@s0up4200)
- 9c736ed: feat(torrents): name column stretch mode and menu column reordering (#2674) (@gl0ryus)
- 0f457e6: feat(torrents): sort the Content tab by name, size, progress, or priority (#2547) (@s0up4200)
Bug Fixes
- 9a4c208: fix(automations): allow workflows to clear categories (#2660) (@s0up4200)
- 62ae9a1: fix(automations): fold Unicode in CONTAINS_IN name matching (#2648) (@thejdubb02)
- cf38e0f: fix(automations): keep unknown filesystem conditions from matching (#2643) (@s0up4200)
- 562aeaf: fix(automations): let a slow or failed preview not block enabling a workflow (#2566) (@s0up4200)
- 1488809: fix(automations): wrap BETWEEN ranges on clock fields (#2668) (@s0up4200)
- b5e5e8a: fix(backups): scope run cache updates to backup queries (#2517) (@s0up4200)
- 33b7142: fix(ci): limit Postgres job to integration tests (#2659) (@s0up4200)
- 086258d: fix(crossseed): fetch file lists only for contested duplicate groups (#2573) (@s0up4200)
- ca9e7a7: fix(crossseed): reconcile run counters and count cross-seeds added separately (#2577) (@s0up4200)
- 5b5a72e: fix(crossseed): resume fast verification rechecks that finish between polls (#2558) (@thejdubb02)
- d00bcea: fix(crossseed): search and match absolute-numbered anime episodes (#2533) (@s0up4200)
- 58d26aa: fix(crossseed): stop rewriting the search run results blob on every candidate (#2574) (@s0up4200)
- 411814e: fix(database): register the sqlite connection hook at init (#2589) (@ColinHebert)
- 29c60b6: fix(dirscan): prune tracked files that no longer exist on disk (#2587) (@ColinHebert)
- 8b6c383: fix(gojackett): stop retrying once the caller's context ends (#2650) (@nitrobass24)
- b63500c: fix(i18n): render the correct plural form for six count strings (#2677) (@ColinHebert)
- 7c3a27b: fix(jackett): reject non-torrent download responses (#2640) (@s0up4200)
- 89d8f83: fix(qbittorrent): key the peer fetch on the lowered hash (#2612) (@s0up4200)
- 16311f3: fix(qbittorrent): serialize peer fetch and merge per torrent (#2611) (@s0up4200)
- eea32de: fix(releases): keep S23E19.Episode.1174 names as one episode (#2543) (@s0up4200)
- b308f7c: fix(search): correct the glob examples in the search help (#2670) (@s0up4200)
- e19a6ac: fix(sse): retain page snapshots and avoid unnecessary reconnects (#2656) (@s0up4200)
- f3cea20: fix(stream): prevent desync after missed baselines (#2506) (@Zariel)
- b2462ea: fix(torrents): make filter clearing scopes explicit (#2595) (@s0up4200)
- 56db722: fix(torrents): require targets for unified bulk actions (#2530) (@s0up4200)
- 25e84a9: fix(torrents): seed add-torrent options from preferences on a cold mount (#2653) (@s0up4200)
- ec9fad5: fix(torrents): send instance targets for recheck and reannounce in the unified view (#2528) (@s0up4200)
- 2a28736: fix(torrents): stop re-applying the search client-side in cross-seed filter mode (#2532) (@s0up4200)
- b47ff45: fix(trackericons): back off dead tracker hosts and stop the DNS flood (#2549) (@s0up4200)
- 04cbdb2: fix(web): dismiss path autocomplete on outside pointer interaction (#2526) (@s0up4200)
- 00551e5: fix(web): format timestamps with date/time preferences everywhere (#2519) (@s0up4200)
Other Changes
- 97b852d: chore(deps): bump anthropics/claude-code-action from 1.0.200 to 1.0.210 in the github group (#2562) (@dependabot[bot])
- 15d5f3f: chore(deps): bump the github group with 3 updates (#2679) (@dependabot[bot])
- 6bea480: chore(i18n): remove unreferenced locale blocks (#2676) (@ColinHebert)
- e2268b4: chore(repo): remove unused workflows, artwork, and ReDoc (#2635) (@s0up4200)
- c23dc25: ci(test): cache the embedded Postgres binary (#2673) (@s0up4200)
- 04435ab: docs(agents): add code comment rules (#2647) (@s0up4200)
- 865d26a: docs(agents): one PR per feature, slice commits instead of stacked PRs (#2569) (@s0up4200)
- fe10338: docs(api): update the torrent peers response schema (#2614) (@s0up4200)
- 6e508b2: docs(backups): state what a snapshot does not contain (#2591) (@s0up4200)
- 92b13bc: docs(context): add search candidate, cross-seed added, and due candidate (@s0up4200)
- 938797b: docs: add Disc report glossary terms and ADR 0003 (#2568) (@s0up4200)
- 538147e: docs: require before/after performance results in PRs (#2655) (@s0up4200)
- a7daed1: perf(automations): rebuild the hardlink index from cached file lists (#2590) (@s0up4200)
- 118df89: perf(filesmanager): skip no-op writes in torrent files cache upsert (#2586) (@ColinHebert)
- e2d7d62: perf(proxy): remove duplicate peer fetch (#2604) (@s0up4200)
- fdf4ae3: perf(qbittorrent): enable bulk tracker fetching after client initialization (#2584) (@s0up4200)
- a6518c4: perf(qbittorrent): expire unused peer sync managers (#2605) (@s0up4200)
- 09f4112: perf(qbittorrent): share one app info refresh across concurrent callers (#2593) (@s0up4200)
- bb04ebf: perf(reannounce): narrow tracker fetches and bound jobs (#2596) (@s0up4200)
- 9bab23d: perf(torrents): answer single-hash requests from the cache index (#2594) (@s0up4200)
- d0b8392: refactor(api): drop the dead full_update field from the peers response (#2606) (@s0up4200)
- 572ed6c: refactor(backend): remove unused APIs and helpers (#2633) (@s0up4200)
- cb32fdf: refactor(cache): migrate ttlcache to autobrr/go-cache (#2672) (@s0up4200)
- e981e5d: refactor(crossseed): remove inactive auto-resume policy flag (#2636) (@s0up4200)
- 67753dc: refactor(filesmanager): remove unused cache paths and chunk helpers (#2630) (@s0up4200)
- a5f6a44: refactor(i18n): consolidate locale coverage checkers (#2627) (@s0up4200)
- aa51e4b: refactor(jackett): remove unused APIs and backup plumbing (#2629) (@s0up4200)
- c730414: refactor(notifications): reuse production Notifiarr payload builders (#2639) (@s0up4200)
- 4759870: refactor(web): remove unused APIs and redundant helpers (#2634) (@s0up4200)
- 3bc7649: test(backend): remove copied and inactive test code (#2628) (@s0up4200)
- dae379b: test(i18n): replace source checks with behavior tests (#2638) (@s0up4200)
- 4e7d2cb: test(postgres): run backend suite with embedded Postgres (#2616) (@s0up4200)
- 14a7071: test(qbittorrent): pin list hydration to never call torrents/trackers (#2592) (@s0up4200)
- eae0f73: test(torznab): cover HTTP 500 and unreachable outcomes of the indexer test (#2422) (@nitrobass24)
Full Changelog: v1.28.0...v1.29.0
Docker images
docker pull ghcr.io/autobrr/qui:v1.29.0docker pull ghcr.io/autobrr/qui:latest
What to do next?
- Join our Discord server
Thank you for using qui!