Skip to content

feat(plex): add content filtering for ignored editions and episode titles#2603

Open
Rubeanie wants to merge 6 commits intoseerr-team:developfrom
Rubeanie:feature/plex-ignored-editions
Open

feat(plex): add content filtering for ignored editions and episode titles#2603
Rubeanie wants to merge 6 commits intoseerr-team:developfrom
Rubeanie:feature/plex-ignored-editions

Conversation

@Rubeanie
Copy link

@Rubeanie Rubeanie commented Feb 28, 2026

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:

  • New "Ignored Editions" multi-tag input in Plex settings
  • Movies with matching Plex edition tags (e.g., Trailer) are skipped during library scans and availability sync
  • Exact, case-insensitive matching

TV Episode Title Filtering:

  • New "Ignored Episode Titles" multi-tag input
  • Configurable "Episode Filter Mode" dropdown with three modes:
    • Season 0: only filters matching titles in specials/Season 0
    • Season 0 + Episode 0: only filters S00E00 specifically
    • Any Season or Episode: filters matching titles everywhere
  • Also applies to Hama (anime) special episode processing
  • Includes a guard to prevent processShow from running when no episodes remain after filtering

UI:

  • New "Content Filtering" section heading in Plex settings
  • Filter mode dropdown is disabled when no ignored episode titles are configured
  • Tooltips cross-reference each other for clarity

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:
image

Example:
image

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
    • AI Assistance: Claude Opus 4.6 was used for troubleshooting and code review
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features
    • Added content-filtering to Plex settings: ignore specific movie editions and episode titles, plus a selectable episode filter mode (season / seasonAndEpisode / any).
    • Filtering now applies during library scans and processing, so ignored editions/episodes are skipped and won’t be imported or updated.
  • Documentation
    • Added UI labels, descriptions, and placeholders to support the new filtering options in settings.

@Rubeanie Rubeanie requested a review from a team as a code owner February 28, 2026 11:04
@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Type Definitions
server/api/plexapi.ts
Added optional editionTitle?: string to PlexLibraryItem and PlexMetadata.
Filtering Utilities
server/utils/plexFilter.ts
New exports isIgnoredEdition(editionTitle?: string) and isIgnoredEpisode(episodeTitle, seasonNumber, episodeNumber) that read Plex settings and apply mode-based logic.
Scan & Sync Integration
server/lib/scanners/plex/index.ts, server/lib/availabilitySync.ts
Integrates ignore checks: skip movies with ignored editions, filter out ignored episodes when collecting seasons/episodes, and avoid processing shows with no non-ignored episodes.
Settings Schema
server/lib/settings/index.ts
Added Plex settings: ignoredEditions: string[], ignoredEpisodeTitles: string[], `ignoredEpisodeFilterMode: 'season'
Settings UI
src/components/Settings/SettingsPlex.tsx
Added UI controls (creatable multi-selects and mode dropdown), form handling, normalization/deduplication on submit, and sends new fields to server.
Localization
src/i18n/locale/en.json
Added 13 new i18n keys for content filtering, ignored editions/episode titles, placeholders, tips, and filter mode labels.
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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nibble titles, trim and tidy bright,
Hopping past editions that don't feel right.
Seasons pruned with a careful twitch,
Ignored or kept — I know which!
A rabbit's filter, quick and spry — hop on by!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially addresses #2235 by filtering ignored edition/episode content, but does not implement the core request for prioritizing Radarr/Sonarr availability over Plex. Implement availability priority selection or consistently prioritize Radarr/Sonarr over Plex availability checks as requested in #2235.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: adding content filtering for ignored editions and episode titles in Plex settings.
Out of Scope Changes check ✅ Passed All changes are scoped to content filtering via ignored editions/episodes and related UI/settings—directly supporting the filtering workaround for #2235.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟠 Major

Fix unreachable TVDB fallback before calling processShow.

Line 431 currently requires mediaIds.tvdbId, which prevents processing when TVDB is only available via tvShow.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

📥 Commits

Reviewing files that changed from the base of the PR and between f74306e and f11631d.

📒 Files selected for processing (6)
  • server/api/plexapi.ts
  • server/lib/availabilitySync.ts
  • server/lib/scanners/plex/index.ts
  • server/lib/settings/index.ts
  • src/components/Settings/SettingsPlex.tsx
  • src/i18n/locale/en.json

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/components/Settings/SettingsPlex.tsx (1)

420-428: Consider using Set for deduplication.

The Map-based approach works but Set is 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

📥 Commits

Reviewing files that changed from the base of the PR and between f11631d and ee7cc5a.

📒 Files selected for processing (4)
  • server/lib/availabilitySync.ts
  • server/lib/scanners/plex/index.ts
  • server/utils/plexFilter.ts
  • src/components/Settings/SettingsPlex.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/lib/availabilitySync.ts

@Rubeanie
Copy link
Author

One alternative approach to this problem is filtering ignored media based on file paths using regular expressions

@Rubeanie
Copy link
Author

Leaving this PR open just in case this implementation is preferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add media detection Priority for Radarr/Sonarr and ignore media server Availability

1 participant