Files
ersatztv/ErsatzTV.Application/ProgramSchedules/ScheduleItemResponseMapper.cs
T
timothyandClaude Fable 5 d7782dccac feat(api): flat schedule-item DTO + discovery endpoints (#126 #207 #212)
Task A (#126): new non-polymorphic ScheduleItemResponseModel /
ScheduleItemsResponseModel in Core/Api/Scheduling, plus shared
NamedIdResponseModel. ScheduleItemResponseMapper flattens the
One/Flood/Multiple/Duration VM hierarchy. ScheduleController GET/POST/PUT
items now return the flat DTOs.

Task B: GET /api/languages (LanguagesController + LanguageCodeResponseModel);
GET /api/channels/music-video-credits-templates and
GET /api/channels/stream-selectors; FillerKind added to
FillerPresetResponseModel with optional ?fillerKind= filter on
GET /api/filler-presets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:40:47 +02:00

110 lines
4.1 KiB
C#

using System.Collections.Generic;
using System.Linq;
using ErsatzTV.Core.Api;
using ErsatzTV.Core.Api.Scheduling;
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.ProgramSchedules;
/// <summary>
/// Maps the polymorphic <see cref="ProgramScheduleItemViewModel" /> hierarchy to the flat,
/// fully-described <see cref="ScheduleItemResponseModel" /> API DTO (issue #126). Subtype-specific
/// fields (Multiple's mode/count, Duration's playoutDuration/tailMode/discardToFillAttempts) are
/// read by pattern-matching the concrete VM type; they are null for other subtypes.
/// </summary>
public static class ScheduleItemResponseMapper
{
public static ScheduleItemResponseModel ProjectToResponseModel(ProgramScheduleItemViewModel item)
{
MultipleMode? multipleMode = null;
string multipleCount = null;
TimeSpan? playoutDuration = null;
TailMode? tailMode = null;
int? discardToFillAttempts = null;
switch (item)
{
case ProgramScheduleItemMultipleViewModel multiple:
multipleMode = multiple.MultipleMode;
multipleCount = multiple.Count;
break;
case ProgramScheduleItemDurationViewModel duration:
playoutDuration = duration.PlayoutDuration;
tailMode = duration.TailMode;
discardToFillAttempts = duration.DiscardToFillAttempts;
break;
}
List<int> watermarkIds = item.Watermarks?.Map(w => w.Id).ToList() ?? new List<int>();
List<int> graphicsElementIds = item.GraphicsElements?.Map(g => g.Id).ToList() ?? new List<int>();
List<NamedIdResponseModel> watermarks =
item.Watermarks?.Map(w => new NamedIdResponseModel(w.Id, w.Name)).ToList()
?? new List<NamedIdResponseModel>();
List<NamedIdResponseModel> graphicsElements =
item.GraphicsElements?.Map(g => new NamedIdResponseModel(g.Id, g.Name)).ToList()
?? new List<NamedIdResponseModel>();
return new ScheduleItemResponseModel(
item.Id,
item.Index,
item.StartType,
item.StartTime,
item.FixedStartTimeBehavior,
item.PlayoutMode,
item.CollectionType,
item.Collection?.Id,
item.MultiCollection?.Id,
item.SmartCollection?.Id,
item.RerunCollection?.Id,
item.MediaItem?.MediaItemId,
item.Playlist?.Id,
item.SearchTitle,
item.SearchQuery,
item.PlaybackOrder,
item.MarathonGroupBy,
item.MarathonShuffleGroups,
item.MarathonShuffleItems,
item.MarathonBatchSize,
item.FillWithGroupMode,
multipleMode,
multipleCount,
playoutDuration,
tailMode,
discardToFillAttempts,
item.CustomTitle,
item.GuideMode,
item.PreRollFiller?.Id,
item.MidRollFiller?.Id,
item.PostRollFiller?.Id,
item.TailFiller?.Id,
item.FallbackFiller?.Id,
watermarkIds,
graphicsElementIds,
item.PreferredAudioLanguageCode,
item.PreferredAudioTitle,
item.PreferredSubtitleLanguageCode,
item.SubtitleMode,
item.Collection?.Name,
item.MultiCollection?.Name,
item.SmartCollection?.Name,
item.RerunCollection?.Name,
item.Playlist?.Name,
item.Playlist?.PlaylistGroupId,
item.MediaItem?.Name,
item.PreRollFiller?.Name,
item.MidRollFiller?.Name,
item.PostRollFiller?.Name,
item.TailFiller?.Name,
item.FallbackFiller?.Name,
watermarks,
graphicsElements,
item.Name,
item.DurationEstimate);
}
public static ScheduleItemsResponseModel ProjectToResponseModel(ProgramScheduleItemsWithDurationViewModel vm) =>
new(
vm.Items.Map(ProjectToResponseModel).ToList(),
vm.TotalDurationEstimate);
}