fix: preserve blocklist on media deletion & optimise watchlist-sync#2478
fix: preserve blocklist on media deletion & optimise watchlist-sync#2478fallenbagel merged 4 commits intodevelopfrom
Conversation
…watchlist sync Blocklisted media was being re-requested via watchlist sync because deleting media from Sonarr/Radarr through the UI also deleted the Media entity and its associated Blocklist record via cascade. The media delete endpoint now preserves blocklisted Media entities by clearing service fields instead of removing the row. Additionally, the watchlist sync filter now excludes blocklisted items and skips media that already has an existing auto-request for the user, avoiding unnecessary API calls and database queries on every sync cycle. fix #2475
|
No actionable comments were generated in the recent review. 🎉 📝 WalkthroughWalkthroughAdds filtering in watchlist sync to skip items the user has already auto-requested by querying existing MediaRequest records; adds Media.resetServiceData() to clear service-related fields; changes DELETE /:id to call resetServiceData() and save when media.status is BLOCKLISTED instead of deleting the record. Changes
Sequence Diagram(s)sequenceDiagram
participant Plex as Plex Watchlist API
participant Job as Watchlist Sync Job
participant DB as Database
participant Creator as MediaRequest Creator
Plex->>Job: return watchlist items (tmdbId, mediaType)
Job->>DB: query MediaRequest where userId = X and tmdbId IN (watchlistTmdbIds)
DB-->>Job: existing auto-request set (mediaType:tmdbId)
Job->>Job: filter watchlist items excluding existing set and blocked/unavailable
Job->>Creator: create media request for each remaining item
Creator-->>DB: persist new MediaRequest (if created)
Creator-->>Job: return result (success/failure)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@server/lib/watchlistsync.ts`:
- Around line 73-84: existingAutoRequests mapping assumes every MediaRequest has
a loaded media relation and accessing r.media.tmdbId can throw; update the
mapping that builds autoRequestedTmdbIds to guard against missing media by
filtering or null-checking each request first (e.g., use
existingAutoRequests.filter(r => r.media).map(r => r.media.tmdbId) or
conditional access) so only valid tmdbId values are added; modify the logic
around requestRepository, existingAutoRequests, and autoRequestedTmdbIds to
safely handle requests with null/undefined media.
There was a problem hiding this comment.
Pull request overview
Fixes a watchlist-sync + media deletion edge case where deleting a Media row could cascade-delete its Blocklist entry, allowing future watchlist sync cycles to recreate and auto-approve requests that should remain blocked.
Changes:
- Updates the media delete endpoint to preserve blocklisted media by nulling service-related fields instead of deleting the row.
- Hardens watchlist sync filtering to skip blocklisted items and avoid repeated duplicate auto-request attempts.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
server/routes/media.ts |
Preserves blocklisted media on deletion by clearing service identifiers instead of removing the entity. |
server/lib/watchlistsync.ts |
Adds pre-filtering to skip blocklisted media and items with existing auto-requests before attempting request creation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…improve item filtering
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…fields on blocklisted media
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/seerr-team/seerr](https://github.com/seerr-team/seerr) | minor | `v3.0.1` → `v3.1.0` | | [seerr-team/seerr](https://github.com/seerr-team/seerr) | minor | `v3.0.1` → `v3.1.0` | --- ### Release Notes <details> <summary>seerr-team/seerr (ghcr.io/seerr-team/seerr)</summary> ### [`v3.1.0`](https://github.com/seerr-team/seerr/releases/tag/v3.1.0) [Compare Source](seerr-team/seerr@v3.0.1...v3.1.0) ##### 🛡️ Security - Patch [CVE-2026-27707](GHSA-rc4w-7m3r-c2f7) - Unauthenticated account registration on Plex-configured Seerr instances via Jellyfin authentication endpoint - ([4ae2068](seerr-team/seerr@4ae2068)) - Patch [CVE-2026-27793](GHSA-f7xw-jcqr-57hp) - Broken Object-Level Authorization in User Profile Endpoint Exposes Third-Party Notification Credentials - ([4f089b2](seerr-team/seerr@4f089b2)) - Patch [CVE-2026-27792](GHSA-gx3h-3jg5-q65f) - Missing authentication on pushSubscription endpoints - ([946bdecec](seerr-team/seerr@946bdec)) ##### 🚀 Features - *(helm)* Use an existing PVC as config volume ([#​2447](seerr-team/seerr#2447)) - ([8f0c904](seerr-team/seerr@8f0c904)) - *(servarr-api)* Make Servarr API request timeout configurable ([#​2556](seerr-team/seerr#2556)) - ([3bcb4da](seerr-team/seerr@3bcb4da)) - Self-host font for better privacy ([#​2540](seerr-team/seerr#2540)) - ([10ea21b](seerr-team/seerr@10ea21b)) ##### 🐛 Bug Fixes - *(helm)* Add "v" as prefix for appVersion tag ([#​2445](seerr-team/seerr#2445)) - ([04b9d87](seerr-team/seerr@04b9d87)) - *(jellyfin-scanner)* Include unmatched seasons in processable seasons ([#​2538](seerr-team/seerr#2538)) - ([68f56d2](seerr-team/seerr@68f56d2)) - *(link-account)* Fix error-message override ([#​2547](seerr-team/seerr#2547)) - ([b843be0](seerr-team/seerr@b843be0)) - *(plex-scanner)* Add TVDb to TMDB fallback in plex scanner ([#​2537](seerr-team/seerr#2537)) - ([7c60a5c](seerr-team/seerr@7c60a5c)) - *(radarr)* Trigger search for existing monitored movies without files ([#​2391](seerr-team/seerr#2391)) - ([55776ea](seerr-team/seerr@55776ea)) - *(servarr)* Increase default API timeout from 5000ms to 10000ms ([#​2442](seerr-team/seerr#2442)) - ([b499976](seerr-team/seerr@b499976)) - *(sonarr)* Use configured metadata provider for season filtering ([#​2516](seerr-team/seerr#2516)) - ([5013d1d](seerr-team/seerr@5013d1d)) - *(watch-data)* Use sentinel values to avoid invalid SQL syntax ([#​2552](seerr-team/seerr#2552)) - ([947f70c](seerr-team/seerr@947f70c)) - *(watchlist-sync)* Correct permission typo for TV auto requests ([#​2488](seerr-team/seerr#2488)) - ([e0e4b6f](seerr-team/seerr@e0e4b6f)) - Preserve blocklist on media deletion & optimise watchlist-sync ([#​2478](seerr-team/seerr#2478)) - ([9da8bb6](seerr-team/seerr@9da8bb6)) ##### 🚜 Refactor - *(tailwind)* Replace deprecated tailwind utilities ([#​2542](seerr-team/seerr#2542)) - ([f42a4ec](seerr-team/seerr@f42a4ec)) ##### 📖 Documentation - *(synology)* Add installation guide via SynoCommunity ([#​2503](seerr-team/seerr#2503)) - ([0e636a3](seerr-team/seerr@0e636a3)) - *(truenas)* Update install/migration guide ([#​2491](seerr-team/seerr#2491)) - ([dc1734d](seerr-team/seerr@dc1734d)) - *(unraid)* Improve unraid migration guide ([#​2470](seerr-team/seerr#2470)) - ([5e64d49](seerr-team/seerr@5e64d49)) - Update Unraid install and migration guides with dual permission methods ([#​2532](seerr-team/seerr#2532)) - ([a0d0eb1](seerr-team/seerr@a0d0eb1)) - Add a warning in migration-guide for third party installation ([#​2527](seerr-team/seerr#2527)) - ([7e9dff3](seerr-team/seerr@7e9dff3)) - Remove double quotes (") from DB\_HOST environment variable ([#​2514](seerr-team/seerr#2514)) - ([fa905be](seerr-team/seerr@fa905be)) - Add Unraid installation and migration guide ([#​2440](seerr-team/seerr#2440)) - ([b6a9132](seerr-team/seerr@b6a9132)) - Fix migration guide title ([#​2425](seerr-team/seerr#2425)) - ([39ae32f](seerr-team/seerr@39ae32f)) ##### ⚡ Performance - Add missing indexes on all foreign key columns ([#​2461](seerr-team/seerr#2461)) - ([c6bcfe0](seerr-team/seerr@c6bcfe0)) ##### ⚙️ Miscellaneous Tasks - *(changelog)* Fix changelog template ([#​2431](seerr-team/seerr#2431)) - ([c2977f6](seerr-team/seerr@c2977f6)) - *(eslint)* Add react/self-closing-comp ([#​2563](seerr-team/seerr#2563)) - ([cd8b386](seerr-team/seerr@cd8b386)) - *(github)* Add docs and maintenance issue templates ([#​2467](seerr-team/seerr#2467)) - ([cf4883a](seerr-team/seerr@cf4883a)) - *(helm)* Add GatewayAPI route support to helm chart ([#​2544](seerr-team/seerr#2544)) - ([3a42f59](seerr-team/seerr@3a42f59)) - *(helm)* Update ghcr.io/seerr-team/seerr ( 3.0.0 → 3.0.1 ) \[skip-ci] ([#​2441](seerr-team/seerr#2441)) - ([87fb0df](seerr-team/seerr@87fb0df)) - *(husky)* Fixed husky commit message from bash/zsh syntax to sh syntax ([#​2572](seerr-team/seerr#2572)) - ([a00c9e5](seerr-team/seerr@a00c9e5)) - *(release)* Prepare ${TAG\_VERSION} - ([94a70bb](seerr-team/seerr@94a70bb)) - Updated the Contributing and Security guides to reflect our current practices ([#​2579](seerr-team/seerr#2579)) - ([0d40a42](seerr-team/seerr@0d40a42)) - Disable nextjs telemetry ([#​2517](seerr-team/seerr#2517)) - ([cecdd63](seerr-team/seerr@cecdd63)) - Update contributing guide regarding Automated AI Agent ([#​2518](seerr-team/seerr#2518)) - ([880fbc9](seerr-team/seerr@880fbc9)) - Remove discord notification from release ([#​2501](seerr-team/seerr#2501)) - ([fba20c1](seerr-team/seerr@fba20c1)) - Add create-tag workflow to streamline release process ([#​2493](seerr-team/seerr#2493)) - ([06e5eb0](seerr-team/seerr@06e5eb0)) - Update concurrency logic ([#​2481](seerr-team/seerr#2481)) - ([4939f13](seerr-team/seerr@4939f13)) - Add semantic-pr workflow to enforce conventional commits ([#​2472](seerr-team/seerr#2472)) - ([5e57fdc](seerr-team/seerr@5e57fdc)) ##### New Contributors ❤️ - [@​caillou](https://github.com/caillou) made their first contribution - [@​Kenshin9977](https://github.com/Kenshin9977) made their first contribution - [@​MagicLegend](https://github.com/MagicLegend) made their first contribution - [@​wiiaam](https://github.com/wiiaam) made their first contribution - [@​mjonkus](https://github.com/mjonkus) made their first contribution - [@​nova-api](https://github.com/nova-api) made their first contribution - [@​mreid-tt](https://github.com/mreid-tt) made their first contribution - [@​DataBitz](https://github.com/DataBitz) made their first contribution - [@​Hyperion2220](https://github.com/Hyperion2220) made their first contribution - [@​blassley](https://github.com/blassley) made their first contribution - [@​JanKleine](https://github.com/JanKleine) made their first contribution - [@​koiralasandesh](https://github.com/koiralasandesh) made their first contribution<!-- generated by git-cliff --> </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 these updates 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:eyJjcmVhdGVkSW5WZXIiOiI0My4yNS43IiwidXBkYXRlZEluVmVyIjoiNDMuMjUuNyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW1hZ2UiXX0=--> Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/4284 Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net> Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
Description
When a user blocklists media and then removes it from Sonarr/Radarr via the Seerr interface, the Media entity and its associated Blocklist record were both destroyed due to the cascade delete on the relationship. On the next watchlist sync cycle, no record existed to check against, so a fresh request was created and auto-approved, completely bypassing the blocklist.
This PR fixes the media delete endpoint to detect blocklisted status and preserve the entity by nulling out service-related fields rather than removing the row entirely. It also improves the watchlist sync filtering to exclude blocklisted media as a safety net and to skip items where the user already has an existing auto-request, eliminating the repeated unnecessary api calls and database lookups that were happening every sync cycle just to throw a duplicate request error.
How Has This Been Tested?
Screenshots / Logs (if applicable)
Checklist:
pnpm buildpnpm i18n:extractSummary by CodeRabbit
Release Notes