github autobrr/qui v1.34.0

4 hours ago

Changelog

Breaking changes

  • The Dir Scan status endpoint returns a list. GET /api/dir-scan/directories/{id}/status now returns {"runs": [...]}, so a script that reads the old shape must read runs. The webhook endpoint no longer returns 409 for a scan in progress.
  • Relative Move paths are rejected. qui skips an enabled rule whose Move path is relative after the template renders, and it refuses to save that rule. Make the Move path absolute.
  • Invalid Move path templates are rejected. qui refuses to save an enabled rule whose Move path is an invalid template. Fix the template.
  • On Windows, Program Path must be an executable. For a Python, PowerShell, or other script, select the interpreter as Program Path and pass the script path as the first argument. For a shortcut, select its target executable.
  • On Windows, batch and terminal arguments are literal. %NAME% and operators such as & in the argument template of a .bat, .cmd, or terminal program no longer take effect. If the script needs an environment variable, read it in the script.

Highlights

  • Much lighter on qBittorrent 5.2. Tracker health now reads the 5.2 announce flags and no longer fetches the whole library every 60 s, so qui and qBittorrent use 7 to 10 times less CPU when idle.
  • A live details panel. The General, Trackers, and Content tabs update while they are open, and General shows live piece counts on qBittorrent 5.2.
  • Safer deletes. Delete rules skip a torrent while qBittorrent checks it, and the Delete dialog finds the cross-seeds of every selected torrent, also on other local instances.
  • Orphan scan keeps torrent data. It no longer deletes files that a torrent reaches through a symlink, a bind mount, or a hardlink, or the folders that qBittorrent monitors or downloads into.
  • Run a workflow now. Run one saved workflow from its row menu or its dialog, also when the workflow is disabled.
  • Fixes and polish. Dir Scan webhooks search during a full scan, qui migrate utorrent with --replace-path, better cross-seed matching for season folders and HYBRID, category edits keep the download path, no stale progress after a failed sync, and UI polish.

Breaking Changes

  • feat(dirscan)!: let webhook scans search while a full scan runs (#3324) (@s0up4200)
  • fix(automations)!: skip relative move paths and match // paths (#2760) (@ColinHebert)
  • fix(windows)!: pass batch and terminal arguments literally (#3575) (@s0up4200)
  • fix(windows)!: preserve native launches and filesystem safety (#3078) (@Audionut)

New Features

  • feat(automations): expand tag actions to cross-seeds (#2446) (@nitrobass24)
  • feat(automations): run one saved workflow now (#3628) (@s0up4200)
  • feat(clientmigrate): import from uTorrent, remap save paths (#3595) (@zze0s)
  • feat(crossseed): name isolation folders without the hash (#3401) (@s0up4200)
  • feat(fsops): skip an existing hardlink target the exec tier can prove is the same file (#3322) (@nitrobass24)
  • feat(fsops): turn on Write for remote instances (#3238) (@nitrobass24)
  • feat(license): end the offline grace after 7 days (#3445) (@s0up4200)
  • feat(orphanscan): delete orphans on remote instances (#3509) (@com6056)
  • feat(qbittorrent): remove leftover folders on remote instances (#3318) (@s0up4200)
  • feat(qbittorrent): use the 5.2 announce flags for tracker health (#3349) (@s0up4200)
  • feat(stream): change subscriptions on an open stream (#3573) (@s0up4200)
  • feat(stream): skip the view rebuild on server-state-only syncs (#3362) (@s0up4200)
  • feat(web): add useTorrentDetailTab with a live General tab (#3579) (@s0up4200)
  • feat(web): change stream subscriptions without a reopen (#3580) (@s0up4200)
  • feat(web): one page layout for sectioned and single pages (#3403) (@s0up4200)
  • feat(web): reload Content and the piece bar on progress changes (#3586) (@s0up4200)
  • feat(web): reload the Trackers tab on a Tracker health change (#3584) (@s0up4200)
  • feat(web): show live piece counts in General on qBittorrent 5.2 (#3583) (@s0up4200)

Bug Fixes

  • fix(api): log one error line per failed torrent add request (#3624) (@s0up4200)
  • fix(api): stop answering 500 for an unknown instance (#2973) (@com6056)
  • fix(automations): keep files another instance needs (#3600) (@s0up4200)
  • fix(automations): keep other actions off torrents a run deletes (#3006) (@ColinHebert)
  • fix(automations): skip delete while qBittorrent checks a torrent (#3493) (@s0up4200)
  • fix(build): send the themes token as a password in the clone URL (#3323) (@s0up4200)
  • fix(clientmigrate): ignore structured peers2 in Transmission resume files (#3519) (@zze0s)
  • fix(clientmigrate): keep Transmission renames on import (#3594) (@zze0s)
  • fix(crossseed): a CRC tag on one name never decides a match (#3467) (@s0up4200)
  • fix(crossseed): keep partial cross-seeds at their save path (#3417) (@s0up4200)
  • fix(crossseed): match announce titles that keep periods (#3077) (@s0up4200)
  • fix(crossseed): match season folders and batches by their files (#3468) (@s0up4200)
  • fix(crossseed): match shows whose title holds an ignore word (#3399) (@s0up4200)
  • fix(crossseed): name assembled season packs in RSS notifications (#2985) (@GertJanH)
  • fix(crossseed): pass one-sided HYBRID within size tolerance (#3133) (@s0up4200)
  • fix(crossseed): read a season folder name from its files (#3395) (@qui-rabbit[bot])
  • fix(crossseed): retry a failed post-add recheck from the queue (#2824) (@s0up4200)
  • fix(crossseed): run External Program on every cross-seed add (#3419) (@s0up4200)
  • fix(dirscan): search every loose episode in a season folder (#3611) (@s0up4200)
  • fix(dirscan): wait 60 s between the searches for two items (#3319) (@s0up4200)
  • fix(docker): keep local .env files out of the build context (#3333) (@s0up4200)
  • fix(instances): try new settings at once after an instance edit (#3491) (@s0up4200)
  • fix(jackett): hold the indexer slot until a stuck search returns (#2823) (@s0up4200)
  • fix(jackett): read the stuck-search warning delay once (#3366) (@s0up4200)
  • fix(orphanscan): drop duplicate scan roots on remote instances (#3175) (@cestercian)
  • fix(orphanscan): keep scanning a root when a folder vanishes (#3503) (@s0up4200)
  • fix(orphanscan): keep the files of a save path that is a symlink (#3483) (@com6056)
  • fix(orphanscan): keep the folders that qBittorrent monitors (#3486) (@s0up4200)
  • fix(orphanscan): match paths below a root ignore path (#3174) (@cestercian)
  • fix(orphanscan): never remove a download folder as abandoned (#3446) (@com6056)
  • fix(orphanscan): never take a nested scan root as a disc unit (#3418) (@com6056)
  • fix(orphanscan): protect hardlinked paths to a torrent's file (#3487) (@com6056)
  • fix(orphanscan): protect in-use aliases regardless of walk order (#3448) (@com6056)
  • fix(orphanscan): prune scan roots below a UNC share root (#3416) (@com6056)
  • fix(orphanscan): start one run when triggers race (#2974) (@com6056)
  • fix(qbittorrent): keep notifications in a mass import (#3372) (@s0up4200)
  • fix(qbittorrent): keep the download path on a category edit (#3371) (@com6056)
  • fix(qbittorrent): log one error line per bulk tracker action (#3625) (@s0up4200)
  • fix(qbittorrent): name category folders the way qBittorrent 5.3 does (#3338) (@s0up4200)
  • fix(qbittorrent): skip folder cleanup below a symlink (#3346) (@com6056)
  • fix(qbittorrent): stop cleanup at a category's download folder (#3415) (@com6056)
  • fix(qbittorrent): update Unified view rows without the stream (#3574) (@s0up4200)
  • fix(sse): show why live updates paused (#3327) (@s0up4200)
  • fix(stream): stop a data race on the sync retry delay (#3581) (@s0up4200)
  • fix(sync): ask for a full update after a failed sync (#3328) (@s0up4200)
  • fix(torrents): hide new unregistered torrents from Tracker Error (#3616) (@s0up4200)
  • fix(torrents): keep loaded pages fresh outside stream coverage (#2507) (@Zariel)
  • fix(web): delete chosen cross-seeds on a select-all delete (#3170) (@thejdubb02)
  • fix(web): distinguish duplicate translated dropdown labels (#3097) (@ColinHebert)
  • fix(web): end select all on a plain click and name large deletes (#3368) (@s0up4200)
  • fix(web): fit the reannounce card on narrow screens (#2976) (@com6056)
  • fix(web): one share and speed limit dialog for both layouts (#3485) (@s0up4200)
  • fix(web): show tracker health the same way in every view (#3367) (@s0up4200)
  • fix(web): stop the torrent search placeholder from being cut off (#3544) (@s0up4200)
  • fix(web): stop two tabs from flipping a client setting (#3427) (@s0up4200)

Other Changes

  • chore(crossseed): block direct AddTorrent calls outside Adder (#3428) (@s0up4200)
  • chore(deps): bump autobrr/rls to v0.10.0 (#3252) (@s0up4200)
  • chore(deps): bump body-parser from 1.20.6 to 1.20.9 in /documentation (#3476) (@dependabot[bot])
  • chore(deps): bump fast-uri from 3.1.5 to 3.1.9 in /documentation (#3462) (@dependabot[bot])
  • chore(deps): bump fast-uri from 3.1.8 to 3.1.9 in /web (#3460) (@dependabot[bot])
  • chore(deps): bump follow-redirects from 1.16.0 to 1.16.1 in /documentation (#3344) (@dependabot[bot])
  • chore(deps): bump github.com/go-jose/go-jose/v4 from 4.1.4 to 4.1.6 (#3589) (@dependabot[bot])
  • chore(deps): bump goreleaser/goreleaser-action from 7.2.3 to 7.3.0 in the github group (#3455) (@dependabot[bot])
  • chore(deps): bump launch-editor from 2.14.1 to 2.14.2 in /documentation (#3345) (@dependabot[bot])
  • chore(deps): bump serialize-javascript from 7.1.2 to 7.1.3 in /web (#3461) (@dependabot[bot])
  • chore(deps): bump the golang group across 1 directory with 13 updates (#3337) (@dependabot[bot])
  • chore(deps): bump the npm group across 1 directory with 4 updates (#3356) (@dependabot[bot])
  • chore(deps): bump the npm group across 1 directory with 45 updates (#3357) (@dependabot[bot])
  • chore(deps): bump undici from 7.30.0 to 7.30.1 in /documentation (#3459) (@dependabot[bot])
  • chore(make): run the lint ratchet in precommit (#3507) (@s0up4200)
  • ci(goreleaser): render the changelog template on pull requests (#3315) (@s0up4200)
  • ci(implement): build ready-for-agent issues on dispatch (#3391) (@s0up4200)
  • ci(implement): refuse an issue that open work blocks (#3393) (@s0up4200)
  • ci(implement): start without the env scrub, fail empty runs (#3394) (@s0up4200)
  • ci(implement): take the PR title and body as structured output (#3396) (@s0up4200)
  • ci(lint): hold four new linters to a shrink-only allowlist (#3380) (@s0up4200)
  • ci(ratchet): add a daily bot that fixes one allowlist file (#3381) (@s0up4200)
  • ci(release): leave refactor PRs out of the Highlights prompt (#3630) (@s0up4200)
  • ci(release): publish Docker image tags only after GoReleaser succeeds on a tag (#3314) (@s0up4200)
  • ci(release): write highlights only about changes users get (#3379) (@s0up4200)
  • ci(triage): move new reports to the daily sweep, add anime label (#3556) (@s0up4200)
  • docs(adr): give the duplicate ADRs 0004 and 0016 new numbers (#3465) (@s0up4200)
  • docs(agents): PR title length and precommit on each push (#3406) (@s0up4200)
  • docs(agents): add rules for low-value tests and real sleeps (#3520) (@s0up4200)
  • docs(agents): fix contradictions in agent and contributor docs (#3521) (@s0up4200)
  • docs(agents): flag changes that depart from an ADR (#3554) (@s0up4200)
  • docs(agents): send docs changes for remote instances to #3330 (#3331) (@s0up4200)
  • docs(agents): send docs cherry-picks to main through a PR (#3378) (@s0up4200)
  • docs(qbittorrent): document the qBittorrent 5.3 RSS fields (#3339) (@s0up4200)
  • docs(readme): add Macroscope banner (#3567) (@s0up4200)
  • docs(standards): use useReducer for state that changes together (#3608) (@s0up4200)
  • docs: add a security policy and OSS Scanner build files (#3329) (@s0up4200)
  • docs: name the ! title rule in the PR template and the worktree install step (#3325) (@s0up4200)
  • docs: record design rules and gotchas in docs and code comments (#3321) (@s0up4200)
  • docs: send outside contributors to Discussions (#3376) (@s0up4200)
  • docs: send outside contributors to Discussions (#3376) (#3377) (@s0up4200)
  • perf(stream): send an idle frame to quiet views (#3566) (@s0up4200)
  • perf(web): slow the stream fallback polls (#3576) (@s0up4200)
  • refactor(api): use structs for external program JSON replies (#3627) (@s0up4200)
  • refactor(automations): Run plan for Actions with no expansion (#3504) (@s0up4200)
  • refactor(automations): export marks in the Run plan (#3505) (@s0up4200)
  • refactor(automations): move and category in the Run plan (#3506) (@s0up4200)
  • refactor(automations): one delete selection for run and preview (#3495) (@s0up4200)
  • refactor(automations): one row per Condition field (#3638) (@s0up4200)
  • refactor(automations): read overlap files through filesReader (#3501) (@s0up4200)
  • refactor(automations): the category preview reads the Run plan (#3603) (@s0up4200)
  • refactor(automations): the tag preview reads the Run plan (#3609) (@s0up4200)
  • refactor(crossseed): apply keeps the stored search verdict (#3440) (@s0up4200)
  • refactor(crossseed): apply one source torrent's search results (#3615) (@s0up4200)
  • refactor(crossseed): every stored verdict names its listing (#3451) (@s0up4200)
  • refactor(crossseed): give the file layout check fixed roles (#3458) (@s0up4200)
  • refactor(crossseed): local Match paths ask the Match verdict (#3466) (@s0up4200)
  • refactor(crossseed): move the link-mode add onto the Adder (#3422) (@s0up4200)
  • refactor(crossseed): move the regular add onto an Adder (#3421) (@s0up4200)
  • refactor(crossseed): move the season-pack add onto the Adder (#3423) (@s0up4200)
  • refactor(crossseed): one Aligner for cross-seed and Dir Scan (#3494) (@s0up4200)
  • refactor(crossseed): one Match verdict decides search matches (#3431) (@s0up4200)
  • refactor(crossseed): one Search scope for a source torrent (#3518) (@s0up4200)
  • refactor(crossseed): one settle module for every add (#3400) (@s0up4200)
  • refactor(crossseed): partial pool coordinator as its own type (#3604) (@s0up4200)
  • refactor(crossseed): read verification from typed differences (#3439) (@s0up4200)
  • refactor(crossseed): season pack check asks the Match verdict (#3464) (@s0up4200)
  • refactor(dirscan): compare Title keys in the title check (#3469) (@s0up4200)
  • refactor(dirscan): move the Dir Scan add onto the Adder (#3426) (@s0up4200)
  • refactor(lint): fix errchkjson in client_api_keys.go (#3597) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in dirscan.go (#3447) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in health.go (#3614) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in qbittorrent_info.go (#3390) (@qui-rabbit[bot] and @qui-ratchet[bot])
  • refactor(lint): fix errchkjson in qbtstub.go (#3517) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in service.go (#3484) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in service.go (#3637) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in swagger.go (#3570) (@qui-rabbit[bot])
  • refactor(lint): fix errchkjson in version.go (#3420) (@qui-rabbit[bot])
  • refactor(lint): fix nilerr in crossseed.go (#3386) (@qui-rabbit[bot] and @qui-ratchet[bot])
  • refactor(lint): fix nilerr in service.go (#3388) (@qui-rabbit[bot] and @qui-ratchet[bot])
  • refactor(lint): fix nilerr in torznab_cache.go (#3387) (@qui-rabbit[bot] and @qui-ratchet[bot])
  • refactor(lint): mark the last nilerr returns as deliberate (#3389) (@s0up4200)
  • refactor(orphanscan): ask one module about Protected paths (#3405) (@s0up4200)
  • refactor(qbittorrent): decide tracker health in one classifier (#3619) (@s0up4200)
  • refactor(qbittorrent): keep tracker health in one snapshot (#3620) (@s0up4200)
  • refactor(qbittorrent): one module returns an instance's folders (#3475) (@s0up4200)
  • refactor(web): build one action target from a selection (#3621) (@s0up4200)
  • refactor(web): keep Select all mode in one reducer (#3488) (@s0up4200)
  • refactor(web): one torrent list controller for both layouts (#3636) (@s0up4200)
  • test(api): remove real waits in the API handler tests (#3542) (@s0up4200)
  • test(crossseed): prune low-value cross-seed tests (#3535) (@s0up4200)
  • test(crossseed): remove real waits in the cross-seed tests (#3545) (@s0up4200)
  • test(database): drop the sleep from TestTransactionSerialization (#3622) (@s0up4200)
  • test(fsops): accept every cause in the sftp drop-during-ReadDir walk test (#3316) (@s0up4200)
  • test(jackett): remove real waits in the scheduler tests (#3541) (@s0up4200)
  • test(middleware): fix flaky API key tests on Windows (#3610) (@s0up4200)
  • test(models): run the Torznab cache test on the real clock (#3540) (@s0up4200)
  • test(qbittorrent): fix a flaky tracker-health kick test (#3369) (@s0up4200)
  • test(qbittorrent): make the folder-cleanup tests fast (#3536) (@s0up4200)
  • test(qbittorrent): remove real waits in client and sync tests (#3543) (@s0up4200)
  • test(sse): remove real waits in the live-update tests (#3546) (@s0up4200)
  • test: prune low-value API, automations, fsops, and web tests (#3539) (@s0up4200)
  • test: prune low-value qBittorrent and Jackett tests (#3538) (@s0up4200)
  • test: remove real waits in SSH, backup, and orphan scan tests (#3547) (@s0up4200)
  • test: remove real waits in the small packages (#3537) (@s0up4200)

Full Changelog: v1.33.1...v1.34.0

Docker images

  • docker pull ghcr.io/autobrr/qui:v1.34.0
  • docker pull ghcr.io/autobrr/qui:latest

What to do next?

Thank you for using qui!

Don't miss a new qui release

NewReleases is sending notifications on new releases.