-
-
Notifications
You must be signed in to change notification settings - Fork 52
fix(crossseed): enforce resolution and language matching with sensible defaults #855
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…e defaults Previously, resolution and language were only compared when both releases had explicit values, allowing false matches like FRENCH.WEB matching MULTi.1080p.WEB. Changes: - Resolution: now requires match, with exception for SD (480p/576p) vs empty since many SD releases omit explicit resolution tags - Language: now requires match, with exception for empty vs ENGLISH since most English releases omit language tags entirely Fixes #688
WalkthroughLoosens release matching in the cross-seed service to treat empty resolutions as matching known SD values and to treat empty language as equivalent to English in specific cases; adds unit tests covering these resolution and language scenarios. Changes
Sequence Diagram(s)(Skipped — changes are localized matching logic and tests, not a multi-component sequential flow.) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Repository UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
internal/services/crossseed/matching.go (1)
236-257: Logic is correct; consider simplifying the control flow.The SD resolution exception correctly addresses issue #688. However, the empty if-body pattern (lines 253-254) is a minor code smell. Consider inverting the condition for cleaner flow:
🔎 Suggested refactor
if sourceRes != candidateRes { - // rls omits resolution for many SD releases (e.g. "WEB" without "480p"), so - // treat an empty resolution as a match only when the other side is clearly SD. isKnownSD := func(res string) bool { switch strings.ToUpper(strings.TrimSpace(res)) { case "480P", "576P", "SD": return true default: return false } } - if (sourceRes == "" && isKnownSD(candidateRes)) || (candidateRes == "" && isKnownSD(sourceRes)) { - // allow SD-vs-empty - } else { + // rls omits resolution for many SD releases (e.g. "WEB" without "480p"), so + // treat an empty resolution as a match only when the other side is clearly SD. + sdVsEmpty := (sourceRes == "" && isKnownSD(candidateRes)) || (candidateRes == "" && isKnownSD(sourceRes)) + if !sdVsEmpty { return false } }internal/services/crossseed/matching_resolution_language_test.go (1)
50-62: Consider adding tests for 576p and "SD" resolution.The SD exception tests only cover 480p, but the
isKnownSDhelper also accepts "576P" and "SD". Adding test cases for these would ensure complete coverage of the resolution exception logic.🔎 Additional test cases
{ name: "empty resolution matches 576p (SD exception)", sourceName: "Show.S01E01.WEB-DL-GROUP", candidateName: "Show.S01E01.576p.WEB-DL-GROUP", wantMatch: true, }, { name: "empty resolution matches SD (SD exception)", sourceName: "Show.S01E01.WEB-DL-GROUP", candidateName: "Show.S01E01.SD.WEB-DL-GROUP", wantMatch: true, },
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
internal/services/crossseed/matching.gointernal/services/crossseed/matching_resolution_language_test.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: s0up4200
Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go:209-212
Timestamp: 2025-11-28T20:32:30.126Z
Learning: Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go
Learning: The cross-seed recheck-resume worker intentionally runs for the process lifetime and keys pending entries by hash only. This is acceptable under the current constraint that background seeded-search runs operate on a single instance at a time; graceful shutdown and instanceID|hash keying are deferred by design.
Learnt from: s0up4200
Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go:2415-2457
Timestamp: 2025-11-28T22:21:20.730Z
Learning: Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go
Learning: The determineSavePath function intentionally includes a contentLayout string parameter for future/content-layout branching and API consistency. Its presence is by design even if unused in the current body; do not flag as an issue in reviews.
📚 Learning: 2025-11-28T20:32:30.126Z
Learnt from: s0up4200
Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go:209-212
Timestamp: 2025-11-28T20:32:30.126Z
Learning: Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go
Learning: The cross-seed recheck-resume worker intentionally runs for the process lifetime and keys pending entries by hash only. This is acceptable under the current constraint that background seeded-search runs operate on a single instance at a time; graceful shutdown and instanceID|hash keying are deferred by design.
Applied to files:
internal/services/crossseed/matching_resolution_language_test.go
🧬 Code graph analysis (1)
internal/services/crossseed/matching_resolution_language_test.go (2)
pkg/releases/parser.go (1)
NewDefaultParser(29-31)pkg/stringutils/normalize.go (1)
NewDefaultNormalizer(35-37)
🔇 Additional comments (2)
internal/services/crossseed/matching.go (1)
309-322: LGTM — language exception handles the common English-release case correctly.The logic treating empty language as equivalent to "ENGLISH" addresses the PR objective. The use of
joinNormalizedSliceensures uppercase comparison, so the "ENGLISH" literal match is correct.internal/services/crossseed/matching_resolution_language_test.go (1)
12-95: Well-structured table-driven tests with good coverage.The test file correctly validates the resolution and language matching behavior introduced in this PR. The use of parallel execution and clear test case naming is appreciated.
…erage - Replace empty if body with inverted guard for SD resolution fallback - Add test cases for 576p and SD resolution matching - Add bidirectional test case (576p source vs empty candidate)
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/autobrr/qui](https://github.com/autobrr/qui) | minor | `v1.11.0` → `v1.12.0` | --- ### Release Notes <details> <summary>autobrr/qui (ghcr.io/autobrr/qui)</summary> ### [`v1.12.0`](https://github.com/autobrr/qui/releases/tag/v1.12.0) [Compare Source](autobrr/qui@v1.11.0...v1.12.0) #### Changelog ##### New Features - [`202e950`](autobrr/qui@202e950): feat(automations): Add `free_space` condition ([#​1061](autobrr/qui#1061)) ([@​Barcode-eng](https://github.com/Barcode-eng)) - [`3b106d6`](autobrr/qui@3b106d6): feat(automations): make conditions optional for non-delete rules and add drag reorder ([#​939](autobrr/qui#939)) ([@​s0up4200](https://github.com/s0up4200)) - [`0684d75`](autobrr/qui@0684d75): feat(config): Add QUI\_\_OIDC\_CLIENT\_SECRET\_FILE env var ([#​841](autobrr/qui#841)) ([@​PedDavid](https://github.com/PedDavid)) - [`dac0173`](autobrr/qui@dac0173): feat(config): allow disabling tracker icon fetching ([#​823](autobrr/qui#823)) ([@​s0up4200](https://github.com/s0up4200)) - [`dc10bad`](autobrr/qui@dc10bad): feat(crossseed): add cancel run and opt-in errored torrent recovery ([#​918](autobrr/qui#918)) ([@​s0up4200](https://github.com/s0up4200)) - [`cd1fcc9`](autobrr/qui@cd1fcc9): feat(crossseed): add custom category option for cross-seeds ([#​907](autobrr/qui#907)) ([@​s0up4200](https://github.com/s0up4200)) - [`d189fe9`](autobrr/qui@d189fe9): feat(crossseed): add indexerName to webhook apply + fix category mode defaults ([#​916](autobrr/qui#916)) ([@​s0up4200](https://github.com/s0up4200)) - [`03a147e`](autobrr/qui@03a147e): feat(crossseed): add option to skip recheck-required matches ([#​825](autobrr/qui#825)) ([@​s0up4200](https://github.com/s0up4200)) - [`edae00a`](autobrr/qui@edae00a): feat(crossseed): add optional hardlink mode for cross-seeding ([#​849](autobrr/qui#849)) ([@​s0up4200](https://github.com/s0up4200)) - [`0938436`](autobrr/qui@0938436): feat(crossseed): add source aliasing for WEB/WEB-DL/WEBRip precheck matching ([#​874](autobrr/qui#874)) ([@​s0up4200](https://github.com/s0up4200)) - [`65f6129`](autobrr/qui@65f6129): feat(crossseed): show failure reasons, prune runs, and add cache cleanup ([#​923](autobrr/qui#923)) ([@​s0up4200](https://github.com/s0up4200)) - [`e10fba8`](autobrr/qui@e10fba8): feat(details): torrent details panel improvements ([#​884](autobrr/qui#884)) ([@​s0up4200](https://github.com/s0up4200)) - [`6921140`](autobrr/qui@6921140): feat(docs): add Docusaurus documentation site ([@​s0up4200](https://github.com/s0up4200)) - [`6a5a66c`](autobrr/qui@6a5a66c): feat(docs): add Icon and webUI variables to the Unraid install guide ([#​942](autobrr/qui#942)) ([@​BaukeZwart](https://github.com/BaukeZwart)) - [`281fce7`](autobrr/qui@281fce7): feat(docs): add local search plugin ([#​1076](autobrr/qui#1076)) ([@​s0up4200](https://github.com/s0up4200)) - [`566de08`](autobrr/qui@566de08): feat(docs): add qui logo, update readme, remove v4 flag ([@​s0up4200](https://github.com/s0up4200)) - [`b83ac5a`](autobrr/qui@b83ac5a): feat(docs): apply minimal.css theme to Docusaurus ([@​s0up4200](https://github.com/s0up4200)) - [`fe6a6df`](autobrr/qui@fe6a6df): feat(docs): improve documentation pages and add support page ([@​s0up4200](https://github.com/s0up4200)) - [`62a7ad5`](autobrr/qui@62a7ad5): feat(docs): use qui favicon ([@​s0up4200](https://github.com/s0up4200)) - [`5d124c0`](autobrr/qui@5d124c0): feat(orphan): add auto cleanup mode ([#​897](autobrr/qui#897)) ([@​s0up4200](https://github.com/s0up4200)) - [`3172ad9`](autobrr/qui@3172ad9): feat(settings): add log settings + live log stream ([#​876](autobrr/qui#876)) ([@​s0up4200](https://github.com/s0up4200)) - [`3c1b34b`](autobrr/qui@3c1b34b): feat(torrents): add "torrent introuvable" to unregistered status ([#​836](autobrr/qui#836)) ([@​kephasdev](https://github.com/kephasdev)) - [`afe4d39`](autobrr/qui@afe4d39): feat(torrents): add tracker URL editing for single torrents ([#​848](autobrr/qui#848)) ([@​s0up4200](https://github.com/s0up4200)) - [`76dedd7`](autobrr/qui@76dedd7): feat(torrents): update GeneralTabHorizontal to display limits and improve layout ([#​1078](autobrr/qui#1078)) ([@​martylukyy](https://github.com/martylukyy)) - [`6831c24`](autobrr/qui@6831c24): feat(ui): unify payment options into single dialog ([@​s0up4200](https://github.com/s0up4200)) - [`4dcdf7f`](autobrr/qui@4dcdf7f): feat(web): add local file access indicator to instance cards ([#​911](autobrr/qui#911)) ([@​s0up4200](https://github.com/s0up4200)) - [`a560e5e`](autobrr/qui@a560e5e): feat(web): compact torrent details panel ([#​833](autobrr/qui#833)) ([@​martylukyy](https://github.com/martylukyy)) - [`557e7bd`](autobrr/qui@557e7bd): feat: add issue/discussion template ([#​945](autobrr/qui#945)) ([@​s0up4200](https://github.com/s0up4200)) - [`8b93719`](autobrr/qui@8b93719): feat: add workflow automation system with category actions, orphan scanner, and hardlink detection ([#​818](autobrr/qui#818)) ([@​s0up4200](https://github.com/s0up4200)) ##### Bug Fixes - [`b85ad6b`](autobrr/qui@b85ad6b): fix(automations): allow delete rules to match incomplete torrents ([#​926](autobrr/qui#926)) ([@​s0up4200](https://github.com/s0up4200)) - [`ae06200`](autobrr/qui@ae06200): fix(automations): make tags field condition operators tag-aware ([#​908](autobrr/qui#908)) ([@​s0up4200](https://github.com/s0up4200)) - [`ace0101`](autobrr/qui@ace0101): fix(crossseed): detect folder mismatch for bare file to folder cross-seeds ([#​846](autobrr/qui#846)) ([@​s0up4200](https://github.com/s0up4200)) - [`1cc1243`](autobrr/qui@1cc1243): fix(crossseed): enforce resolution and language matching with sensible defaults ([#​855](autobrr/qui#855)) ([@​s0up4200](https://github.com/s0up4200)) - [`cefb9cd`](autobrr/qui@cefb9cd): fix(crossseed): execute external program reliably after injection ([#​1083](autobrr/qui#1083)) ([@​s0up4200](https://github.com/s0up4200)) - [`867e2da`](autobrr/qui@867e2da): fix(crossseed): improve matching with size validation and relaxed audio checks ([#​845](autobrr/qui#845)) ([@​s0up4200](https://github.com/s0up4200)) - [`4b5079b`](autobrr/qui@4b5079b): fix(crossseed): persist custom category settings in PATCH handler ([#​913](autobrr/qui#913)) ([@​s0up4200](https://github.com/s0up4200)) - [`cfbbc1f`](autobrr/qui@cfbbc1f): fix(crossseed): prevent season packs matching episodes ([#​854](autobrr/qui#854)) ([@​s0up4200](https://github.com/s0up4200)) - [`c7c1706`](autobrr/qui@c7c1706): fix(crossseed): reconcile interrupted runs on startup ([#​1084](autobrr/qui#1084)) ([@​s0up4200](https://github.com/s0up4200)) - [`7d633bd`](autobrr/qui@7d633bd): fix(crossseed): use ContentPath for manually-managed single-file torrents ([#​832](autobrr/qui#832)) ([@​s0up4200](https://github.com/s0up4200)) - [`d5db761`](autobrr/qui@d5db761): fix(database): include arr\_instances in string pool cleanup + remove auto-recovery ([#​898](autobrr/qui#898)) ([@​s0up4200](https://github.com/s0up4200)) - [`c73ec6f`](autobrr/qui@c73ec6f): fix(database): prevent race between stmt cache access and db close ([#​840](autobrr/qui#840)) ([@​s0up4200](https://github.com/s0up4200)) - [`a40b872`](autobrr/qui@a40b872): fix(db): drop legacy hardlink columns from cross\_seed\_settings ([#​912](autobrr/qui#912)) ([@​s0up4200](https://github.com/s0up4200)) - [`e400af3`](autobrr/qui@e400af3): fix(db): recover wedged SQLite writer + stop cross-seed tight loop ([#​890](autobrr/qui#890)) ([@​s0up4200](https://github.com/s0up4200)) - [`90e15b4`](autobrr/qui@90e15b4): fix(deps): update rls to recognize IP as iPlayer ([#​922](autobrr/qui#922)) ([@​s0up4200](https://github.com/s0up4200)) - [`8e81b9f`](autobrr/qui@8e81b9f): fix(proxy): honor TLSSkipVerify for proxied requests ([#​1051](autobrr/qui#1051)) ([@​s0up4200](https://github.com/s0up4200)) - [`eb2bee0`](autobrr/qui@eb2bee0): fix(security): redact sensitive URL parameters in logs ([#​853](autobrr/qui#853)) ([@​s0up4200](https://github.com/s0up4200)) - [`40982bc`](autobrr/qui@40982bc): fix(themes): prevent reset on license errors, improve switch performance ([#​844](autobrr/qui#844)) ([@​s0up4200](https://github.com/s0up4200)) - [`a8a32f7`](autobrr/qui@a8a32f7): fix(ui): incomplete torrents aren't "Completed: 1969-12-31" ([#​851](autobrr/qui#851)) ([@​finevan](https://github.com/finevan)) - [`5908bba`](autobrr/qui@5908bba): fix(ui): preserve category collapse state when toggling incognito mode ([#​834](autobrr/qui#834)) ([@​jabloink](https://github.com/jabloink)) - [`25c847e`](autobrr/qui@25c847e): fix(ui): torrents with no creation metadata don't display 1969 ([#​873](autobrr/qui#873)) ([@​finevan](https://github.com/finevan)) - [`6403b6a`](autobrr/qui@6403b6a): fix(web): column filter status now matches all states in category ([#​880](autobrr/qui#880)) ([@​s0up4200](https://github.com/s0up4200)) - [`eafc4e7`](autobrr/qui@eafc4e7): fix(web): make delete cross-seed check rely on content\_path matches ([#​1080](autobrr/qui#1080)) ([@​s0up4200](https://github.com/s0up4200)) - [`d57c749`](autobrr/qui@d57c749): fix(web): only show selection checkbox on normal view ([#​830](autobrr/qui#830)) ([@​jabloink](https://github.com/jabloink)) - [`60338f6`](autobrr/qui@60338f6): fix(web): optimize TorrentDetailsPanel for mobile view and make tabs scrollable horizontally ([#​1066](autobrr/qui#1066)) ([@​martylukyy](https://github.com/martylukyy)) - [`aedab87`](autobrr/qui@aedab87): fix(web): speed limit input reformatting during typing ([#​881](autobrr/qui#881)) ([@​s0up4200](https://github.com/s0up4200)) - [`df7f3e0`](autobrr/qui@df7f3e0): fix(web): truncate file progress percentage instead of rounding ([#​919](autobrr/qui#919)) ([@​s0up4200](https://github.com/s0up4200)) - [`2fadd01`](autobrr/qui@2fadd01): fix(web): update eslint config for flat config compatibility ([#​879](autobrr/qui#879)) ([@​s0up4200](https://github.com/s0up4200)) - [`721cedd`](autobrr/qui@721cedd): fix(web): use fixed heights for mobile torrent cards ([#​812](autobrr/qui#812)) ([@​jabloink](https://github.com/jabloink)) - [`a7db605`](autobrr/qui@a7db605): fix: remove pnpm-workspace.yaml breaking CI ([@​s0up4200](https://github.com/s0up4200)) - [`c0ddc0a`](autobrr/qui@c0ddc0a): fix: use prefix matching for allowed bash commands ([@​s0up4200](https://github.com/s0up4200)) ##### Other Changes - [`fff52ce`](autobrr/qui@fff52ce): chore(ci): disable reviewer ([@​s0up4200](https://github.com/s0up4200)) - [`7ef2a38`](autobrr/qui@7ef2a38): chore(ci): fix automated triage and deduplication workflows ([#​1057](autobrr/qui#1057)) ([@​s0up4200](https://github.com/s0up4200)) - [`d84910b`](autobrr/qui@d84910b): chore(docs): move Tailwind to documentation workspace only ([@​s0up4200](https://github.com/s0up4200)) - [`37ebe05`](autobrr/qui@37ebe05): chore(docs): move netlify.toml to documentation directory ([@​s0up4200](https://github.com/s0up4200)) - [`e25de38`](autobrr/qui@e25de38): chore(docs): remove disclaimer ([@​s0up4200](https://github.com/s0up4200)) - [`c59b809`](autobrr/qui@c59b809): chore(docs): update support sections ([#​1063](autobrr/qui#1063)) ([@​s0up4200](https://github.com/s0up4200)) - [`b723523`](autobrr/qui@b723523): chore(tests): remove dead tests and optimize slow test cases ([#​842](autobrr/qui#842)) ([@​s0up4200](https://github.com/s0up4200)) - [`662a1c6`](autobrr/qui@662a1c6): chore(workflows): update runners from 4vcpu to 2vcpu for all jobs ([#​859](autobrr/qui#859)) ([@​s0up4200](https://github.com/s0up4200)) - [`46f2a1c`](autobrr/qui@46f2a1c): chore: clean up repo root by moving Docker, scripts, and community docs ([#​1054](autobrr/qui#1054)) ([@​s0up4200](https://github.com/s0up4200)) - [`2f27c0d`](autobrr/qui@2f27c0d): chore: remove old issue templates ([@​s0up4200](https://github.com/s0up4200)) - [`04f361a`](autobrr/qui@04f361a): ci(triage): add labeling for feature-requests-ideas discussions ([@​s0up4200](https://github.com/s0up4200)) - [`f249c69`](autobrr/qui@f249c69): ci(triage): remove needs-triage label after applying labels ([@​s0up4200](https://github.com/s0up4200)) - [`bdda1de`](autobrr/qui@bdda1de): ci(workflows): add self-dispatch workaround for discussion events ([@​s0up4200](https://github.com/s0up4200)) - [`a9732a2`](autobrr/qui@a9732a2): ci(workflows): increase max-turns to 25 for Claude workflows ([@​s0up4200](https://github.com/s0up4200)) - [`d7d830d`](autobrr/qui@d7d830d): docs(README): add Buy Me a Coffee link ([#​863](autobrr/qui#863)) ([@​s0up4200](https://github.com/s0up4200)) - [`266d92e`](autobrr/qui@266d92e): docs(readme): Clarify ignore pattern ([#​878](autobrr/qui#878)) ([@​quorn23](https://github.com/quorn23)) - [`9586084`](autobrr/qui@9586084): docs(readme): add banner linking to stable docs ([#​925](autobrr/qui#925)) ([@​s0up4200](https://github.com/s0up4200)) - [`e36a621`](autobrr/qui@e36a621): docs(readme): use markdown link for Polar URL ([@​s0up4200](https://github.com/s0up4200)) - [`9394676`](autobrr/qui@9394676): docs: add frontmatter titles and descriptions, remove marketing language ([@​s0up4200](https://github.com/s0up4200)) - [`ba9d45e`](autobrr/qui@ba9d45e): docs: add local filesystem access snippet and swizzle Details component ([@​s0up4200](https://github.com/s0up4200)) - [`4329edd`](autobrr/qui@4329edd): docs: disclaimer about unreleased features ([#​943](autobrr/qui#943)) ([@​s0up4200](https://github.com/s0up4200)) - [`735d065`](autobrr/qui@735d065): docs: improve external programs, orphan scan, reverse proxy, tracker icons documentation ([@​s0up4200](https://github.com/s0up4200)) - [`78faef2`](autobrr/qui@78faef2): docs: remove premature tip and fix stat command ([@​s0up4200](https://github.com/s0up4200)) - [`eaad3bf`](autobrr/qui@eaad3bf): docs: update social card image in Docusaurus configuration ([@​s0up4200](https://github.com/s0up4200)) - [`02a68e5`](autobrr/qui@02a68e5): refactor(crossseed): hardcode ignore patterns for file matching ([#​915](autobrr/qui#915)) ([@​s0up4200](https://github.com/s0up4200)) **Full Changelog**: <autobrr/qui@v1.11.0...v1.12.0> #### Docker images - `docker pull ghcr.io/autobrr/qui:v1.12.0` - `docker pull ghcr.io/autobrr/qui:latest` #### What to do next? - Join our [Discord server](https://discord.autobrr.com/qui) Thank you for using qui! </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi42OS4yIiwidXBkYXRlZEluVmVyIjoiNDIuNjkuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW1hZ2UiXX0=--> Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/3060 Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net> Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
Summary
rlsoften omits resolution for SD releasesFRENCH.WEBmatchingMULTi.1080p.WEBFixes #688
Test plan
Summary by CodeRabbit
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.