add dead air fallback to deco system (#1668)
* add dead air fallback to deco editor * fix deco watermark logic * use dead air fallback from decos
This commit is contained in:
+5
-3
@@ -9,14 +9,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- This is year-agnostic, meaning the Month/Day range will apply to every year
|
- This is year-agnostic, meaning the Month/Day range will apply to every year
|
||||||
- This also supports wrapping the end of the year (e.g., start 12/1 and end 1/15)
|
- This also supports wrapping the end of the year (e.g., start 12/1 and end 1/15)
|
||||||
- Add new `Deco` system for "decorating" channels with non-primary content
|
- Add new `Deco` system for "decorating" channels with non-primary content
|
||||||
- Decos currently only contain Watermarks, but future work will add other functionality, including filler
|
- Decos currently contain
|
||||||
|
- Watermarks
|
||||||
|
- Dead Air Fallback (i.e. fallback filler)
|
||||||
- Similar to blocks, decos have deco groups for organization
|
- Similar to blocks, decos have deco groups for organization
|
||||||
- Similar to blocks, decos have deco templates for filling a "day" with decos
|
- Similar to blocks, decos have deco templates for filling a "day" with decos
|
||||||
- In the playout template editor, playout template items can have *both* a block template and a deco template
|
- In the playout template editor, playout template items can have *both* a block template and a deco template
|
||||||
- This allows watermarks to change at different times than primary content
|
- This allows watermarks and dead air fallback to change at different times than primary content
|
||||||
- Block playouts can also have a default deco
|
- Block playouts can also have a default deco
|
||||||
- This will apply whenever a deco template is missing, or when a deco template item cannot be found for the current time
|
- This will apply whenever a deco template is missing, or when a deco template item cannot be found for the current time
|
||||||
- Effectively, this sets a default watermark for the entire playout
|
- Effectively, this sets a default watermark and dead air fallback for the entire playout
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix some cases of 404s from Plex when files were replaced and scanning the library from ETV didn't help
|
- Fix some cases of 404s from Plex when files were replaced and scanning the library from ETV didn't help
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
using ErsatzTV.Core;
|
using ErsatzTV.Core;
|
||||||
|
using ErsatzTV.Core.Domain;
|
||||||
|
using ErsatzTV.Core.Domain.Scheduling;
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Scheduling;
|
namespace ErsatzTV.Application.Scheduling;
|
||||||
|
|
||||||
public record UpdateDeco(int DecoId, int DecoGroupId, string Name, int? WatermarkId) : IRequest<Either<BaseError, DecoViewModel>>;
|
public record UpdateDeco(
|
||||||
|
int DecoId,
|
||||||
|
int DecoGroupId,
|
||||||
|
string Name,
|
||||||
|
DecoMode WatermarkMode,
|
||||||
|
int? WatermarkId,
|
||||||
|
DecoMode DeadAirFallbackMode,
|
||||||
|
ProgramScheduleItemCollectionType DeadAirFallbackCollectionType,
|
||||||
|
int? DeadAirFallbackCollectionId,
|
||||||
|
int? DeadAirFallbackMediaItemId,
|
||||||
|
int? DeadAirFallbackMultiCollectionId,
|
||||||
|
int? DeadAirFallbackSmartCollectionId)
|
||||||
|
: IRequest<Either<BaseError, DecoViewModel>>;
|
||||||
|
|||||||
@@ -22,7 +22,26 @@ public class UpdateDecoHandler(IDbContextFactory<TvContext> dbContextFactory)
|
|||||||
UpdateDeco request)
|
UpdateDeco request)
|
||||||
{
|
{
|
||||||
existing.Name = request.Name;
|
existing.Name = request.Name;
|
||||||
existing.WatermarkId = request.WatermarkId;
|
|
||||||
|
// watermark
|
||||||
|
existing.WatermarkMode = request.WatermarkMode;
|
||||||
|
existing.WatermarkId = request.WatermarkMode is DecoMode.Override ? request.WatermarkId : null;
|
||||||
|
|
||||||
|
// dead air fallback
|
||||||
|
existing.DeadAirFallbackMode = request.DeadAirFallbackMode;
|
||||||
|
existing.DeadAirFallbackCollectionType = request.DeadAirFallbackCollectionType;
|
||||||
|
existing.DeadAirFallbackCollectionId = request.DeadAirFallbackMode is DecoMode.Override
|
||||||
|
? request.DeadAirFallbackCollectionId
|
||||||
|
: null;
|
||||||
|
existing.DeadAirFallbackMediaItemId = request.DeadAirFallbackMode is DecoMode.Override
|
||||||
|
? request.DeadAirFallbackMediaItemId
|
||||||
|
: null;
|
||||||
|
existing.DeadAirFallbackMultiCollectionId = request.DeadAirFallbackMode is DecoMode.Override
|
||||||
|
? request.DeadAirFallbackMultiCollectionId
|
||||||
|
: null;
|
||||||
|
existing.DeadAirFallbackSmartCollectionId = request.DeadAirFallbackMode is DecoMode.Override
|
||||||
|
? request.DeadAirFallbackSmartCollectionId
|
||||||
|
: null;
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync();
|
await dbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
using ErsatzTV.Core.Domain;
|
||||||
|
using ErsatzTV.Core.Domain.Scheduling;
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Scheduling;
|
namespace ErsatzTV.Application.Scheduling;
|
||||||
|
|
||||||
public record DecoViewModel(int Id, int DecoGroupId, string Name, int? WatermarkId);
|
public record DecoViewModel(
|
||||||
|
int Id,
|
||||||
|
int DecoGroupId,
|
||||||
|
string Name,
|
||||||
|
DecoMode WatermarkMode,
|
||||||
|
int? WatermarkId,
|
||||||
|
DecoMode DeadAirFallbackMode,
|
||||||
|
ProgramScheduleItemCollectionType DeadAirFallbackCollectionType,
|
||||||
|
int? DeadAirFallbackCollectionId,
|
||||||
|
int? DeadAirFallbackMediaItemId,
|
||||||
|
int? DeadAirFallbackMultiCollectionId,
|
||||||
|
int? DeadAirFallbackSmartCollectionId);
|
||||||
|
|||||||
@@ -50,7 +50,18 @@ internal static class Mapper
|
|||||||
new(decoGroup.Id, decoGroup.Name, decoGroup.Decos.Count);
|
new(decoGroup.Id, decoGroup.Name, decoGroup.Decos.Count);
|
||||||
|
|
||||||
internal static DecoViewModel ProjectToViewModel(Deco deco) =>
|
internal static DecoViewModel ProjectToViewModel(Deco deco) =>
|
||||||
new(deco.Id, deco.DecoGroupId, deco.Name, deco.WatermarkId);
|
new(
|
||||||
|
deco.Id,
|
||||||
|
deco.DecoGroupId,
|
||||||
|
deco.Name,
|
||||||
|
deco.WatermarkMode,
|
||||||
|
deco.WatermarkId,
|
||||||
|
deco.DeadAirFallbackMode,
|
||||||
|
deco.DeadAirFallbackCollectionType,
|
||||||
|
deco.DeadAirFallbackCollectionId,
|
||||||
|
deco.DeadAirFallbackMediaItemId,
|
||||||
|
deco.DeadAirFallbackMultiCollectionId,
|
||||||
|
deco.DeadAirFallbackSmartCollectionId);
|
||||||
|
|
||||||
internal static DecoTemplateGroupViewModel ProjectToViewModel(DecoTemplateGroup decoTemplateGroup) =>
|
internal static DecoTemplateGroupViewModel ProjectToViewModel(DecoTemplateGroup decoTemplateGroup) =>
|
||||||
new(decoTemplateGroup.Id, decoTemplateGroup.Name, decoTemplateGroup.DecoTemplates.Count);
|
new(decoTemplateGroup.Id, decoTemplateGroup.Name, decoTemplateGroup.DecoTemplates.Count);
|
||||||
|
|||||||
+210
-58
@@ -79,9 +79,19 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
DateTimeOffset now = request.Now;
|
DateTimeOffset now = request.Now;
|
||||||
|
|
||||||
Either<BaseError, PlayoutItemWithPath> maybePlayoutItem = await dbContext.PlayoutItems
|
Either<BaseError, PlayoutItemWithPath> maybePlayoutItem = await dbContext.PlayoutItems
|
||||||
|
// get playout deco
|
||||||
.Include(i => i.Playout)
|
.Include(i => i.Playout)
|
||||||
.ThenInclude(p => p.Deco)
|
.ThenInclude(p => p.Deco)
|
||||||
.ThenInclude(d => d.Watermark)
|
.ThenInclude(d => d.Watermark)
|
||||||
|
|
||||||
|
// get playout templates (and deco templates/decos)
|
||||||
|
.Include(i => i.Playout)
|
||||||
|
.ThenInclude(p => p.Templates)
|
||||||
|
.ThenInclude(t => t.DecoTemplate)
|
||||||
|
.ThenInclude(t => t.Items)
|
||||||
|
.ThenInclude(i => i.Deco)
|
||||||
|
.ThenInclude(d => d.Watermark)
|
||||||
|
|
||||||
.Include(i => i.MediaItem)
|
.Include(i => i.MediaItem)
|
||||||
.ThenInclude(mi => (mi as Episode).EpisodeMetadata)
|
.ThenInclude(mi => (mi as Episode).EpisodeMetadata)
|
||||||
.ThenInclude(em => em.Subtitles)
|
.ThenInclude(em => em.Subtitles)
|
||||||
@@ -163,7 +173,31 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
|
|
||||||
if (maybePlayoutItem.LeftAsEnumerable().Any(e => e is UnableToLocatePlayoutItem))
|
if (maybePlayoutItem.LeftAsEnumerable().Any(e => e is UnableToLocatePlayoutItem))
|
||||||
{
|
{
|
||||||
maybePlayoutItem = await CheckForFallbackFiller(dbContext, channel, now);
|
Option<Playout> maybePlayout = await dbContext.Playouts
|
||||||
|
.AsNoTracking()
|
||||||
|
|
||||||
|
// get playout deco
|
||||||
|
.Include(p => p.Deco)
|
||||||
|
.ThenInclude(d => d.Watermark)
|
||||||
|
|
||||||
|
// get playout templates (and deco templates/decos)
|
||||||
|
.Include(p => p.Templates)
|
||||||
|
.ThenInclude(t => t.DecoTemplate)
|
||||||
|
.ThenInclude(t => t.Items)
|
||||||
|
.ThenInclude(i => i.Deco)
|
||||||
|
.ThenInclude(d => d.Watermark)
|
||||||
|
|
||||||
|
.SelectOneAsync(p => p.ChannelId, p => p.ChannelId == channel.Id);
|
||||||
|
|
||||||
|
foreach (var playout in maybePlayout)
|
||||||
|
{
|
||||||
|
maybePlayoutItem = await CheckForFallbackFiller(dbContext, channel, playout, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybePlayout.IsNone)
|
||||||
|
{
|
||||||
|
maybePlayoutItem = await CheckForFallbackFiller(dbContext, channel, null, now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PlayoutItemWithPath playoutItemWithPath in maybePlayoutItem.RightToSeq())
|
foreach (PlayoutItemWithPath playoutItemWithPath in maybePlayoutItem.RightToSeq())
|
||||||
@@ -198,62 +232,20 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
watermarkId => dbContext.ChannelWatermarks
|
watermarkId => dbContext.ChannelWatermarks
|
||||||
.SelectOneAsync(w => w.Id, w => w.Id == watermarkId));
|
.SelectOneAsync(w => w.Id, w => w.Id == watermarkId));
|
||||||
|
|
||||||
Option<ChannelWatermark> playoutItemWatermark = Optional(playoutItemWithPath.PlayoutItem.Watermark);
|
Option<ChannelWatermark> playoutItemWatermark = Option<ChannelWatermark>.None;
|
||||||
if (playoutItemWatermark.IsNone &&
|
bool disableWatermarks = playoutItemWithPath.PlayoutItem.DisableWatermarks;
|
||||||
playoutItemWithPath.PlayoutItem.Playout.ProgramSchedulePlayoutType is ProgramSchedulePlayoutType.Block)
|
WatermarkResult watermarkResult = GetPlayoutItemWatermark(playoutItemWithPath.PlayoutItem.Playout, now);
|
||||||
|
switch (watermarkResult)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Block playout item has no watermark; checking for deco");
|
case InheritWatermark:
|
||||||
|
// do nothing, other code will fall back to channel/global
|
||||||
// check for playout template deco
|
break;
|
||||||
// load all playout templates
|
case DisableWatermark:
|
||||||
// get playout template for start time
|
disableWatermarks = true;
|
||||||
// check for deco
|
break;
|
||||||
// load all templates that have decos
|
case CustomWatermark watermark:
|
||||||
List<PlayoutTemplate> playoutTemplates = await dbContext.PlayoutTemplates
|
playoutItemWatermark = watermark.Watermark;
|
||||||
.AsNoTracking()
|
break;
|
||||||
.Filter(t => t.PlayoutId == playoutItemWithPath.PlayoutItem.PlayoutId)
|
|
||||||
.Filter(t => t.DecoTemplateId != null)
|
|
||||||
.Include(t => t.DecoTemplate)
|
|
||||||
.ThenInclude(t => t.Items)
|
|
||||||
.ThenInclude(i => i.Deco)
|
|
||||||
.ThenInclude(d => d.Watermark)
|
|
||||||
.ToListAsync(cancellationToken);
|
|
||||||
|
|
||||||
Option<PlayoutTemplate> maybeActiveTemplate = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
|
||||||
playoutTemplates,
|
|
||||||
playoutItemWithPath.PlayoutItem.StartOffset);
|
|
||||||
|
|
||||||
foreach (PlayoutTemplate activeTemplate in maybeActiveTemplate)
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Block playout has active playout template; checking for deco template items");
|
|
||||||
Option<DecoTemplateItem> maybeItem = activeTemplate.DecoTemplate.Items
|
|
||||||
.Find(i => i.StartTime <= now.TimeOfDay && i.EndTime > now.TimeOfDay);
|
|
||||||
foreach (DecoTemplateItem item in maybeItem)
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Block playout has active deco template item; checking for watermark");
|
|
||||||
foreach (ChannelWatermark watermark in Optional(item.Deco.Watermark))
|
|
||||||
{
|
|
||||||
_logger.LogDebug(
|
|
||||||
"Block playout has active deco template item with watermark; will use for this playout item");
|
|
||||||
playoutItemWatermark = watermark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playoutItemWatermark.IsNone)
|
|
||||||
{
|
|
||||||
// check for playout deco
|
|
||||||
foreach (Deco deco in Optional(playoutItemWithPath.PlayoutItem.Playout.Deco))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Block playout item has default deco; checking for watermark");
|
|
||||||
foreach (ChannelWatermark watermark in Optional(deco.Watermark))
|
|
||||||
{
|
|
||||||
_logger.LogDebug(
|
|
||||||
"Block playout has default deco with watermark; will use for this playout item");
|
|
||||||
playoutItemWatermark = watermark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playoutItemWithPath.PlayoutItem.MediaItem is Song song)
|
if (playoutItemWithPath.PlayoutItem.MediaItem is Song song)
|
||||||
@@ -312,7 +304,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
outPoint,
|
outPoint,
|
||||||
request.PtsOffset,
|
request.PtsOffset,
|
||||||
request.TargetFramerate,
|
request.TargetFramerate,
|
||||||
playoutItemWithPath.PlayoutItem.DisableWatermarks,
|
disableWatermarks,
|
||||||
_ => { });
|
_ => { });
|
||||||
|
|
||||||
var result = new PlayoutItemProcessModel(process, duration, finish, true);
|
var result = new PlayoutItemProcessModel(process, duration, finish, true);
|
||||||
@@ -463,10 +455,31 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
private async Task<Either<BaseError, PlayoutItemWithPath>> CheckForFallbackFiller(
|
private async Task<Either<BaseError, PlayoutItemWithPath>> CheckForFallbackFiller(
|
||||||
TvContext dbContext,
|
TvContext dbContext,
|
||||||
Channel channel,
|
Channel channel,
|
||||||
|
Playout playout,
|
||||||
DateTimeOffset now)
|
DateTimeOffset now)
|
||||||
{
|
{
|
||||||
|
Option<FillerPreset> maybeFallback = Option<FillerPreset>.None;
|
||||||
|
|
||||||
|
DeadAirFallbackResult decoDeadAirFallback = GetDecoDeadAirFallback(playout, now);
|
||||||
|
switch (decoDeadAirFallback)
|
||||||
|
{
|
||||||
|
case CustomDeadAirFallback custom:
|
||||||
|
maybeFallback = new FillerPreset
|
||||||
|
{
|
||||||
|
AllowWatermarks = true,
|
||||||
|
CollectionType = custom.CollectionType,
|
||||||
|
CollectionId = custom.CollectionId,
|
||||||
|
MediaItemId = custom.MediaItemId,
|
||||||
|
MultiCollectionId = custom.MultiCollectionId,
|
||||||
|
SmartCollectionId = custom.SmartCollectionId
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case DisableDeadAirFallback:
|
||||||
|
// do nothing
|
||||||
|
break;
|
||||||
|
case InheritDeadAirFallback:
|
||||||
// check for channel fallback
|
// check for channel fallback
|
||||||
Option<FillerPreset> maybeFallback = await dbContext.FillerPresets
|
maybeFallback = await dbContext.FillerPresets
|
||||||
.SelectOneAsync(w => w.Id, w => w.Id == channel.FallbackFillerId);
|
.SelectOneAsync(w => w.Id, w => w.Id == channel.FallbackFillerId);
|
||||||
|
|
||||||
// then check for global fallback
|
// then check for global fallback
|
||||||
@@ -476,6 +489,9 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
.GetValue<int>(ConfigElementKey.FFmpegGlobalFallbackFillerId)
|
.GetValue<int>(ConfigElementKey.FFmpegGlobalFallbackFillerId)
|
||||||
.BindT(fillerId => dbContext.FillerPresets.SelectOneAsync(w => w.Id, w => w.Id == fillerId));
|
.BindT(fillerId => dbContext.FillerPresets.SelectOneAsync(w => w.Id, w => w.Id == fillerId));
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (FillerPreset fallbackPreset in maybeFallback)
|
foreach (FillerPreset fallbackPreset in maybeFallback)
|
||||||
{
|
{
|
||||||
@@ -641,4 +657,140 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
_ => path
|
_ => path
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WatermarkResult GetPlayoutItemWatermark(Playout playout, DateTimeOffset now)
|
||||||
|
{
|
||||||
|
DecoEntries decoEntries = GetDecoEntries(playout, now);
|
||||||
|
|
||||||
|
// first, check deco template / active deco
|
||||||
|
foreach (Deco templateDeco in decoEntries.TemplateDeco)
|
||||||
|
{
|
||||||
|
switch (templateDeco.WatermarkMode)
|
||||||
|
{
|
||||||
|
case DecoMode.Override:
|
||||||
|
_logger.LogDebug("Watermark will come from template deco (override)");
|
||||||
|
return new CustomWatermark(templateDeco.Watermark);
|
||||||
|
case DecoMode.Disable:
|
||||||
|
_logger.LogDebug("Watermark is disabled by template deco");
|
||||||
|
return new DisableWatermark();
|
||||||
|
case DecoMode.Inherit:
|
||||||
|
_logger.LogDebug("Watermark will inherit from playout deco");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// second, check playout deco
|
||||||
|
foreach (Deco playoutDeco in decoEntries.PlayoutDeco)
|
||||||
|
{
|
||||||
|
switch (playoutDeco.WatermarkMode)
|
||||||
|
{
|
||||||
|
case DecoMode.Override:
|
||||||
|
_logger.LogDebug("Watermark will come from playout deco (override)");
|
||||||
|
return new CustomWatermark(playoutDeco.Watermark);
|
||||||
|
case DecoMode.Disable:
|
||||||
|
_logger.LogDebug("Watermark is disabled by playout deco");
|
||||||
|
return new DisableWatermark();
|
||||||
|
case DecoMode.Inherit:
|
||||||
|
_logger.LogDebug("Watermark will inherit from channel and/or global setting");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InheritWatermark();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeadAirFallbackResult GetDecoDeadAirFallback(Playout playout, DateTimeOffset now)
|
||||||
|
{
|
||||||
|
DecoEntries decoEntries = GetDecoEntries(playout, now);
|
||||||
|
|
||||||
|
// first, check deco template / active deco
|
||||||
|
foreach (Deco templateDeco in decoEntries.TemplateDeco)
|
||||||
|
{
|
||||||
|
switch (templateDeco.DeadAirFallbackMode)
|
||||||
|
{
|
||||||
|
case DecoMode.Override:
|
||||||
|
_logger.LogDebug("Dead air fallback will come from template deco (override)");
|
||||||
|
return new CustomDeadAirFallback(
|
||||||
|
templateDeco.DeadAirFallbackCollectionType,
|
||||||
|
templateDeco.DeadAirFallbackCollectionId,
|
||||||
|
templateDeco.DeadAirFallbackMediaItemId,
|
||||||
|
templateDeco.DeadAirFallbackMultiCollectionId,
|
||||||
|
templateDeco.DeadAirFallbackSmartCollectionId);
|
||||||
|
case DecoMode.Disable:
|
||||||
|
_logger.LogDebug("Dead air fallback is disabled by template deco");
|
||||||
|
return new DisableDeadAirFallback();
|
||||||
|
case DecoMode.Inherit:
|
||||||
|
_logger.LogDebug("Dead air fallback will inherit from playout deco");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// second, check playout deco
|
||||||
|
foreach (Deco playoutDeco in decoEntries.PlayoutDeco)
|
||||||
|
{
|
||||||
|
switch (playoutDeco.DeadAirFallbackMode)
|
||||||
|
{
|
||||||
|
case DecoMode.Override:
|
||||||
|
_logger.LogDebug("Dead air fallback will come from playout deco (override)");
|
||||||
|
return new CustomDeadAirFallback(
|
||||||
|
playoutDeco.DeadAirFallbackCollectionType,
|
||||||
|
playoutDeco.DeadAirFallbackCollectionId,
|
||||||
|
playoutDeco.DeadAirFallbackMediaItemId,
|
||||||
|
playoutDeco.DeadAirFallbackMultiCollectionId,
|
||||||
|
playoutDeco.DeadAirFallbackSmartCollectionId);
|
||||||
|
case DecoMode.Disable:
|
||||||
|
_logger.LogDebug("Dead air fallback is disabled by playout deco");
|
||||||
|
return new DisableDeadAirFallback();
|
||||||
|
case DecoMode.Inherit:
|
||||||
|
_logger.LogDebug("Dead air fallback will inherit from channel and/or global setting");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InheritDeadAirFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DecoEntries GetDecoEntries(Playout playout, DateTimeOffset now)
|
||||||
|
{
|
||||||
|
if (playout is null)
|
||||||
|
{
|
||||||
|
return new DecoEntries(Option<Deco>.None, Option<Deco>.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Option<Deco> maybePlayoutDeco = Optional(playout.Deco);
|
||||||
|
Option<Deco> maybeTemplateDeco = Option<Deco>.None;
|
||||||
|
|
||||||
|
Option<PlayoutTemplate> maybeActiveTemplate =
|
||||||
|
PlayoutTemplateSelector.GetPlayoutTemplateFor(playout.Templates, now);
|
||||||
|
|
||||||
|
foreach (PlayoutTemplate activeTemplate in maybeActiveTemplate)
|
||||||
|
{
|
||||||
|
Option<DecoTemplateItem> maybeItem = activeTemplate.DecoTemplate.Items
|
||||||
|
.Find(i => i.StartTime <= now.TimeOfDay && i.EndTime > now.TimeOfDay);
|
||||||
|
foreach (DecoTemplateItem item in maybeItem)
|
||||||
|
{
|
||||||
|
maybeTemplateDeco = Optional(item.Deco);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DecoEntries(maybeTemplateDeco, maybePlayoutDeco);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record DecoEntries(Option<Deco> TemplateDeco, Option<Deco> PlayoutDeco);
|
||||||
|
|
||||||
|
private abstract record WatermarkResult;
|
||||||
|
private sealed record InheritWatermark : WatermarkResult;
|
||||||
|
private sealed record DisableWatermark : WatermarkResult;
|
||||||
|
private sealed record CustomWatermark(ChannelWatermark Watermark) : WatermarkResult;
|
||||||
|
|
||||||
|
private abstract record DeadAirFallbackResult;
|
||||||
|
private sealed record InheritDeadAirFallback : DeadAirFallbackResult;
|
||||||
|
private sealed record DisableDeadAirFallback : DeadAirFallbackResult;
|
||||||
|
|
||||||
|
private sealed record CustomDeadAirFallback(
|
||||||
|
ProgramScheduleItemCollectionType CollectionType,
|
||||||
|
int? CollectionId,
|
||||||
|
int? MediaItemId,
|
||||||
|
int? MultiCollectionId,
|
||||||
|
int? SmartCollectionId) : DeadAirFallbackResult;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,23 @@ public class Deco
|
|||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
// watermark
|
||||||
|
public DecoMode WatermarkMode { get; set; }
|
||||||
public int? WatermarkId { get; set; }
|
public int? WatermarkId { get; set; }
|
||||||
public ChannelWatermark Watermark { get; set; }
|
public ChannelWatermark Watermark { get; set; }
|
||||||
|
|
||||||
// can be added directly to playouts
|
// dead air fallback
|
||||||
|
public DecoMode DeadAirFallbackMode { get; set; }
|
||||||
|
public ProgramScheduleItemCollectionType DeadAirFallbackCollectionType { get; set; }
|
||||||
|
public int? DeadAirFallbackCollectionId { get; set; }
|
||||||
|
public Collection DeadAirFallbackCollection { get; set; }
|
||||||
|
public int? DeadAirFallbackMediaItemId { get; set; }
|
||||||
|
public MediaItem DeadAirFallbackMediaItem { get; set; }
|
||||||
|
public int? DeadAirFallbackMultiCollectionId { get; set; }
|
||||||
|
public MultiCollection DeadAirFallbackMultiCollection { get; set; }
|
||||||
|
public int? DeadAirFallbackSmartCollectionId { get; set; }
|
||||||
|
public SmartCollection DeadAirFallbackSmartCollection { get; set; }
|
||||||
|
|
||||||
|
// can be added directly to (block) playouts
|
||||||
public ICollection<Playout> Playouts { get; set; }
|
public ICollection<Playout> Playouts { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ErsatzTV.Core.Domain.Scheduling;
|
||||||
|
|
||||||
|
public enum DecoMode
|
||||||
|
{
|
||||||
|
Inherit = 0,
|
||||||
|
Disable = 1,
|
||||||
|
Override = 2
|
||||||
|
}
|
||||||
+5590
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,175 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.MySql.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_DecoMode : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackCollectionType",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackMode",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "WatermarkMode",
|
||||||
|
table: "Deco",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackCollectionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMediaItemId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMultiCollectionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackSmartCollectionId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_Collection_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackCollectionId",
|
||||||
|
principalTable: "Collection",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_MediaItem_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMediaItemId",
|
||||||
|
principalTable: "MediaItem",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_MultiCollection_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMultiCollectionId",
|
||||||
|
principalTable: "MultiCollection",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_SmartCollection_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackSmartCollectionId",
|
||||||
|
principalTable: "SmartCollection",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_Collection_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_MediaItem_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_MultiCollection_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_SmartCollection_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackCollectionType",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackMode",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "WatermarkMode",
|
||||||
|
table: "Deco");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2145,6 +2145,24 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
|||||||
|
|
||||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackCollectionId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("DeadAirFallbackCollectionType")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackMediaItemId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("DeadAirFallbackMode")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackMultiCollectionId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackSmartCollectionId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int>("DecoGroupId")
|
b.Property<int>("DecoGroupId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
@@ -2154,8 +2172,19 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
|||||||
b.Property<int?>("WatermarkId")
|
b.Property<int?>("WatermarkId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("WatermarkMode")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackCollectionId");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackMediaItemId");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackMultiCollectionId");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackSmartCollectionId");
|
||||||
|
|
||||||
b.HasIndex("WatermarkId");
|
b.HasIndex("WatermarkId");
|
||||||
|
|
||||||
b.HasIndex("DecoGroupId", "Name")
|
b.HasIndex("DecoGroupId", "Name")
|
||||||
@@ -4409,6 +4438,26 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Deco", b =>
|
modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Deco", b =>
|
||||||
{
|
{
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.Collection", "DeadAirFallbackCollection")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackCollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.MediaItem", "DeadAirFallbackMediaItem")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackMediaItemId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "DeadAirFallbackMultiCollection")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackMultiCollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "DeadAirFallbackSmartCollection")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackSmartCollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
b.HasOne("ErsatzTV.Core.Domain.Scheduling.DecoGroup", "DecoGroup")
|
b.HasOne("ErsatzTV.Core.Domain.Scheduling.DecoGroup", "DecoGroup")
|
||||||
.WithMany("Decos")
|
.WithMany("Decos")
|
||||||
.HasForeignKey("DecoGroupId")
|
.HasForeignKey("DecoGroupId")
|
||||||
@@ -4420,6 +4469,14 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
|||||||
.HasForeignKey("WatermarkId")
|
.HasForeignKey("WatermarkId")
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackCollection");
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackMediaItem");
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackMultiCollection");
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackSmartCollection");
|
||||||
|
|
||||||
b.Navigation("DecoGroup");
|
b.Navigation("DecoGroup");
|
||||||
|
|
||||||
b.Navigation("Watermark");
|
b.Navigation("Watermark");
|
||||||
|
|||||||
Generated
+5429
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,153 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_Deco_DeadAirFallback : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackCollectionType",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackCollectionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMediaItemId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMultiCollectionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackSmartCollectionId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_Collection_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackCollectionId",
|
||||||
|
principalTable: "Collection",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_MediaItem_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMediaItemId",
|
||||||
|
principalTable: "MediaItem",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_MultiCollection_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackMultiCollectionId",
|
||||||
|
principalTable: "MultiCollection",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Deco_SmartCollection_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco",
|
||||||
|
column: "DeadAirFallbackSmartCollectionId",
|
||||||
|
principalTable: "SmartCollection",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_Collection_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_MediaItem_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_MultiCollection_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Deco_SmartCollection_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Deco_DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackCollectionType",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackMediaItemId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackMultiCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackSmartCollectionId",
|
||||||
|
table: "Deco");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5435
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_DecoMode : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "DeadAirFallbackMode",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "WatermarkMode",
|
||||||
|
table: "Deco",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DeadAirFallbackMode",
|
||||||
|
table: "Deco");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "WatermarkMode",
|
||||||
|
table: "Deco");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2036,6 +2036,24 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackCollectionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("DeadAirFallbackCollectionType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackMediaItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("DeadAirFallbackMode")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackMultiCollectionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("DeadAirFallbackSmartCollectionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("DecoGroupId")
|
b.Property<int>("DecoGroupId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@@ -2045,8 +2063,19 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
|||||||
b.Property<int?>("WatermarkId")
|
b.Property<int?>("WatermarkId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("WatermarkMode")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackCollectionId");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackMediaItemId");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackMultiCollectionId");
|
||||||
|
|
||||||
|
b.HasIndex("DeadAirFallbackSmartCollectionId");
|
||||||
|
|
||||||
b.HasIndex("WatermarkId");
|
b.HasIndex("WatermarkId");
|
||||||
|
|
||||||
b.HasIndex("DecoGroupId", "Name")
|
b.HasIndex("DecoGroupId", "Name")
|
||||||
@@ -4254,6 +4283,26 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Deco", b =>
|
modelBuilder.Entity("ErsatzTV.Core.Domain.Scheduling.Deco", b =>
|
||||||
{
|
{
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.Collection", "DeadAirFallbackCollection")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackCollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.MediaItem", "DeadAirFallbackMediaItem")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackMediaItemId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "DeadAirFallbackMultiCollection")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackMultiCollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.SmartCollection", "DeadAirFallbackSmartCollection")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeadAirFallbackSmartCollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
b.HasOne("ErsatzTV.Core.Domain.Scheduling.DecoGroup", "DecoGroup")
|
b.HasOne("ErsatzTV.Core.Domain.Scheduling.DecoGroup", "DecoGroup")
|
||||||
.WithMany("Decos")
|
.WithMany("Decos")
|
||||||
.HasForeignKey("DecoGroupId")
|
.HasForeignKey("DecoGroupId")
|
||||||
@@ -4265,6 +4314,14 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
|||||||
.HasForeignKey("WatermarkId")
|
.HasForeignKey("WatermarkId")
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackCollection");
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackMediaItem");
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackMultiCollection");
|
||||||
|
|
||||||
|
b.Navigation("DeadAirFallbackSmartCollection");
|
||||||
|
|
||||||
b.Navigation("DecoGroup");
|
b.Navigation("DecoGroup");
|
||||||
|
|
||||||
b.Navigation("Watermark");
|
b.Navigation("Watermark");
|
||||||
|
|||||||
@@ -24,5 +24,29 @@ public class DecoConfiguration : IEntityTypeConfiguration<Deco>
|
|||||||
.HasForeignKey(d => d.WatermarkId)
|
.HasForeignKey(d => d.WatermarkId)
|
||||||
.OnDelete(DeleteBehavior.SetNull)
|
.OnDelete(DeleteBehavior.SetNull)
|
||||||
.IsRequired(false);
|
.IsRequired(false);
|
||||||
|
|
||||||
|
builder.HasOne(d => d.DeadAirFallbackCollection)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(d => d.DeadAirFallbackCollectionId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired(false);
|
||||||
|
|
||||||
|
builder.HasOne(d => d.DeadAirFallbackMediaItem)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(d => d.DeadAirFallbackMediaItemId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired(false);
|
||||||
|
|
||||||
|
builder.HasOne(d => d.DeadAirFallbackMultiCollection)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(d => d.DeadAirFallbackMultiCollectionId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired(false);
|
||||||
|
|
||||||
|
builder.HasOne(d => d.DeadAirFallbackSmartCollection)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(d => d.DeadAirFallbackSmartCollectionId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+193
-11
@@ -1,19 +1,43 @@
|
|||||||
@page "/decos/{Id:int}"
|
@page "/decos/{Id:int}"
|
||||||
@using ErsatzTV.Application.Scheduling
|
@using ErsatzTV.Application.Scheduling
|
||||||
@using ErsatzTV.Application.Watermarks
|
@using ErsatzTV.Application.Watermarks
|
||||||
|
@using ErsatzTV.Application.MediaCollections
|
||||||
|
@using ErsatzTV.Application.MediaItems
|
||||||
|
@using ErsatzTV.Application.Television
|
||||||
|
@using ErsatzTV.Application.Artists
|
||||||
|
@using ErsatzTV.Core.Domain.Scheduling
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject ILogger<DecoEditor> Logger
|
@inject ILogger<DecoEditor> Logger
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
@inject IMediator Mediator
|
@inject IMediator Mediator
|
||||||
|
|
||||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8" Style="display: flex; flex-direction: row">
|
||||||
<MudText Typo="Typo.h4" Class="mb-4">Edit Deco</MudText>
|
<MudStack Class="mr-6">
|
||||||
<div style="max-width: 400px">
|
<MudText Typo="Typo.h4" Class="mb-4">Edit Deco</MudText>
|
||||||
<MudCard>
|
<MudCard Class="mb-6" Style="width: 350px">
|
||||||
<MudCardContent>
|
<MudCardContent>
|
||||||
<MudTextField Label="Name" @bind-Value="_deco.Name" For="@(() => _deco.Name)"/>
|
<MudTextField Label="Name" @bind-Value="_deco.Name" For="@(() => _deco.Name)"/>
|
||||||
<MudSelect Class="mt-3" Label="Watermark" @bind-Value="_deco.WatermarkId" For="@(() => _deco.WatermarkId)"
|
</MudCardContent>
|
||||||
|
<MudCardActions>
|
||||||
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SaveChanges())" StartIcon="@Icons.Material.Filled.Save">
|
||||||
|
Save Changes
|
||||||
|
</MudButton>
|
||||||
|
</MudCardActions>
|
||||||
|
</MudCard>
|
||||||
|
<MudCard Class="mb-6" Style="width: 350px">
|
||||||
|
<MudCardHeader>
|
||||||
|
<CardHeaderContent>
|
||||||
|
<MudText Typo="Typo.h6">Watermark</MudText>
|
||||||
|
</CardHeaderContent>
|
||||||
|
</MudCardHeader>
|
||||||
|
<MudCardContent>
|
||||||
|
<MudSelect Label="Watermark Mode" @bind-Value="_deco.WatermarkMode" For="@(() => _deco.WatermarkMode)">
|
||||||
|
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||||
|
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||||
|
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||||
|
</MudSelect>
|
||||||
|
<MudSelect Disabled="@(_deco.WatermarkMode != DecoMode.Override)" Label="Watermark Override" @bind-Value="_deco.WatermarkId" For="@(() => _deco.WatermarkId)"
|
||||||
Clearable="true">
|
Clearable="true">
|
||||||
<MudSelectItem T="int?" Value="@((int?)null)">(none)</MudSelectItem>
|
<MudSelectItem T="int?" Value="@((int?)null)">(none)</MudSelectItem>
|
||||||
@foreach (WatermarkViewModel watermark in _watermarks)
|
@foreach (WatermarkViewModel watermark in _watermarks)
|
||||||
@@ -23,10 +47,116 @@
|
|||||||
</MudSelect>
|
</MudSelect>
|
||||||
</MudCardContent>
|
</MudCardContent>
|
||||||
</MudCard>
|
</MudCard>
|
||||||
</div>
|
<MudCard Class="mb-6" Style="width: 350px">
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SaveChanges())" Class="mt-4 ml-4">
|
<MudCardHeader>
|
||||||
Save Changes
|
<CardHeaderContent>
|
||||||
</MudButton>
|
<MudTooltip Style="max-width: 350px">
|
||||||
|
<ChildContent>
|
||||||
|
<MudText Typo="Typo.h6">Dead Air Fallback</MudText>
|
||||||
|
</ChildContent>
|
||||||
|
<TooltipContent>
|
||||||
|
<MudText Typo="Typo.body2">When no playout item is found for the current time, *one* item will be randomly selected from this collection and looped and cut to exactly fit until the start of the next playout item.</MudText>
|
||||||
|
<MudText Typo="Typo.body2" Class="mt-3">This replaces the "Channel is Offline" image that would otherwise display.</MudText>
|
||||||
|
</TooltipContent>
|
||||||
|
</MudTooltip>
|
||||||
|
</CardHeaderContent>
|
||||||
|
</MudCardHeader>
|
||||||
|
<MudCardContent>
|
||||||
|
<MudSelect Label="Dead Air Fallback Mode" @bind-Value="_deco.DeadAirFallbackMode" For="@(() => _deco.DeadAirFallbackMode)">
|
||||||
|
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||||
|
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||||
|
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||||
|
</MudSelect>
|
||||||
|
<MudSelect Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Dead Air Fallback Collection Type"
|
||||||
|
@bind-Value="_deco.DeadAirFallbackCollectionType"
|
||||||
|
For="@(() => _deco.DeadAirFallbackCollectionType)">
|
||||||
|
@foreach (ProgramScheduleItemCollectionType collectionType in Enum.GetValues<ProgramScheduleItemCollectionType>())
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@collectionType">@collectionType</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.Collection)
|
||||||
|
{
|
||||||
|
<MudSelect Class="mt-3"
|
||||||
|
T="MediaCollectionViewModel"
|
||||||
|
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Collection"
|
||||||
|
@bind-value="_deco.DeadAirFallbackCollection">
|
||||||
|
@foreach (MediaCollectionViewModel collection in _mediaCollections)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.MultiCollection)
|
||||||
|
{
|
||||||
|
<MudSelect Class="mt-3"
|
||||||
|
T="MultiCollectionViewModel"
|
||||||
|
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Multi Collection"
|
||||||
|
@bind-value="_deco.DeadAirFallbackMultiCollection">
|
||||||
|
@foreach (MultiCollectionViewModel collection in _multiCollections)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.SmartCollection)
|
||||||
|
{
|
||||||
|
<MudSelect Class="mt-3"
|
||||||
|
T="SmartCollectionViewModel"
|
||||||
|
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Smart Collection"
|
||||||
|
@bind-value="_deco.DeadAirFallbackSmartCollection">
|
||||||
|
@foreach (SmartCollectionViewModel collection in _smartCollections)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.TelevisionShow)
|
||||||
|
{
|
||||||
|
<MudSelect Class="mt-3"
|
||||||
|
T="NamedMediaItemViewModel"
|
||||||
|
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Television Show"
|
||||||
|
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||||
|
@foreach (NamedMediaItemViewModel show in _televisionShows)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@show">@show.Name</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.TelevisionSeason)
|
||||||
|
{
|
||||||
|
<MudSelect Class="mt-3"
|
||||||
|
T="NamedMediaItemViewModel"
|
||||||
|
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Television Season"
|
||||||
|
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||||
|
@foreach (NamedMediaItemViewModel season in _televisionSeasons)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@season">@season.Name</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.Artist)
|
||||||
|
{
|
||||||
|
<MudSelect Class="mt-3"
|
||||||
|
T="NamedMediaItemViewModel"
|
||||||
|
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||||
|
Label="Artist"
|
||||||
|
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||||
|
@foreach (NamedMediaItemViewModel artist in _artists)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@artist">@artist.Name</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
</MudCardContent>
|
||||||
|
</MudCard>
|
||||||
|
</MudStack>
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@@ -36,8 +166,17 @@
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
private DecoEditViewModel _deco = new();
|
private DecoEditViewModel _deco = new();
|
||||||
|
|
||||||
private List<WatermarkViewModel> _watermarks = [];
|
private List<WatermarkViewModel> _watermarks = [];
|
||||||
|
|
||||||
|
private List<MediaCollectionViewModel> _mediaCollections = [];
|
||||||
|
private List<MultiCollectionViewModel> _multiCollections = [];
|
||||||
|
private List<SmartCollectionViewModel> _smartCollections = [];
|
||||||
|
private List<NamedMediaItemViewModel> _televisionShows = [];
|
||||||
|
private List<NamedMediaItemViewModel> _televisionSeasons = [];
|
||||||
|
private List<NamedMediaItemViewModel> _artists = [];
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_cts.Cancel();
|
_cts.Cancel();
|
||||||
@@ -47,6 +186,20 @@
|
|||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
await LoadWatermarks();
|
await LoadWatermarks();
|
||||||
|
|
||||||
|
_mediaCollections = await Mediator.Send(new GetAllCollections(), _cts.Token)
|
||||||
|
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||||
|
_multiCollections = await Mediator.Send(new GetAllMultiCollections(), _cts.Token)
|
||||||
|
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||||
|
_smartCollections = await Mediator.Send(new GetAllSmartCollections(), _cts.Token)
|
||||||
|
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||||
|
_televisionShows = await Mediator.Send(new GetAllTelevisionShows(), _cts.Token)
|
||||||
|
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||||
|
_televisionSeasons = await Mediator.Send(new GetAllTelevisionSeasons(), _cts.Token)
|
||||||
|
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||||
|
_artists = await Mediator.Send(new GetAllArtists(), _cts.Token)
|
||||||
|
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||||
|
|
||||||
await LoadDeco();
|
await LoadDeco();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,15 +221,44 @@
|
|||||||
{
|
{
|
||||||
Name = deco.Name,
|
Name = deco.Name,
|
||||||
DecoGroupId = deco.DecoGroupId,
|
DecoGroupId = deco.DecoGroupId,
|
||||||
WatermarkId = deco.WatermarkId
|
WatermarkMode = deco.WatermarkMode,
|
||||||
|
WatermarkId = deco.WatermarkId,
|
||||||
|
DeadAirFallbackMode = deco.DeadAirFallbackMode,
|
||||||
|
DeadAirFallbackCollectionType = deco.DeadAirFallbackCollectionType,
|
||||||
|
DeadAirFallbackCollection = deco.DeadAirFallbackCollectionId.HasValue
|
||||||
|
? _mediaCollections.Find(c => c.Id == deco.DeadAirFallbackCollectionId.Value)
|
||||||
|
: null,
|
||||||
|
DeadAirFallbackMediaItem = deco.DeadAirFallbackMediaItemId.HasValue
|
||||||
|
? _televisionShows.Append(_televisionSeasons).Append(_artists).ToList()
|
||||||
|
.Find(vm => vm.MediaItemId == deco.DeadAirFallbackMediaItemId.Value)
|
||||||
|
: null,
|
||||||
|
DeadAirFallbackMultiCollection = deco.DeadAirFallbackMultiCollectionId.HasValue
|
||||||
|
? _multiCollections.Find(c => c.Id == deco.DeadAirFallbackMultiCollectionId.Value)
|
||||||
|
: null,
|
||||||
|
DeadAirFallbackSmartCollection = deco.DeadAirFallbackSmartCollectionId.HasValue
|
||||||
|
? _smartCollections.Find(c => c.Id == deco.DeadAirFallbackSmartCollectionId.Value)
|
||||||
|
: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveChanges()
|
private async Task SaveChanges()
|
||||||
{
|
{
|
||||||
|
var request = new UpdateDeco(
|
||||||
|
Id,
|
||||||
|
_deco.DecoGroupId,
|
||||||
|
_deco.Name,
|
||||||
|
_deco.WatermarkMode,
|
||||||
|
_deco.WatermarkId,
|
||||||
|
_deco.DeadAirFallbackMode,
|
||||||
|
_deco.DeadAirFallbackCollectionType,
|
||||||
|
_deco.DeadAirFallbackCollection?.Id,
|
||||||
|
_deco.DeadAirFallbackMediaItem?.MediaItemId,
|
||||||
|
_deco.DeadAirFallbackMultiCollection?.Id,
|
||||||
|
_deco.DeadAirFallbackSmartCollection?.Id);
|
||||||
|
|
||||||
Seq<BaseError> errorMessages = await Mediator
|
Seq<BaseError> errorMessages = await Mediator
|
||||||
.Send(new UpdateDeco(Id, _deco.DecoGroupId, _deco.Name, _deco.WatermarkId), _cts.Token)
|
.Send(request, _cts.Token)
|
||||||
.Map(e => e.LeftToSeq());
|
.Map(e => e.LeftToSeq());
|
||||||
|
|
||||||
errorMessages.HeadOrNone().Match(
|
errorMessages.HeadOrNone().Match(
|
||||||
|
|||||||
@@ -1,8 +1,20 @@
|
|||||||
|
using ErsatzTV.Application.MediaCollections;
|
||||||
|
using ErsatzTV.Application.MediaItems;
|
||||||
|
using ErsatzTV.Core.Domain;
|
||||||
|
using ErsatzTV.Core.Domain.Scheduling;
|
||||||
|
|
||||||
namespace ErsatzTV.ViewModels;
|
namespace ErsatzTV.ViewModels;
|
||||||
|
|
||||||
public class DecoEditViewModel
|
public class DecoEditViewModel
|
||||||
{
|
{
|
||||||
public int DecoGroupId { get; set; }
|
public int DecoGroupId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public DecoMode WatermarkMode { get; set; }
|
||||||
public int? WatermarkId { get; set; }
|
public int? WatermarkId { get; set; }
|
||||||
|
public DecoMode DeadAirFallbackMode { get; set; }
|
||||||
|
public ProgramScheduleItemCollectionType DeadAirFallbackCollectionType { get; set; }
|
||||||
|
public MediaCollectionViewModel DeadAirFallbackCollection { get; set; }
|
||||||
|
public MultiCollectionViewModel DeadAirFallbackMultiCollection { get; set; }
|
||||||
|
public SmartCollectionViewModel DeadAirFallbackSmartCollection { get; set; }
|
||||||
|
public NamedMediaItemViewModel DeadAirFallbackMediaItem { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user