feat(plex): add content filtering for ignored editions and episode titles#2603
feat(plex): add content filtering for ignored editions and episode titles#2603Rubeanie wants to merge 6 commits intoseerr-team:developfrom
Conversation
📝 WalkthroughWalkthroughAdds configurable Plex content filtering: new settings and UI to ignore specific movie editions and episode titles, helper functions to evaluate ignores, and integration into Plex scanners and availability sync to skip ignored media during processing. Changes
sequenceDiagram
participant User
participant UI as Settings UI
participant Server
participant SettingsStore as Settings DB
participant Scanner as Plex Scanner
participant Plex as Plex Media Server
User->>UI: Configure ignored editions / episode titles & mode
UI->>Server: POST /api/v1/settings/plex (includes ignored lists + mode)
Server->>SettingsStore: save plex.ignoredEditions, plex.ignoredEpisodeTitles, plex.ignoredEpisodeFilterMode
Scanner->>SettingsStore: getSettings()
Scanner->>Plex: fetch library items / seasons / episodes
Scanner->>Server: (calls) isIgnoredEdition / isIgnoredEpisode
Server->>SettingsStore: read plex ignore settings
Server-->>Scanner: return ignore decision (true/false)
alt not ignored
Scanner->>Server: process item (match, add, update)
else ignored
Scanner->>Scanner: skip item (log and do not process)
end
Scanner->>Server: availability sync uses same ignore checks before marking available/missing
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
server/lib/scanners/plex/index.ts (1)
431-435:⚠️ Potential issue | 🟠 MajorFix unreachable TVDB fallback before calling
processShow.Line 431 currently requires
mediaIds.tvdbId, which prevents processing when TVDB is only available viatvShow.external_ids.tvdb_id. That makes the fallback on Line 434 effectively dead.💡 Proposed fix
- if (mediaIds.tvdbId && hasAnyEpisodes) { + const resolvedTvdbId = mediaIds.tvdbId ?? tvShow.external_ids.tvdb_id; + if (resolvedTvdbId && hasAnyEpisodes) { await this.processShow( mediaIds.tmdbId, - mediaIds.tvdbId ?? tvShow.external_ids.tvdb_id, + resolvedTvdbId, processableSeasons, { mediaAddedAt: new Date(metadata.addedAt * 1000),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@server/lib/scanners/plex/index.ts` around lines 431 - 435, The condition currently gates processShow on mediaIds.tvdbId, making the tvShow.external_ids.tvdb_id fallback dead; change the if to check for either TVDB id (e.g., if ((mediaIds.tvdbId || tvShow.external_ids?.tvdb_id) && hasAnyEpisodes)) and call processShow with the chosen id (mediaIds.tvdbId ?? tvShow.external_ids?.tvdb_id) so processShow receives the correct TVDB id even when mediaIds.tvdbId is absent; ensure optional chaining on tvShow.external_ids to avoid runtime errors.
🧹 Nitpick comments (1)
src/components/Settings/SettingsPlex.tsx (1)
425-427: Normalize tag arrays before persisting settings.Consider trimming, filtering empty strings, and case-insensitive deduplication before POST to avoid redundant config entries.
♻️ Suggested hardening
+ const normalizeTags = (tags: string[]) => + [...new Set(tags.map((t) => t.trim()).filter(Boolean))]; + await axios.post('/api/v1/settings/plex', { ip: values.hostname, port: Number(values.port), useSsl: values.useSsl, webAppUrl: values.webAppUrl, - ignoredEditions: values.ignoredEditions, - ignoredEpisodeTitles: values.ignoredEpisodeTitles, + ignoredEditions: normalizeTags(values.ignoredEditions), + ignoredEpisodeTitles: normalizeTags(values.ignoredEpisodeTitles), ignoredEpisodeFilterMode: values.ignoredEpisodeFilterMode, } as PlexSettings);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/Settings/SettingsPlex.tsx` around lines 425 - 427, The ignoredEditions and ignoredEpisodeTitles arrays are assigned directly from values and should be normalized before the POST: trim each string, remove any empty strings, lowercase for case-insensitive comparisons, and deduplicate (preserve order) so the payload has no redundant entries; modify the code that builds the request body where ignoredEditions and ignoredEpisodeTitles are set (the block assigning ignoredEditions: values.ignoredEditions and ignoredEpisodeTitles: values.ignoredEpisodeTitles) to map/trim/filter/toLowerCase and run a dedupe step before sending.
🤖 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/availabilitySync.ts`:
- Line 15: The availability sync file imports isIgnoredEdition directly from the
scanner module which causes scanner singletons to initialize as a side effect;
extract the pure helper isIgnoredEdition into a new small shared module (e.g.,
export a function named isIgnoredEdition from a new plex filtering utility) and
update both the scanner module and availabilitySync to import that helper
instead of importing from the scanner module; remove the import of the scanner
module from availabilitySync so availability sync no longer triggers scanner
initialization and ensure both places import the same new utility function name
isIgnoredEdition.
---
Outside diff comments:
In `@server/lib/scanners/plex/index.ts`:
- Around line 431-435: The condition currently gates processShow on
mediaIds.tvdbId, making the tvShow.external_ids.tvdb_id fallback dead; change
the if to check for either TVDB id (e.g., if ((mediaIds.tvdbId ||
tvShow.external_ids?.tvdb_id) && hasAnyEpisodes)) and call processShow with the
chosen id (mediaIds.tvdbId ?? tvShow.external_ids?.tvdb_id) so processShow
receives the correct TVDB id even when mediaIds.tvdbId is absent; ensure
optional chaining on tvShow.external_ids to avoid runtime errors.
---
Nitpick comments:
In `@src/components/Settings/SettingsPlex.tsx`:
- Around line 425-427: The ignoredEditions and ignoredEpisodeTitles arrays are
assigned directly from values and should be normalized before the POST: trim
each string, remove any empty strings, lowercase for case-insensitive
comparisons, and deduplicate (preserve order) so the payload has no redundant
entries; modify the code that builds the request body where ignoredEditions and
ignoredEpisodeTitles are set (the block assigning ignoredEditions:
values.ignoredEditions and ignoredEpisodeTitles: values.ignoredEpisodeTitles) to
map/trim/filter/toLowerCase and run a dedupe step before sending.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
server/api/plexapi.tsserver/lib/availabilitySync.tsserver/lib/scanners/plex/index.tsserver/lib/settings/index.tssrc/components/Settings/SettingsPlex.tsxsrc/i18n/locale/en.json
…, and normalize filter inputs
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/components/Settings/SettingsPlex.tsx (1)
420-428: Consider usingSetfor deduplication.The
Map-based approach works butSetis more idiomatic for simple deduplication:♻️ Suggested simplification
- const dedupe = (arr: string[]) => [ - ...new Map(arr.map((s) => [s, s])).values(), - ]; + const dedupe = (arr: string[]) => [...new Set(arr)];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/Settings/SettingsPlex.tsx` around lines 420 - 428, The deduplication is implemented with a Map in the dedupe function; replace that with an idiomatic Set-based approach by changing dedupe(arr: string[]) to return [...new Set(arr)] and ensure normalize (which calls dedupe) still trims, lowercases and filters entries before deduplication; update references to dedupe and normalize accordingly so types (arr?: string[]) and behavior remain the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/components/Settings/SettingsPlex.tsx`:
- Around line 420-428: The deduplication is implemented with a Map in the dedupe
function; replace that with an idiomatic Set-based approach by changing
dedupe(arr: string[]) to return [...new Set(arr)] and ensure normalize (which
calls dedupe) still trims, lowercases and filters entries before deduplication;
update references to dedupe and normalize accordingly so types (arr?: string[])
and behavior remain the same.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
server/lib/availabilitySync.tsserver/lib/scanners/plex/index.tsserver/utils/plexFilter.tssrc/components/Settings/SettingsPlex.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- server/lib/availabilitySync.ts
|
One alternative approach to this problem is filtering ignored media based on file paths using regular expressions |
Leaving this PR open just in case this implementation is preferred. |
Description
Adds configurable content filtering to Plex settings, allowing users to exclude specific media from being detected during library scans. This prevents placeholder files (e.g., trailers) from incorrectly marking content as available.
Movie Edition Filtering:
Trailer) are skipped during library scans and availability syncTV Episode Title Filtering:
processShowfrom running when no episodes remain after filteringUI:
Related
How Has This Been Tested?
Built and published to DockerHub
rubeanie/seerr:ignored-editions. Self tested, with more users actively testing.Screenshots / Logs (if applicable)
Default:

Example:

Checklist:
pnpm buildpnpm i18n:extractSummary by CodeRabbit