diff --git a/server/lib/overlays/OverlayLibraryService.ts b/server/lib/overlays/OverlayLibraryService.ts index f593eda..a03ac72 100644 --- a/server/lib/overlays/OverlayLibraryService.ts +++ b/server/lib/overlays/OverlayLibraryService.ts @@ -256,6 +256,11 @@ class OverlayLibraryService { let errorCount = 0; for (const item of allItems) { + // CRITICAL: Skip episodes and seasons - overlays only apply to movies and shows + if (item.type === 'episode' || item.type === 'season') { + continue; + } + // Check for cancellation if (checkCancelled && checkCancelled()) { logger.info( @@ -417,6 +422,14 @@ class OverlayLibraryService { const itemMetadata = await plexApi.getMetadata(ratingKey); if (itemMetadata) { + // CRITICAL: Skip episodes and seasons - overlays only apply to movies and shows + if ( + itemMetadata.type === 'episode' || + itemMetadata.type === 'season' + ) { + continue; + } + // Convert to PlexLibraryItem format (cast to satisfy type requirements) const item = { ratingKey: itemMetadata.ratingKey, @@ -430,6 +443,8 @@ class OverlayLibraryService { index: itemMetadata.index, addedAt: itemMetadata.addedAt || 0, updatedAt: itemMetadata.updatedAt || 0, + editionTitle: (itemMetadata as { editionTitle?: string }) + .editionTitle, } as PlexLibraryItem; await this.applyOverlaysToItem( @@ -584,6 +599,7 @@ class OverlayLibraryService { let daysAgo: number | undefined; let daysUntilNextEpisode: number | undefined; let daysUntilNextSeason: number | undefined; + let daysAgoNextSeason: number | undefined; if (releaseDateInfo.releaseDate) { const daysSince = calculateDaysSince(releaseDateInfo.releaseDate); @@ -609,6 +625,8 @@ class OverlayLibraryService { ); if (daysSince < 0) { daysUntilNextSeason = -daysSince; + } else { + daysAgoNextSeason = daysSince; } } @@ -620,6 +638,7 @@ class OverlayLibraryService { daysUntilNextEpisode, nextSeasonAirDate: releaseDateInfo.nextSeasonAirDate, daysUntilNextSeason, + daysAgoNextSeason, seasonNumber: releaseDateInfo.seasonNumber, }; } @@ -656,11 +675,11 @@ class OverlayLibraryService { const context: OverlayRenderContext = { ...baseContext, - ...releaseDateContext, - ...monitoringContext, - ...contextOverrides, isPlaceholder: actualIsPlaceholder, downloaded, + ...contextOverrides, + ...releaseDateContext, + ...monitoringContext, }; // Filter templates by conditions to get only templates that will actually be applied diff --git a/server/lib/overlays/OverlayTemplateRenderer.ts b/server/lib/overlays/OverlayTemplateRenderer.ts index cf67752..49b232f 100644 --- a/server/lib/overlays/OverlayTemplateRenderer.ts +++ b/server/lib/overlays/OverlayTemplateRenderer.ts @@ -244,6 +244,7 @@ export interface OverlayRenderContext { daysUntilNextEpisode?: number; // Calculated days until ANY next episode nextSeasonAirDate?: string; // Raw date for SEASON PREMIERES only (episode 1) daysUntilNextSeason?: number; // Calculated days until next SEASON PREMIERE only + daysAgoNextSeason?: number; // Days since next season premiered (only if nextSeasonAirDate is in the past) // Episode information seasonNumber?: number; diff --git a/server/lib/overlays/PresetTemplates.ts b/server/lib/overlays/PresetTemplates.ts index cceac62..dab1c29 100644 --- a/server/lib/overlays/PresetTemplates.ts +++ b/server/lib/overlays/PresetTemplates.ts @@ -328,10 +328,15 @@ export const PRESET_TEMPLATES: { applicationCondition: { sections: [ { + // MOVIES: Released (daysAgo >= 0), not downloaded, monitored, in Radarr rules: [ - // Released items only (daysAgo >= 0 means already released) - // Note: daysUntilRelease and daysAgo are mutually exclusive - { field: 'daysAgo', operator: 'gte', value: 0 }, + { field: 'mediaType', operator: 'neq', value: 'show' }, + { + ruleOperator: 'and', + field: 'daysAgo', + operator: 'gte', + value: 0, + }, { ruleOperator: 'and', field: 'downloaded', @@ -344,15 +349,39 @@ export const PRESET_TEMPLATES: { operator: 'eq', value: true, }, + { + ruleOperator: 'and', + field: 'inRadarr', + operator: 'eq', + value: true, + }, ], }, { - // AND (in Radarr OR in Sonarr) - sectionOperator: 'and', + // OR TV SHOWS: Monitored season has aired (daysAgoNextSeason >= 0), not downloaded, monitored, in Sonarr + sectionOperator: 'or', rules: [ - { field: 'inRadarr', operator: 'eq', value: true }, + { field: 'mediaType', operator: 'eq', value: 'show' }, { - ruleOperator: 'or', + ruleOperator: 'and', + field: 'daysAgoNextSeason', + operator: 'gte', + value: 0, + }, + { + ruleOperator: 'and', + field: 'downloaded', + operator: 'eq', + value: false, + }, + { + ruleOperator: 'and', + field: 'isMonitored', + operator: 'eq', + value: true, + }, + { + ruleOperator: 'and', field: 'inSonarr', operator: 'eq', value: true, diff --git a/src/components/OverlayEditor/types.ts b/src/components/OverlayEditor/types.ts index 7657ffd..87cebb6 100644 --- a/src/components/OverlayEditor/types.ts +++ b/src/components/OverlayEditor/types.ts @@ -209,6 +209,7 @@ export interface OverlayRenderContext { daysUntilNextEpisode?: number; // Calculated days until ANY next episode nextSeasonAirDate?: string; // Raw date for SEASON PREMIERES only (episode 1) daysUntilNextSeason?: number; // Calculated days until next SEASON PREMIERE only + daysAgoNextSeason?: number; // Days since next season premiered (only if nextSeasonAirDate is in the past) // Episode information seasonNumber?: number; @@ -322,6 +323,11 @@ export const AVAILABLE_VARIABLES = { label: 'Days Until Next Season (TV)', example: '45', }, + { + field: 'daysAgoNextSeason', + label: 'Days Since Next Season Premiered (TV)', + example: '7', + }, { field: 'seasonNumber', label: 'Season Number', example: '5' }, { field: 'episodeNumber', label: 'Episode Number', example: '16' }, { @@ -432,6 +438,11 @@ export const CONDITION_FIELD_CATEGORIES = { label: 'Days Until Next Season (TV)', example: '45', }, + { + field: 'daysAgoNextSeason', + label: 'Days Since Next Season Premiered (TV)', + example: '7', + }, { field: 'seasonNumber', label: 'Season Number', example: '5' }, { field: 'episodeNumber', label: 'Episode Number', example: '16' }, { field: 'episodeLabel', label: 'Episode Label', example: 'SERIES FINALE' }, @@ -560,6 +571,7 @@ export const SAMPLE_PREVIEW_CONTEXTS: { daysUntilNextEpisode: 7, // Days until next episode nextSeasonAirDate: '2025-02-05', // Next SEASON premiere (episode 1 only) daysUntilNextSeason: 45, // Days until next season + daysAgoNextSeason: undefined, // Not set when season hasn't aired yet daysAgo: 0, isMonitored: true, inSonarr: true,