Document channel architecture, M3U/XMLTV integration with Jellyfin, and fork maintenance strategy for the archived upstream. Also includes CLAUDE.md updates for implementer workflow and project boundaries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
99 lines
4.5 KiB
Markdown
99 lines
4.5 KiB
Markdown
# Channel Architecture
|
|
|
|
## Channel Entity
|
|
|
|
Defined in `ErsatzTV.Core/Domain/Channel.cs`. Key fields:
|
|
|
|
- **Identity**: `Number` (e.g., "1", "2.1"), `Name`, `UniqueId` (GUID for M3U/XMLTV)
|
|
- **Encoding**: `FFmpegProfileId` — video/audio codec, bitrate, resolution, hardware acceleration
|
|
- **Streaming**: `StreamingMode` (TransportStream, HLS Direct, HLS Segmenter, TS Hybrid)
|
|
- **Behavior**: `PlayoutMode` (Continuous vs OnDemand), `IdleBehavior` (StopOnDisconnect vs KeepRunning)
|
|
- **Visual**: `WatermarkId`, `FallbackFillerId`, artwork (logos)
|
|
- **Mirroring**: `PlayoutSource` (Generated vs Mirror) — a mirror channel copies another with optional time offset
|
|
- **Display**: `Group`, `Categories`, `ShowInEpg`, `IsEnabled`
|
|
- **Audio/Subtitle defaults**: preferred language codes, subtitle mode
|
|
|
|
## Content Sources
|
|
|
|
Channels get content through a **Playout** → **ProgramSchedule** → **ProgramScheduleItem** chain.
|
|
|
|
### Collection Types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `Collection` | Manual grouping of media items with custom playback order |
|
|
| `MultiCollection` | Aggregate of collections + smart collections |
|
|
| `SmartCollection` | Query-based (Lucene.Net) dynamic filtering |
|
|
| `Playlist` | Ordered items with per-item config (count, fillers, playback order) |
|
|
| `TelevisionShow` / `TelevisionSeason` | Structured TV hierarchy |
|
|
| `Movie`, `Episode`, `MusicVideo`, `OtherVideo`, `Song`, `Image` | Individual media items |
|
|
| `RerunCollection` | Wraps any collection with separate first-run/rerun playback orders |
|
|
| `SearchQuery` | Dynamic results from a search |
|
|
| `RemoteStream` | External stream URLs |
|
|
|
|
### Media Sources
|
|
|
|
Media items are imported from configured libraries (Jellyfin, Plex, Emby, or local filesystem). Each source type has its own entity variants (e.g., `JellyfinMovie`, `PlexEpisode`).
|
|
|
|
## Scheduling
|
|
|
|
### Schedule Kinds
|
|
|
|
- **Classic**: Traditional ProgramSchedule with items — the most common
|
|
- **Block**: Template-based block scheduling
|
|
- **Sequential**: Strict sequential ordering
|
|
- **Scripted**: External script-driven playout
|
|
- **ExternalJson**: Playout defined by external JSON file
|
|
|
|
### Schedule Item Types
|
|
|
|
Each `ProgramScheduleItem` is one of four concrete types:
|
|
|
|
1. **One** — Play exactly 1 item per cycle
|
|
2. **Multiple** — Play N items (fixed count, collection size, or playlist item size)
|
|
3. **Duration** — Fill a time window (with tail mode: none, offline, slate, or filler)
|
|
4. **Flood** — Play items continuously until the next fixed-start item
|
|
|
|
Items can have `StartType` of Fixed (anchored to clock time) or Dynamic (follows previous item).
|
|
|
|
### Playback Orders
|
|
|
|
`Chronological`, `Random`, `Shuffle`, `ShuffleInOrder`, `MultiEpisodeShuffle`, `SeasonEpisode`, `RandomRotation`, `Marathon` (group by show/season/artist/album/director).
|
|
|
|
### Filler System
|
|
|
|
`FillerPreset` defines content to fill gaps. Each schedule item can have:
|
|
- **PreRoll** — before main content
|
|
- **MidRoll** — during (chapter breaks)
|
|
- **PostRoll** — after main content
|
|
- **Tail** — pad remaining time in a duration block
|
|
- **Fallback** — channel-level default when nothing else available
|
|
|
|
Filler modes: Duration, Count, Pad (to nearest minute), RandomCount.
|
|
|
|
### Alternate Schedules
|
|
|
|
`ProgramScheduleAlternate` overrides the main schedule for specific days of week, days of month, months of year, or date ranges. Useful for seasonal programming or weekend variations.
|
|
|
|
## Playout Pipeline
|
|
|
|
```
|
|
Channel
|
|
└── Playout
|
|
├── ProgramSchedule
|
|
│ └── ProgramScheduleItems (One|Multiple|Duration|Flood)
|
|
│ └── Content source (Collection, Playlist, SmartCollection, etc.)
|
|
├── PlayoutItems (generated — the actual timeline)
|
|
│ └── MediaItem + start/finish times + filler kind + watermarks
|
|
├── PlayoutGaps (time periods with no content)
|
|
└── ProgramScheduleAlternates (day/date overrides)
|
|
```
|
|
|
|
The scheduling engine (`ErsatzTV.Core/Scheduling/`) resolves schedule items into concrete `PlayoutItem` entries with precise start/finish times. Each `PlayoutItem` references a specific `MediaItem` and includes trim points (`InPoint`/`OutPoint`), filler classification, and per-item audio/subtitle overrides.
|
|
|
|
## Watermarks
|
|
|
|
`ChannelWatermark` supports modes: Permanent, Intermittent, OpacityExpression. Image sources: custom upload, channel logo, or built-in resource. Positioned with percentage-based margins and z-index.
|
|
|
|
Note: `ChannelLogoGenerator.GenerateChannelLogoUrl()` hardcodes `localhost` for watermark logo fetching — see issue #1 for details.
|