Files
ersatztv/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs
T
timothyandClaude Fable 5 14d06a1e49
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 2m51s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m22s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
docs: note expression-based counts yield null duration estimate
Adversarial review finding on #111: MultipleMode.Count supports
expressions the estimator cannot evaluate; document that they
produce a null (unknown) estimate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 23:41:57 +02:00

96 lines
4.2 KiB
C#

using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Scheduling;
namespace ErsatzTV.Application.ProgramSchedules;
public abstract record ProgramScheduleItemViewModel(
int Id,
int Index,
StartType StartType,
TimeSpan? StartTime,
FixedStartTimeBehavior? FixedStartTimeBehavior,
PlayoutMode PlayoutMode,
CollectionType CollectionType,
MediaCollectionViewModel Collection,
MultiCollectionViewModel MultiCollection,
SmartCollectionViewModel SmartCollection,
RerunCollectionViewModel RerunCollection,
PlaylistViewModel Playlist,
NamedMediaItemViewModel MediaItem,
string SearchTitle,
string SearchQuery,
PlaybackOrder PlaybackOrder,
MarathonGroupBy MarathonGroupBy,
bool MarathonShuffleGroups,
bool MarathonShuffleItems,
int? MarathonBatchSize,
FillWithGroupMode FillWithGroupMode,
string CustomTitle,
GuideMode GuideMode,
FillerPresetViewModel PreRollFiller,
FillerPresetViewModel MidRollFiller,
FillerPresetViewModel PostRollFiller,
FillerPresetViewModel TailFiller,
FillerPresetViewModel FallbackFiller,
List<WatermarkViewModel> Watermarks,
List<GraphicsElementViewModel> GraphicsElements,
string PreferredAudioLanguageCode,
string PreferredAudioTitle,
string PreferredSubtitleLanguageCode,
ChannelSubtitleMode? SubtitleMode)
{
/// <summary>
/// A rough estimate, in wall-clock time, of how long a single pass of this schedule item will play,
/// derived from the aggregated playout runtimes of the referenced content.
/// <para>
/// Semantics by <see cref="PlayoutMode" />:
/// <list type="bullet">
/// <item><b>One</b> — the average runtime of one item in the referenced collection.</item>
/// <item>
/// <b>Multiple</b> — the average item runtime multiplied by the configured count
/// (<see cref="MultipleMode.Count" />), or the whole collection runtime for
/// <see cref="MultipleMode.CollectionSize" />. An expression-based (non-integer)
/// count cannot be evaluated here and yields <c>null</c>.
/// </item>
/// <item><b>Flood</b> — always <c>null</c>: a flood item fills the remaining time and is unbounded.</item>
/// <item><b>Duration</b> — the explicit <c>playoutDuration</c> setting on the item.</item>
/// </list>
/// </para>
/// <para>
/// <c>null</c> whenever a bounded estimate cannot be produced — an unbounded mode (Flood),
/// a referenced collection with no items that have a known positive duration, a Multiple mode other
/// than Count/CollectionSize, or a collection type other than <see cref="CollectionType.Collection" />
/// (smart/multi/playlist/search/rerun/show/season/artist references are not aggregated in this pass).
/// Callers should treat a <c>null</c> as "unknown", never as zero.
/// </para>
/// </summary>
public TimeSpan? DurationEstimate { get; init; }
public string Name => CollectionType switch
{
CollectionType.Collection => Collection?.Name,
CollectionType.TelevisionShow =>
MediaItem?.Name, // $"{TelevisionShow?.Title} ({TelevisionShow?.Year})",
CollectionType.TelevisionSeason =>
MediaItem?.Name, // $"{TelevisionSeason?.Title} ({TelevisionSeason?.Plot})",
CollectionType.Artist =>
MediaItem?.Name,
CollectionType.MultiCollection =>
MultiCollection?.Name,
CollectionType.SmartCollection =>
SmartCollection?.Name,
CollectionType.SearchQuery =>
string.IsNullOrWhiteSpace(SearchTitle) ? SearchQuery : SearchTitle,
CollectionType.Playlist =>
Playlist?.Name,
CollectionType.RerunFirstRun or CollectionType.RerunRerun =>
RerunCollection?.Name,
_ => string.Empty
};
}