Browse Source

add graphics elements on classic schedule items (#2380)

pull/2369/head
Jason Dove 11 months ago committed by GitHub
parent
commit
40ab7c2cff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 7
      ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs
  3. 2
      ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs
  4. 9
      ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramScheduleHandler.cs
  5. 1
      ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs
  6. 11
      ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs
  7. 1
      ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs
  8. 8
      ErsatzTV.Application/ProgramSchedules/Mapper.cs
  9. 3
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs
  10. 3
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs
  11. 3
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs
  12. 3
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs
  13. 2
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs
  14. 2
      ErsatzTV.Application/ProgramSchedules/Queries/GetProgramScheduleItemsHandler.cs
  15. 7
      ErsatzTV.Core.Tests/Scheduling/ScheduleIntegrationTests.cs
  16. 2
      ErsatzTV.Core/Domain/GraphicsElement.cs
  17. 2
      ErsatzTV.Core/Domain/ProgramScheduleItem.cs
  18. 9
      ErsatzTV.Core/Domain/ProgramScheduleItemGraphicsElement.cs
  19. 14
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs
  20. 14
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs
  21. 14
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerMultiple.cs
  22. 14
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerOne.cs
  23. 6366
      ErsatzTV.Infrastructure.MySql/Migrations/20250905114217_Add_ProgramScheduleItemGraphicsElements.Designer.cs
  24. 51
      ErsatzTV.Infrastructure.MySql/Migrations/20250905114217_Add_ProgramScheduleItemGraphicsElements.cs
  25. 38
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  26. 6201
      ErsatzTV.Infrastructure.Sqlite/Migrations/20250905114029_Add_ProgramScheduleItemGraphicsElements.Designer.cs
  27. 50
      ErsatzTV.Infrastructure.Sqlite/Migrations/20250905114029_Add_ProgramScheduleItemGraphicsElements.cs
  28. 38
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  29. 13
      ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleItemConfiguration.cs
  30. 24
      ErsatzTV/Pages/ScheduleItemsEditor.razor
  31. 2
      ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

3
CHANGELOG.md

@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Added
- Classic schedules: allow selecting multiple graphics elements on schedule items
### Fixed ### Fixed
- Fix transcoding content with bt709/pc color metadata - Fix transcoding content with bt709/pc color metadata
- Fix scripted schedule validation (file exists) when creating or editing playout - Fix scripted schedule validation (file exists) when creating or editing playout

7
ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs

@ -375,6 +375,9 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
.ThenInclude(psi => psi.ProgramScheduleItemWatermarks) .ThenInclude(psi => psi.ProgramScheduleItemWatermarks)
.ThenInclude(psi => psi.Watermark) .ThenInclude(psi => psi.Watermark)
.Include(ps => ps.Items) .Include(ps => ps.Items)
.ThenInclude(psi => psi.ProgramScheduleItemGraphicsElements)
.ThenInclude(psi => psi.GraphicsElement)
.Include(ps => ps.Items)
.ThenInclude(psi => psi.Collection) .ThenInclude(psi => psi.Collection)
.Include(ps => ps.Items) .Include(ps => ps.Items)
.ThenInclude(psi => psi.MediaItem) .ThenInclude(psi => psi.MediaItem)
@ -399,6 +402,10 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
.ThenInclude(psi => psi.Watermark) .ThenInclude(psi => psi.Watermark)
.Include(a => a.ProgramSchedule) .Include(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items) .ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.ProgramScheduleItemGraphicsElements)
.ThenInclude(psi => psi.GraphicsElement)
.Include(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.Collection) .ThenInclude(psi => psi.Collection)
.Include(a => a.ProgramSchedule) .Include(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items) .ThenInclude(ps => ps.Items)

2
ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs

@ -30,8 +30,8 @@ public record AddProgramScheduleItem(
int? PostRollFillerId, int? PostRollFillerId,
int? TailFillerId, int? TailFillerId,
int? FallbackFillerId, int? FallbackFillerId,
int? WatermarkId,
List<int> WatermarkIds, List<int> WatermarkIds,
List<int> GraphicsElementIds,
string PreferredAudioLanguageCode, string PreferredAudioLanguageCode,
string PreferredAudioTitle, string PreferredAudioTitle,
string PreferredSubtitleLanguageCode, string PreferredSubtitleLanguageCode,

9
ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramScheduleHandler.cs

@ -56,6 +56,13 @@ public class
watermark.ProgramScheduleItemId = 0; watermark.ProgramScheduleItemId = 0;
watermark.ProgramScheduleItem = item; watermark.ProgramScheduleItem = item;
} }
foreach (ProgramScheduleItemGraphicsElement graphicsElement in item.ProgramScheduleItemGraphicsElements)
{
DetachEntity(dbContext, graphicsElement);
graphicsElement.ProgramScheduleItemId = 0;
graphicsElement.ProgramScheduleItem = item;
}
} }
await dbContext.ProgramSchedules.AddAsync(schedule, cancellationToken); await dbContext.ProgramSchedules.AddAsync(schedule, cancellationToken);
@ -81,6 +88,8 @@ public class
.AsNoTracking() .AsNoTracking()
.Include(ps => ps.Items) .Include(ps => ps.Items)
.ThenInclude(ps => ps.ProgramScheduleItemWatermarks) .ThenInclude(ps => ps.ProgramScheduleItemWatermarks)
.Include(ps => ps.Items)
.ThenInclude(ps => ps.ProgramScheduleItemGraphicsElements)
.SelectOneAsync(p => p.Id, p => p.Id == request.ProgramScheduleId, cancellationToken) .SelectOneAsync(p => p.Id, p => p.Id == request.ProgramScheduleId, cancellationToken)
.Map(o => o.ToValidation<BaseError>("Schedule does not exist.")); .Map(o => o.ToValidation<BaseError>("Schedule does not exist."));

1
ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs

@ -29,6 +29,7 @@ public interface IProgramScheduleItemRequest
int? TailFillerId { get; } int? TailFillerId { get; }
int? FallbackFillerId { get; } int? FallbackFillerId { get; }
List<int> WatermarkIds { get; } List<int> WatermarkIds { get; }
List<int> GraphicsElementIds { get; }
string PreferredAudioLanguageCode { get; } string PreferredAudioLanguageCode { get; }
string PreferredAudioTitle { get; } string PreferredAudioTitle { get; }
string PreferredSubtitleLanguageCode { get; } string PreferredSubtitleLanguageCode { get; }

11
ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs

@ -314,6 +314,17 @@ public abstract class ProgramScheduleItemCommandBase
}); });
} }
foreach (int graphicsElementId in item.GraphicsElementIds)
{
result.ProgramScheduleItemGraphicsElements ??= [];
result.ProgramScheduleItemGraphicsElements.Add(
new ProgramScheduleItemGraphicsElement
{
ProgramScheduleItem = result,
GraphicsElementId = graphicsElementId
});
}
return result; return result;
} }

1
ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs

@ -31,6 +31,7 @@ public record ReplaceProgramScheduleItem(
int? TailFillerId, int? TailFillerId,
int? FallbackFillerId, int? FallbackFillerId,
List<int> WatermarkIds, List<int> WatermarkIds,
List<int> GraphicsElementIds,
string PreferredAudioLanguageCode, string PreferredAudioLanguageCode,
string PreferredAudioTitle, string PreferredAudioTitle,
string PreferredSubtitleLanguageCode, string PreferredSubtitleLanguageCode,

8
ErsatzTV.Application/ProgramSchedules/Mapper.cs

@ -68,6 +68,8 @@ internal static class Mapper
: null, : null,
duration.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark)) duration.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark))
.ToList(), .ToList(),
duration.ProgramScheduleItemGraphicsElements.Map(ge => Graphics.Mapper.ProjectToViewModel(ge.GraphicsElement))
.ToList(),
duration.PreferredAudioLanguageCode, duration.PreferredAudioLanguageCode,
duration.PreferredAudioTitle, duration.PreferredAudioTitle,
duration.PreferredSubtitleLanguageCode, duration.PreferredSubtitleLanguageCode,
@ -120,6 +122,8 @@ internal static class Mapper
: null, : null,
flood.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark)) flood.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark))
.ToList(), .ToList(),
flood.ProgramScheduleItemGraphicsElements.Map(ge => Graphics.Mapper.ProjectToViewModel(ge.GraphicsElement))
.ToList(),
flood.PreferredAudioLanguageCode, flood.PreferredAudioLanguageCode,
flood.PreferredAudioTitle, flood.PreferredAudioTitle,
flood.PreferredSubtitleLanguageCode, flood.PreferredSubtitleLanguageCode,
@ -174,6 +178,8 @@ internal static class Mapper
: null, : null,
multiple.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark)) multiple.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark))
.ToList(), .ToList(),
multiple.ProgramScheduleItemGraphicsElements.Map(ge => Graphics.Mapper.ProjectToViewModel(ge.GraphicsElement))
.ToList(),
multiple.PreferredAudioLanguageCode, multiple.PreferredAudioLanguageCode,
multiple.PreferredAudioTitle, multiple.PreferredAudioTitle,
multiple.PreferredSubtitleLanguageCode, multiple.PreferredSubtitleLanguageCode,
@ -226,6 +232,8 @@ internal static class Mapper
: null, : null,
one.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark)) one.ProgramScheduleItemWatermarks.Map(wm => Watermarks.Mapper.ProjectToViewModel(wm.Watermark))
.ToList(), .ToList(),
one.ProgramScheduleItemGraphicsElements.Map(ge => Graphics.Mapper.ProjectToViewModel(ge.GraphicsElement))
.ToList(),
one.PreferredAudioLanguageCode, one.PreferredAudioLanguageCode,
one.PreferredAudioTitle, one.PreferredAudioTitle,
one.PreferredSubtitleLanguageCode, one.PreferredSubtitleLanguageCode,

3
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs

@ -1,4 +1,5 @@
using ErsatzTV.Application.Filler; using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems; using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks; using ErsatzTV.Application.Watermarks;
@ -34,6 +35,7 @@ public record ProgramScheduleItemDurationViewModel : ProgramScheduleItemViewMode
FillerPresetViewModel tailFiller, FillerPresetViewModel tailFiller,
FillerPresetViewModel fallbackFiller, FillerPresetViewModel fallbackFiller,
List<WatermarkViewModel> watermarks, List<WatermarkViewModel> watermarks,
List<GraphicsElementViewModel> graphicsElements,
string preferredAudioLanguageCode, string preferredAudioLanguageCode,
string preferredAudioTitle, string preferredAudioTitle,
string preferredSubtitleLanguageCode, string preferredSubtitleLanguageCode,
@ -60,6 +62,7 @@ public record ProgramScheduleItemDurationViewModel : ProgramScheduleItemViewMode
tailFiller, tailFiller,
fallbackFiller, fallbackFiller,
watermarks, watermarks,
graphicsElements,
preferredAudioLanguageCode, preferredAudioLanguageCode,
preferredAudioTitle, preferredAudioTitle,
preferredSubtitleLanguageCode, preferredSubtitleLanguageCode,

3
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs

@ -1,4 +1,5 @@
using ErsatzTV.Application.Filler; using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems; using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks; using ErsatzTV.Application.Watermarks;
@ -31,6 +32,7 @@ public record ProgramScheduleItemFloodViewModel : ProgramScheduleItemViewModel
FillerPresetViewModel tailFiller, FillerPresetViewModel tailFiller,
FillerPresetViewModel fallbackFiller, FillerPresetViewModel fallbackFiller,
List<WatermarkViewModel> watermarks, List<WatermarkViewModel> watermarks,
List<GraphicsElementViewModel> graphicsElements,
string preferredAudioLanguageCode, string preferredAudioLanguageCode,
string preferredAudioTitle, string preferredAudioTitle,
string preferredSubtitleLanguageCode, string preferredSubtitleLanguageCode,
@ -57,6 +59,7 @@ public record ProgramScheduleItemFloodViewModel : ProgramScheduleItemViewModel
tailFiller, tailFiller,
fallbackFiller, fallbackFiller,
watermarks, watermarks,
graphicsElements,
preferredAudioLanguageCode, preferredAudioLanguageCode,
preferredAudioTitle, preferredAudioTitle,
preferredSubtitleLanguageCode, preferredSubtitleLanguageCode,

3
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs

@ -1,4 +1,5 @@
using ErsatzTV.Application.Filler; using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems; using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks; using ErsatzTV.Application.Watermarks;
@ -33,6 +34,7 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
FillerPresetViewModel tailFiller, FillerPresetViewModel tailFiller,
FillerPresetViewModel fallbackFiller, FillerPresetViewModel fallbackFiller,
List<WatermarkViewModel> watermarks, List<WatermarkViewModel> watermarks,
List<GraphicsElementViewModel> graphicsElements,
string preferredAudioLanguageCode, string preferredAudioLanguageCode,
string preferredAudioTitle, string preferredAudioTitle,
string preferredSubtitleLanguageCode, string preferredSubtitleLanguageCode,
@ -59,6 +61,7 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
tailFiller, tailFiller,
fallbackFiller, fallbackFiller,
watermarks, watermarks,
graphicsElements,
preferredAudioLanguageCode, preferredAudioLanguageCode,
preferredAudioTitle, preferredAudioTitle,
preferredSubtitleLanguageCode, preferredSubtitleLanguageCode,

3
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs

@ -1,4 +1,5 @@
using ErsatzTV.Application.Filler; using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems; using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks; using ErsatzTV.Application.Watermarks;
@ -31,6 +32,7 @@ public record ProgramScheduleItemOneViewModel : ProgramScheduleItemViewModel
FillerPresetViewModel tailFiller, FillerPresetViewModel tailFiller,
FillerPresetViewModel fallbackFiller, FillerPresetViewModel fallbackFiller,
List<WatermarkViewModel> watermarks, List<WatermarkViewModel> watermarks,
List<GraphicsElementViewModel> graphicsElements,
string preferredAudioLanguageCode, string preferredAudioLanguageCode,
string preferredAudioTitle, string preferredAudioTitle,
string preferredSubtitleLanguageCode, string preferredSubtitleLanguageCode,
@ -57,6 +59,7 @@ public record ProgramScheduleItemOneViewModel : ProgramScheduleItemViewModel
tailFiller, tailFiller,
fallbackFiller, fallbackFiller,
watermarks, watermarks,
graphicsElements,
preferredAudioLanguageCode, preferredAudioLanguageCode,
preferredAudioTitle, preferredAudioTitle,
preferredSubtitleLanguageCode, preferredSubtitleLanguageCode,

2
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs

@ -1,4 +1,5 @@
using ErsatzTV.Application.Filler; using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems; using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks; using ErsatzTV.Application.Watermarks;
@ -30,6 +31,7 @@ public abstract record ProgramScheduleItemViewModel(
FillerPresetViewModel TailFiller, FillerPresetViewModel TailFiller,
FillerPresetViewModel FallbackFiller, FillerPresetViewModel FallbackFiller,
List<WatermarkViewModel> Watermarks, List<WatermarkViewModel> Watermarks,
List<GraphicsElementViewModel> GraphicsElements,
string PreferredAudioLanguageCode, string PreferredAudioLanguageCode,
string PreferredAudioTitle, string PreferredAudioTitle,
string PreferredSubtitleLanguageCode, string PreferredSubtitleLanguageCode,

2
ErsatzTV.Application/ProgramSchedules/Queries/GetProgramScheduleItemsHandler.cs

@ -47,6 +47,8 @@ public class GetProgramScheduleItemsHandler(IDbContextFactory<TvContext> dbConte
.Include(i => i.FallbackFiller) .Include(i => i.FallbackFiller)
.Include(i => i.ProgramScheduleItemWatermarks) .Include(i => i.ProgramScheduleItemWatermarks)
.ThenInclude(i => i.Watermark) .ThenInclude(i => i.Watermark)
.Include(i => i.ProgramScheduleItemGraphicsElements)
.ThenInclude(i => i.GraphicsElement)
.ToListAsync(cancellationToken) .ToListAsync(cancellationToken)
.Map(programScheduleItems => programScheduleItems.Map(ProjectToViewModel) .Map(programScheduleItems => programScheduleItems.Map(ProjectToViewModel)
.Map(psi => EnforceProperties(maybeProgramSchedule, psi)).ToList()); .Map(psi => EnforceProperties(maybeProgramSchedule, psi)).ToList());

7
ErsatzTV.Core.Tests/Scheduling/ScheduleIntegrationTests.cs

@ -439,6 +439,9 @@ public class ScheduleIntegrationTests
.ThenInclude(psi => psi.ProgramScheduleItemWatermarks) .ThenInclude(psi => psi.ProgramScheduleItemWatermarks)
.ThenInclude(psi => psi.Watermark) .ThenInclude(psi => psi.Watermark)
.Include(ps => ps.Items) .Include(ps => ps.Items)
.ThenInclude(psi => psi.ProgramScheduleItemGraphicsElements)
.ThenInclude(psi => psi.GraphicsElement)
.Include(ps => ps.Items)
.ThenInclude(psi => psi.Collection) .ThenInclude(psi => psi.Collection)
.Include(ps => ps.Items) .Include(ps => ps.Items)
.ThenInclude(psi => psi.MediaItem) .ThenInclude(psi => psi.MediaItem)
@ -463,6 +466,10 @@ public class ScheduleIntegrationTests
.ThenInclude(psi => psi.Watermark) .ThenInclude(psi => psi.Watermark)
.Include(a => a.ProgramSchedule) .Include(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items) .ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.ProgramScheduleItemGraphicsElements)
.ThenInclude(psi => psi.GraphicsElement)
.Include(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.Collection) .ThenInclude(psi => psi.Collection)
.Include(a => a.ProgramSchedule) .Include(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items) .ThenInclude(ps => ps.Items)

2
ErsatzTV.Core/Domain/GraphicsElement.cs

@ -7,4 +7,6 @@ public class GraphicsElement
public GraphicsElementKind Kind { get; set; } public GraphicsElementKind Kind { get; set; }
public List<PlayoutItem> PlayoutItems { get; set; } public List<PlayoutItem> PlayoutItems { get; set; }
public List<PlayoutItemGraphicsElement> PlayoutItemGraphicsElements { get; set; } public List<PlayoutItemGraphicsElement> PlayoutItemGraphicsElements { get; set; }
public List<ProgramScheduleItem> ProgramScheduleItems { get; set; }
public List<ProgramScheduleItemGraphicsElement> ProgramScheduleItemGraphicsElements { get; set; }
} }

2
ErsatzTV.Core/Domain/ProgramScheduleItem.cs

@ -43,6 +43,8 @@ public abstract class ProgramScheduleItem
public FillerPreset FallbackFiller { get; set; } public FillerPreset FallbackFiller { get; set; }
public List<ChannelWatermark> Watermarks { get; set; } public List<ChannelWatermark> Watermarks { get; set; }
public List<ProgramScheduleItemWatermark> ProgramScheduleItemWatermarks { get; set; } public List<ProgramScheduleItemWatermark> ProgramScheduleItemWatermarks { get; set; }
public List<GraphicsElement> GraphicsElements { get; set; }
public List<ProgramScheduleItemGraphicsElement> ProgramScheduleItemGraphicsElements { get; set; }
public string PreferredAudioLanguageCode { get; set; } public string PreferredAudioLanguageCode { get; set; }
public string PreferredAudioTitle { get; set; } public string PreferredAudioTitle { get; set; }
public string PreferredSubtitleLanguageCode { get; set; } public string PreferredSubtitleLanguageCode { get; set; }

9
ErsatzTV.Core/Domain/ProgramScheduleItemGraphicsElement.cs

@ -0,0 +1,9 @@
namespace ErsatzTV.Core.Domain;
public class ProgramScheduleItemGraphicsElement
{
public int ProgramScheduleItemId { get; set; }
public ProgramScheduleItem ProgramScheduleItem { get; set; }
public int GraphicsElementId { get; set; }
public GraphicsElement GraphicsElement { get; set; }
}

14
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs

@ -162,7 +162,8 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
PreferredAudioTitle = scheduleItem.PreferredAudioTitle, PreferredAudioTitle = scheduleItem.PreferredAudioTitle,
PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode,
SubtitleMode = scheduleItem.SubtitleMode, SubtitleMode = scheduleItem.SubtitleMode,
PlayoutItemWatermarks = [] PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
}; };
foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem
@ -176,6 +177,17 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
}); });
} }
foreach (ProgramScheduleItemGraphicsElement programScheduleItemGraphicsElement in scheduleItem
.ProgramScheduleItemGraphicsElements ?? [])
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = programScheduleItemGraphicsElement.GraphicsElementId
});
}
durationUntil.Do(du => playoutItem.GuideFinish = du.UtcDateTime); durationUntil.Do(du => playoutItem.GuideFinish = du.UtcDateTime);
DateTimeOffset durationFinish = nextState.DurationFinish.IfNone(SystemTime.MaxValueUtc); DateTimeOffset durationFinish = nextState.DurationFinish.IfNone(SystemTime.MaxValueUtc);

14
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs

@ -81,7 +81,8 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
PreferredAudioTitle = scheduleItem.PreferredAudioTitle, PreferredAudioTitle = scheduleItem.PreferredAudioTitle,
PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode,
SubtitleMode = scheduleItem.SubtitleMode, SubtitleMode = scheduleItem.SubtitleMode,
PlayoutItemWatermarks = [] PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
}; };
foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem
@ -95,6 +96,17 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
}); });
} }
foreach (ProgramScheduleItemGraphicsElement programScheduleItemGraphicsElement in scheduleItem
.ProgramScheduleItemGraphicsElements ?? [])
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = programScheduleItemGraphicsElement.GraphicsElementId
});
}
var enumeratorStates = new Dictionary<CollectionKey, CollectionEnumeratorState>(); var enumeratorStates = new Dictionary<CollectionKey, CollectionEnumeratorState>();
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators) foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{ {

14
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerMultiple.cs

@ -107,7 +107,8 @@ public class PlayoutModeSchedulerMultiple : PlayoutModeSchedulerBase<ProgramSche
PreferredAudioTitle = scheduleItem.PreferredAudioTitle, PreferredAudioTitle = scheduleItem.PreferredAudioTitle,
PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode,
SubtitleMode = scheduleItem.SubtitleMode, SubtitleMode = scheduleItem.SubtitleMode,
PlayoutItemWatermarks = [] PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
}; };
foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem
@ -121,6 +122,17 @@ public class PlayoutModeSchedulerMultiple : PlayoutModeSchedulerBase<ProgramSche
}); });
} }
foreach (ProgramScheduleItemGraphicsElement programScheduleItemGraphicsElement in scheduleItem
.ProgramScheduleItemGraphicsElements ?? [])
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = programScheduleItemGraphicsElement.GraphicsElementId
});
}
// LogScheduledItem(scheduleItem, mediaItem, itemStartTime); // LogScheduledItem(scheduleItem, mediaItem, itemStartTime);
playoutItems.AddRange( playoutItems.AddRange(

14
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerOne.cs

@ -55,7 +55,8 @@ public class PlayoutModeSchedulerOne : PlayoutModeSchedulerBase<ProgramScheduleI
PreferredAudioTitle = scheduleItem.PreferredAudioTitle, PreferredAudioTitle = scheduleItem.PreferredAudioTitle,
PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode,
SubtitleMode = scheduleItem.SubtitleMode, SubtitleMode = scheduleItem.SubtitleMode,
PlayoutItemWatermarks = [] PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
}; };
foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem foreach (ProgramScheduleItemWatermark programScheduleItemWatermark in scheduleItem
@ -69,6 +70,17 @@ public class PlayoutModeSchedulerOne : PlayoutModeSchedulerBase<ProgramScheduleI
}); });
} }
foreach (ProgramScheduleItemGraphicsElement programScheduleItemGraphicsElement in scheduleItem
.ProgramScheduleItemGraphicsElements ?? [])
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = programScheduleItemGraphicsElement.GraphicsElementId
});
}
List<PlayoutItem> playoutItems = AddFiller( List<PlayoutItem> playoutItems = AddFiller(
playoutBuilderState, playoutBuilderState,
collectionEnumerators, collectionEnumerators,

6366
ErsatzTV.Infrastructure.MySql/Migrations/20250905114217_Add_ProgramScheduleItemGraphicsElements.Designer.cs generated

File diff suppressed because it is too large Load Diff

51
ErsatzTV.Infrastructure.MySql/Migrations/20250905114217_Add_ProgramScheduleItemGraphicsElements.cs

@ -0,0 +1,51 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.MySql.Migrations
{
/// <inheritdoc />
public partial class Add_ProgramScheduleItemGraphicsElements : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ProgramScheduleItemGraphicsElement",
columns: table => new
{
ProgramScheduleItemId = table.Column<int>(type: "int", nullable: false),
GraphicsElementId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProgramScheduleItemGraphicsElement", x => new { x.ProgramScheduleItemId, x.GraphicsElementId });
table.ForeignKey(
name: "FK_ProgramScheduleItemGraphicsElement_GraphicsElement_GraphicsE~",
column: x => x.GraphicsElementId,
principalTable: "GraphicsElement",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProgramScheduleItemGraphicsElement_ProgramScheduleItem_Progr~",
column: x => x.ProgramScheduleItemId,
principalTable: "ProgramScheduleItem",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_ProgramScheduleItemGraphicsElement_GraphicsElementId",
table: "ProgramScheduleItemGraphicsElement",
column: "GraphicsElementId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ProgramScheduleItemGraphicsElement");
}
}
}

38
ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs

@ -2284,6 +2284,21 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.UseTptMappingStrategy(); b.UseTptMappingStrategy();
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemGraphicsElement", b =>
{
b.Property<int>("ProgramScheduleItemId")
.HasColumnType("int");
b.Property<int>("GraphicsElementId")
.HasColumnType("int");
b.HasKey("ProgramScheduleItemId", "GraphicsElementId");
b.HasIndex("GraphicsElementId");
b.ToTable("ProgramScheduleItemGraphicsElement");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b =>
{ {
b.Property<int>("ProgramScheduleItemId") b.Property<int>("ProgramScheduleItemId")
@ -4973,6 +4988,25 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Navigation("TailFiller"); b.Navigation("TailFiller");
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemGraphicsElement", b =>
{
b.HasOne("ErsatzTV.Core.Domain.GraphicsElement", "GraphicsElement")
.WithMany("ProgramScheduleItemGraphicsElements")
.HasForeignKey("GraphicsElementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem")
.WithMany("ProgramScheduleItemGraphicsElements")
.HasForeignKey("ProgramScheduleItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("GraphicsElement");
b.Navigation("ProgramScheduleItem");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b =>
{ {
b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem") b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem")
@ -5909,6 +5943,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
modelBuilder.Entity("ErsatzTV.Core.Domain.GraphicsElement", b => modelBuilder.Entity("ErsatzTV.Core.Domain.GraphicsElement", b =>
{ {
b.Navigation("PlayoutItemGraphicsElements"); b.Navigation("PlayoutItemGraphicsElements");
b.Navigation("ProgramScheduleItemGraphicsElements");
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b =>
@ -6083,6 +6119,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b =>
{ {
b.Navigation("ProgramScheduleItemGraphicsElements");
b.Navigation("ProgramScheduleItemWatermarks"); b.Navigation("ProgramScheduleItemWatermarks");
}); });

6201
ErsatzTV.Infrastructure.Sqlite/Migrations/20250905114029_Add_ProgramScheduleItemGraphicsElements.Designer.cs generated

File diff suppressed because it is too large Load Diff

50
ErsatzTV.Infrastructure.Sqlite/Migrations/20250905114029_Add_ProgramScheduleItemGraphicsElements.cs

@ -0,0 +1,50 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
{
/// <inheritdoc />
public partial class Add_ProgramScheduleItemGraphicsElements : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ProgramScheduleItemGraphicsElement",
columns: table => new
{
ProgramScheduleItemId = table.Column<int>(type: "INTEGER", nullable: false),
GraphicsElementId = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProgramScheduleItemGraphicsElement", x => new { x.ProgramScheduleItemId, x.GraphicsElementId });
table.ForeignKey(
name: "FK_ProgramScheduleItemGraphicsElement_GraphicsElement_GraphicsElementId",
column: x => x.GraphicsElementId,
principalTable: "GraphicsElement",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProgramScheduleItemGraphicsElement_ProgramScheduleItem_ProgramScheduleItemId",
column: x => x.ProgramScheduleItemId,
principalTable: "ProgramScheduleItem",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ProgramScheduleItemGraphicsElement_GraphicsElementId",
table: "ProgramScheduleItemGraphicsElement",
column: "GraphicsElementId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ProgramScheduleItemGraphicsElement");
}
}
}

38
ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs

@ -2177,6 +2177,21 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.UseTptMappingStrategy(); b.UseTptMappingStrategy();
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemGraphicsElement", b =>
{
b.Property<int>("ProgramScheduleItemId")
.HasColumnType("INTEGER");
b.Property<int>("GraphicsElementId")
.HasColumnType("INTEGER");
b.HasKey("ProgramScheduleItemId", "GraphicsElementId");
b.HasIndex("GraphicsElementId");
b.ToTable("ProgramScheduleItemGraphicsElement");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b =>
{ {
b.Property<int>("ProgramScheduleItemId") b.Property<int>("ProgramScheduleItemId")
@ -4808,6 +4823,25 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Navigation("TailFiller"); b.Navigation("TailFiller");
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemGraphicsElement", b =>
{
b.HasOne("ErsatzTV.Core.Domain.GraphicsElement", "GraphicsElement")
.WithMany("ProgramScheduleItemGraphicsElements")
.HasForeignKey("GraphicsElementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem")
.WithMany("ProgramScheduleItemGraphicsElements")
.HasForeignKey("ProgramScheduleItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("GraphicsElement");
b.Navigation("ProgramScheduleItem");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItemWatermark", b =>
{ {
b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem") b.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "ProgramScheduleItem")
@ -5744,6 +5778,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
modelBuilder.Entity("ErsatzTV.Core.Domain.GraphicsElement", b => modelBuilder.Entity("ErsatzTV.Core.Domain.GraphicsElement", b =>
{ {
b.Navigation("PlayoutItemGraphicsElements"); b.Navigation("PlayoutItemGraphicsElements");
b.Navigation("ProgramScheduleItemGraphicsElements");
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ImageMetadata", b =>
@ -5918,6 +5954,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b => modelBuilder.Entity("ErsatzTV.Core.Domain.ProgramScheduleItem", b =>
{ {
b.Navigation("ProgramScheduleItemGraphicsElements");
b.Navigation("ProgramScheduleItemWatermarks"); b.Navigation("ProgramScheduleItemWatermarks");
}); });

13
ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleItemConfiguration.cs

@ -82,5 +82,18 @@ public class ProgramScheduleItemConfiguration : IEntityTypeConfiguration<Program
.HasForeignKey(ci => ci.ProgramScheduleItemId) .HasForeignKey(ci => ci.ProgramScheduleItemId)
.OnDelete(DeleteBehavior.Cascade), .OnDelete(DeleteBehavior.Cascade),
j => j.HasKey(ci => new { ci.ProgramScheduleItemId, ci.WatermarkId })); j => j.HasKey(ci => new { ci.ProgramScheduleItemId, ci.WatermarkId }));
builder.HasMany(c => c.GraphicsElements)
.WithMany(m => m.ProgramScheduleItems)
.UsingEntity<ProgramScheduleItemGraphicsElement>(
j => j.HasOne(ci => ci.GraphicsElement)
.WithMany(mi => mi.ProgramScheduleItemGraphicsElements)
.HasForeignKey(ci => ci.GraphicsElementId)
.OnDelete(DeleteBehavior.Cascade),
j => j.HasOne(ci => ci.ProgramScheduleItem)
.WithMany(c => c.ProgramScheduleItemGraphicsElements)
.HasForeignKey(ci => ci.ProgramScheduleItemId)
.OnDelete(DeleteBehavior.Cascade),
j => j.HasKey(ci => new { ci.ProgramScheduleItemId, ci.GraphicsElementId }));
} }
} }

24
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -1,5 +1,6 @@
@page "/schedules/{Id:int}/items" @page "/schedules/{Id:int}/items"
@using ErsatzTV.Application.Filler @using ErsatzTV.Application.Filler
@using ErsatzTV.Application.Graphics
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaItems @using ErsatzTV.Application.MediaItems
@using ErsatzTV.Application.ProgramSchedules @using ErsatzTV.Application.ProgramSchedules
@ -574,6 +575,21 @@
} }
</MudSelect> </MudSelect>
</MudStack> </MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Graphics Elements</MudText>
</div>
<MudSelect T="GraphicsElementViewModel"
@bind-SelectedValues="_selectedItem.GraphicsElements"
ToStringFunc="@(ge => ge?.Name)"
Clearable="true"
MultiSelection="true">
@foreach (GraphicsElementViewModel graphicsElement in _graphicsElements)
{
<MudSelectItem Value="@graphicsElement">@graphicsElement.Name</MudSelectItem>
}
</MudSelect>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5"> <MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex"> <div class="d-flex">
<MudText>Preferred Audio Language</MudText> <MudText>Preferred Audio Language</MudText>
@ -633,6 +649,7 @@
private ProgramScheduleItemsEditViewModel _schedule = new(); private ProgramScheduleItemsEditViewModel _schedule = new();
private List<FillerPresetViewModel> _fillerPresets = []; private List<FillerPresetViewModel> _fillerPresets = [];
private List<WatermarkViewModel> _watermarks = []; private List<WatermarkViewModel> _watermarks = [];
private List<GraphicsElementViewModel> _graphicsElements = [];
private List<LanguageCodeViewModel> _availableCultures = []; private List<LanguageCodeViewModel> _availableCultures = [];
private readonly List<PlaylistGroupViewModel> _playlistGroups = []; private readonly List<PlaylistGroupViewModel> _playlistGroups = [];
private readonly List<PlaylistViewModel> _playlists = []; private readonly List<PlaylistViewModel> _playlists = [];
@ -663,6 +680,8 @@
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_watermarks = await Mediator.Send(new GetAllWatermarks(), token) _watermarks = await Mediator.Send(new GetAllWatermarks(), token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_graphicsElements = await Mediator.Send(new GetAllGraphicsElements(), token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_availableCultures = await Mediator.Send(new GetAllLanguageCodes(), token); _availableCultures = await Mediator.Send(new GetAllLanguageCodes(), token);
_playlistGroups.AddRange(await Mediator.Send(new GetAllPlaylistGroups(), token)); _playlistGroups.AddRange(await Mediator.Send(new GetAllPlaylistGroups(), token));
@ -795,7 +814,8 @@
PreferredAudioTitle = item.PreferredAudioTitle, PreferredAudioTitle = item.PreferredAudioTitle,
PreferredSubtitleLanguageCode = item.PreferredSubtitleLanguageCode, PreferredSubtitleLanguageCode = item.PreferredSubtitleLanguageCode,
SubtitleMode = item.SubtitleMode, SubtitleMode = item.SubtitleMode,
Watermarks = item.Watermarks Watermarks = item.Watermarks,
GraphicsElements = item.GraphicsElements
}; };
switch (item) switch (item)
@ -861,6 +881,7 @@
TailFiller = item.TailFiller, TailFiller = item.TailFiller,
FallbackFiller = item.FallbackFiller, FallbackFiller = item.FallbackFiller,
Watermarks = item.Watermarks.ToList(), Watermarks = item.Watermarks.ToList(),
GraphicsElements = item.GraphicsElements.ToList(),
PreferredAudioLanguageCode = item.PreferredAudioLanguageCode, PreferredAudioLanguageCode = item.PreferredAudioLanguageCode,
PreferredAudioTitle = item.PreferredAudioTitle, PreferredAudioTitle = item.PreferredAudioTitle,
PreferredSubtitleLanguageCode = item.PreferredSubtitleLanguageCode, PreferredSubtitleLanguageCode = item.PreferredSubtitleLanguageCode,
@ -935,6 +956,7 @@
item.TailFiller?.Id, item.TailFiller?.Id,
item.FallbackFiller?.Id, item.FallbackFiller?.Id,
item.Watermarks.Map(wm => wm.Id).ToList(), item.Watermarks.Map(wm => wm.Id).ToList(),
item.GraphicsElements.Map(wm => wm.Id).ToList(),
item.PreferredAudioLanguageCode, item.PreferredAudioLanguageCode,
item.PreferredAudioTitle, item.PreferredAudioTitle,
item.PreferredSubtitleLanguageCode, item.PreferredSubtitleLanguageCode,

2
ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

@ -2,6 +2,7 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ErsatzTV.Annotations; using ErsatzTV.Annotations;
using ErsatzTV.Application.Filler; using ErsatzTV.Application.Filler;
using ErsatzTV.Application.Graphics;
using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaItems; using ErsatzTV.Application.MediaItems;
using ErsatzTV.Application.Watermarks; using ErsatzTV.Application.Watermarks;
@ -93,6 +94,7 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
public FillerPresetViewModel TailFiller { get; set; } public FillerPresetViewModel TailFiller { get; set; }
public FillerPresetViewModel FallbackFiller { get; set; } public FillerPresetViewModel FallbackFiller { get; set; }
public IEnumerable<WatermarkViewModel> Watermarks { get; set; } public IEnumerable<WatermarkViewModel> Watermarks { get; set; }
public IEnumerable<GraphicsElementViewModel> GraphicsElements { get; set; }
public string PreferredAudioLanguageCode { get; set; } public string PreferredAudioLanguageCode { get; set; }
public string PreferredAudioTitle { get; set; } public string PreferredAudioTitle { get; set; }
public string PreferredSubtitleLanguageCode { get; set; } public string PreferredSubtitleLanguageCode { get; set; }

Loading…
Cancel
Save