Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ErsatzTV/legacy/llms.txt

Use this file to discover all available pages before exploring further.

A playout is the computed, time-stamped list of media items that ErsatzTV will play on a channel. It is the concrete product of resolving a schedule against your media library: when ErsatzTV builds a playout, it walks through schedule items, expands collections into individual media items, assigns precise start and finish timestamps to each, and stores the result as a sequence of PlayoutItem records. The streaming engine reads these records in real time to decide what to transcode and deliver to viewers.

The Role of a Playout

Channels and schedules do not interact directly. The playout is the joining entity between them. A Channel has a List<Playout> — meaning one channel can have multiple active playouts simultaneously — and each playout references both the channel and the schedule that drives it.
// From ErsatzTV.Core.Domain.Channel
public List<Playout> Playouts { get; set; }

// From ErsatzTV.Core.Domain.Playout
public int ChannelId { get; set; }
public Channel Channel { get; set; }
public int? ProgramScheduleId { get; set; }
public ProgramSchedule ProgramSchedule { get; set; }
public string ScheduleFile { get; set; }
public PlayoutScheduleKind ScheduleKind { get; set; }
Having multiple playouts on a single channel is useful in advanced configurations — for example, when combining a primary schedule playout with an on-demand playout that can be triggered independently.

Schedule Kinds

The ScheduleKind property (PlayoutScheduleKind) identifies which type of schedule is powering this playout:
KindValueSource of Truth
None0No schedule assigned; the playout is empty.
Classic1A ProgramSchedule object (referenced by ProgramScheduleId).
Block2Block templates and decos, resolved via Templates.
Sequential3A YAML file at the path in ScheduleFile.
Scripted4A Python script at the path in ScheduleFile.
ExternalJson20A JSON document at the path in ScheduleFile.
For Classic schedules, the schedule definition lives in the database. For Sequential, Scripted, and ExternalJson schedules, it lives in a file on disk referenced by ScheduleFile.

Playout Items

Each PlayoutItem represents one media item placed at a specific point in time in the playout:
PropertyDescription
MediaItemIdThe database ID of the media item to play.
Start / FinishUTC timestamps defining when the item begins and ends.
GuideStart / GuideFinishOptional override timestamps used in EPG output, allowing guide data to differ from actual playout times.
CustomTitleAn optional title override displayed in the EPG instead of the media item’s real title.
FillerKindWhether this item is primary content or a specific filler type (pre-roll, mid-roll, post-roll, tail, fallback).
InPoint / OutPointTrim points within the media file — used when scheduling a chapter or a clipped segment.
ChapterTitleWhen playing a specific chapter, the title of that chapter.
GuideGroupGroups multiple items that should appear as a single entry in the EPG (e.g., a movie split across a commercial break).
BlockKey / CollectionKeyString keys identifying which block and collection this item belongs to — used for history tracking.

The Playout Anchor

The PlayoutAnchor is ErsatzTV’s bookmark into the current state of the playout build. It tracks:
PropertyDescription
NextStartThe UTC DateTime at which the next item should be placed.
ScheduleItemsEnumeratorStateThe current position within the schedule item list.
MultipleRemainingFor Multiple-mode items, how many more items remain in the current slot.
DurationFinishFor Duration-mode items, the UTC time at which the duration budget is exhausted.
InFloodWhether the build is currently in a flood-fill phase.
InDurationFillerWhether the build is currently filling with duration filler.
NextGuideGroupCounter for assigning guide group IDs to items.
NextInstructionIndexUsed by Block and Scripted schedules to track position within instruction sequences.
The anchor is persisted to the database so that incremental playout builds can resume from the correct position rather than rebuilding from the beginning every time.

Playout Build Process

ErsatzTV builds playouts as a background service. The build process:
1

Resolve the Schedule

ErsatzTV reads the schedule definition — from the database for Classic schedules, or from the file system for YAML/Scripted/ExternalJson. For Block schedules, it evaluates which templates apply to the current date based on day-of-week, day-of-month, and date range rules.
2

Enumerate Collections

Each schedule item’s collection, multi-collection, smart collection, playlist, or search query is resolved into a concrete ordered list of media items. Playback order (Chronological, Shuffle, SeasonEpisode, etc.) is applied at this step.
3

Place Items on the Timeline

Items are assigned Start and Finish timestamps. Fixed-time slots snap items to clock times; dynamic (flood/back-to-back) items are placed end-to-end. Filler items are inserted to fill gaps.
4

Persist the Playout

The resulting PlayoutItem records are written to the database. Gaps (PlayoutGap) are recorded for any spans of time in the playout that have no coverage. The PlayoutBuildStatus record is updated with the build result and timestamp.
Playouts are typically extended automatically as the current time approaches the end of the existing built window. The DailyRebuildTime property (TimeSpan?) can be set to force a full playout rebuild at a specific time of day — useful for Block schedules where each day’s programming is determined by template matching.

Playout Build Status

The PlayoutBuildStatus entity tracks the outcome of the most recent build for each playout:
PropertyDescription
LastBuildThe timestamp of the most recent build attempt.
SuccessWhether the build completed successfully.
MessageAn error or informational message from the build, if any.
If Success is false, check the Message for details about what went wrong — common causes include missing media files, empty collections, or invalid schedule configurations.

Playout History

For Block schedules, ErsatzTV maintains a PlayoutHistory table that records which item from each collection was most recently played in each block:
// From ErsatzTV.Core.Domain.Scheduling.PlayoutHistory
public int BlockId { get; set; }
public PlaybackOrder PlaybackOrder { get; set; }
public int Index { get; set; }
public string Key { get; set; }          // identifies the collection within the block
public string ChildKey { get; set; }     // identifies a child within a parent collection
public bool IsCurrentChild { get; set; } // marks the active child in multi-child collections
public DateTime When { get; set; }       // when the item last played
public DateTime Finish { get; set; }     // when the item's timeslot ended
public string Details { get; set; }      // item details for debugging
Playout history is maintained exclusively for Block schedules. It enables ErsatzTV to resume playback of each block’s collection from the correct position after a daily rebuild or playout reset, preserving your channel’s continuity across rebuilds.

Playout Seed

The Seed property (int) is a random seed stored on the playout. It is used to initialize shuffle and random operations during playout builds, ensuring that a given playout always produces the same random ordering when rebuilt with the same seed. You can change the seed to produce a different shuffle sequence.

Playout Templates (Block Schedules)

For Block schedule playouts, the Templates collection holds PlayoutTemplate entries that map programming templates to calendar conditions:
PropertyDescription
TemplateIdThe Block template to use.
DecoTemplateIdAn optional Deco template to layer over the block.
DaysOfWeekWhich days of the week this template applies to.
DaysOfMonthWhich days of the month this template applies to.
MonthsOfYearWhich months of the year this template applies to.
LimitToDateRangeWhen true, restricts the template to the specified date range.
StartMonthMonth component of the range start date (int).
StartDayDay component of the range start date (int).
StartYearOptional year component of the range start date (int?).
EndMonthMonth component of the range end date (int).
EndDayDay component of the range end date (int).
EndYearOptional year component of the range end date (int?).
ErsatzTV evaluates templates in index order and selects the first matching template for each day.

Playout Offset

The EPG display times for a playout’s items can be shifted by configuring PlayoutOffset (TimeSpan?) on the channel — not the playout itself. This channel-level setting is applied when generating XMLTV guide data, allowing the displayed program times to be offset from the actual playout timestamps. See Channels for details on setting this property.

On-Demand Playouts

When a channel’s PlayoutMode is set to OnDemand, the playout behaves differently from a continuous channel:
  • Items are added to the playout queue when a viewer requests content
  • After a viewer finishes watching an item, that item is automatically removed from the playout
  • The OnDemandCheckpoint (DateTimeOffset?) property tracks the last-acknowledged position for resuming on-demand playback
On-demand channels are useful for creating watch-on-request channels where content plays when a viewer tunes in, rather than running a fixed live schedule.

Fill Group Indices

The FillGroupIndices collection (List<PlayoutScheduleItemFillGroupIndex>) tracks the current position within each schedule item’s filler group. This enables ErsatzTV to continue cycling through filler content correctly across playout rebuild boundaries, rather than restarting from the first filler item each time.

Alternate Schedules on Playouts

For Classic schedule playouts, ProgramScheduleAlternates allows override schedules to be evaluated before the primary schedule. Alternate schedules can target specific days of the week, date ranges, or other conditions — enabling seasonal or special-event programming without creating a separate playout for each variant.

Resetting a Playout

You can force a full playout rebuild via the API. Resetting discards all existing PlayoutItem records and rebuilds the timeline from scratch:
POST /api/channels/{channelNumber}/playout/reset
Resetting a playout will discard the current playout anchor and all scheduled items. The channel may briefly display the fallback filler or go dark while the new playout is being built. For Block schedule playouts, history is preserved across resets so that playback resumes from the correct collection position.
For full API reference, see Channels API.

Gaps

When the playout builder cannot fill a span of time — because a collection is empty, a file is missing, or filler runs out — it records a PlayoutGap:
public class PlayoutGap
{
    public DateTime Start { get; set; }
    public DateTime Finish { get; set; }
}
Gaps represent dead air. The channel’s FallbackFiller (if configured) is the last line of defense against gaps. Monitor the build status and any recorded gaps after a rebuild to diagnose scheduling or library issues.

Build docs developers (and LLMs) love