Files
ersatztv/docs/channels.md
Timothy f1e97b94a7
Some checks failed
Build / Calculate version information (push) Successful in 13s
Build / build_and_upload (push) Failing after 0s
Build / build_images (push) Failing after 0s
Close stale issues / stale (push) Successful in 15s
Add architecture docs and fork maintenance strategy (#6)
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>
2026-03-17 22:42:07 +01:00

4.5 KiB

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 PlayoutProgramScheduleProgramScheduleItem 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.