From e73598d63f63a335d7fbd6db0daa7a37f5dd5b3d Mon Sep 17 00:00:00 2001 From: Adam Jacob Muller Date: Mon, 22 Dec 2025 21:13:29 -0500 Subject: [PATCH] Add flat API response DTOs for OpenAPI schema generation Create ApiResponseModels.cs with flat record types to replace complex nested ViewModels in API responses. This resolves JSON schema depth limit issues during OpenAPI generation. New DTOs include: - CollectionApiResponse, SmartCollectionApiResponse, MultiCollectionApiResponse - BlockItemApiResponse, PlaylistItemApiResponse, ScheduleItemApiResponse - WatermarkApiResponse, GraphicsElementApiResponse - DecoApiResponse, DecoBreakContentApiResponse - FillerPresetApiResponse, RerunCollectionApiResponse - MediaItemApiResponse, PlaylistApiResponse - PagedCollectionsApiResponse These flat structures avoid inheritance hierarchies that cause the OpenAPI schema generator to exceed MaxDepth limits. --- ErsatzTV/Controllers/Api/ApiResponseModels.cs | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 ErsatzTV/Controllers/Api/ApiResponseModels.cs diff --git a/ErsatzTV/Controllers/Api/ApiResponseModels.cs b/ErsatzTV/Controllers/Api/ApiResponseModels.cs new file mode 100644 index 000000000..c9ffedc1a --- /dev/null +++ b/ErsatzTV/Controllers/Api/ApiResponseModels.cs @@ -0,0 +1,202 @@ +#nullable enable +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Domain.Scheduling; +using ErsatzTV.Core.Scheduling; +using ErsatzTV.FFmpeg.State; + +namespace ErsatzTV.Controllers.Api; + +// Flat collection response (no inheritance from MediaCardViewModel) +public record CollectionApiResponse( + int Id, + string Name, + CollectionType CollectionType, + bool UseCustomPlaybackOrder, + MediaItemState State); + +// Flat smart collection response +public record SmartCollectionApiResponse( + int Id, + string Name, + string Query); + +// Flat multi-collection response with inline items +public record MultiCollectionApiResponse( + int Id, + string Name, + List Items, + List SmartItems); + +public record MultiCollectionItemApiResponse( + int MultiCollectionId, + int CollectionId, + string CollectionName, + CollectionType CollectionType, + bool UseCustomPlaybackOrder, + MediaItemState State, + bool ScheduleAsGroup, + PlaybackOrder PlaybackOrder); + +public record MultiCollectionSmartItemApiResponse( + int MultiCollectionId, + int SmartCollectionId, + string SmartCollectionName, + string Query, + bool ScheduleAsGroup, + PlaybackOrder PlaybackOrder); + +// Flat media item response +public record MediaItemApiResponse( + int MediaItemId, + string Name); + +// Block Item API Response - all data, flat structure +public record BlockItemApiResponse( + int Id, + int Index, + CollectionType CollectionType, + CollectionApiResponse? Collection, + MultiCollectionApiResponse? MultiCollection, + SmartCollectionApiResponse? SmartCollection, + MediaItemApiResponse? MediaItem, + string? SearchTitle, + string? SearchQuery, + PlaybackOrder PlaybackOrder, + bool IncludeInProgramGuide, + bool DisableWatermarks, + List Watermarks, + List GraphicsElements); + +public record WatermarkApiResponse( + int Id, + string Name, + string? ImagePath, + ChannelWatermarkMode Mode, + ChannelWatermarkImageSource ImageSource, + WatermarkLocation Location, + WatermarkSize Size, + double Width, + double HorizontalMargin, + double VerticalMargin, + int FrequencyMinutes, + int DurationSeconds, + int Opacity, + bool PlaceWithinSourceContent, + string? OpacityExpression, + int ZIndex); + +public record GraphicsElementApiResponse( + int Id, + string Name, + string FileName); + +// Playlist Item API Response - all data, flat structure +public record PlaylistItemApiResponse( + int Id, + int Index, + CollectionType CollectionType, + CollectionApiResponse? Collection, + MultiCollectionApiResponse? MultiCollection, + SmartCollectionApiResponse? SmartCollection, + MediaItemApiResponse? MediaItem, + PlaybackOrder PlaybackOrder, + int? Count, + bool PlayAll, + bool IncludeInProgramGuide); + +// Playlist response +public record PlaylistApiResponse( + int Id, + int PlaylistGroupId, + string Name, + bool IsSystem); + +// Rerun collection response +public record RerunCollectionApiResponse( + int Id, + string Name); + +// Filler preset response - flat +public record FillerPresetApiResponse( + int Id, + string Name); + +// Schedule Item API Response - all data, flat structure +public record ScheduleItemApiResponse( + int Id, + int Index, + StartType StartType, + TimeSpan? StartTime, + FixedStartTimeBehavior? FixedStartTimeBehavior, + PlayoutMode PlayoutMode, + CollectionType CollectionType, + CollectionApiResponse? Collection, + MultiCollectionApiResponse? MultiCollection, + SmartCollectionApiResponse? SmartCollection, + RerunCollectionApiResponse? RerunCollection, + PlaylistApiResponse? Playlist, + MediaItemApiResponse? MediaItem, + string? SearchTitle, + string? SearchQuery, + PlaybackOrder PlaybackOrder, + MarathonGroupBy MarathonGroupBy, + bool MarathonShuffleGroups, + bool MarathonShuffleItems, + int? MarathonBatchSize, + FillWithGroupMode FillWithGroupMode, + string? CustomTitle, + GuideMode GuideMode, + FillerPresetApiResponse? PreRollFiller, + FillerPresetApiResponse? MidRollFiller, + FillerPresetApiResponse? PostRollFiller, + FillerPresetApiResponse? TailFiller, + FillerPresetApiResponse? FallbackFiller, + List Watermarks, + List GraphicsElements, + string? PreferredAudioLanguageCode, + string? PreferredAudioTitle, + string? PreferredSubtitleLanguageCode, + ChannelSubtitleMode? SubtitleMode, + int? Count, + TimeSpan? PlayoutDuration); + +// Paged response types +public record PagedCollectionsApiResponse(int TotalCount, List Page); + +// Deco API Response - all data, flat structure +public record DecoApiResponse( + int Id, + int DecoGroupId, + string DecoGroupName, + string Name, + DecoMode WatermarkMode, + List Watermarks, + bool UseWatermarkDuringFiller, + DecoMode GraphicsElementsMode, + List GraphicsElements, + bool UseGraphicsElementsDuringFiller, + DecoMode BreakContentMode, + List BreakContent, + DecoMode DefaultFillerMode, + CollectionType DefaultFillerCollectionType, + CollectionApiResponse? DefaultFillerCollection, + MediaItemApiResponse? DefaultFillerMediaItem, + MultiCollectionApiResponse? DefaultFillerMultiCollection, + SmartCollectionApiResponse? DefaultFillerSmartCollection, + bool DefaultFillerTrimToFit, + DecoMode DeadAirFallbackMode, + CollectionType DeadAirFallbackCollectionType, + CollectionApiResponse? DeadAirFallbackCollection, + MediaItemApiResponse? DeadAirFallbackMediaItem, + MultiCollectionApiResponse? DeadAirFallbackMultiCollection, + SmartCollectionApiResponse? DeadAirFallbackSmartCollection); + +public record DecoBreakContentApiResponse( + int Id, + CollectionType CollectionType, + CollectionApiResponse? Collection, + MediaItemApiResponse? MediaItem, + MultiCollectionApiResponse? MultiCollection, + SmartCollectionApiResponse? SmartCollection, + PlaylistApiResponse? Playlist, + DecoBreakPlacement Placement);