Browse Source

add basic block scheduling context

pull/2819/head
Jason Dove 6 months ago
parent
commit
301e137d67
No known key found for this signature in database
  1. 5
      CHANGELOG.md
  2. 155
      ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContextHandler.cs
  3. 24
      ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutBuilder.cs
  4. 8
      ErsatzTV.Core/Scheduling/BlockSchedulingContext.cs

5
CHANGELOG.md

@ -10,8 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -10,8 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add UI language setting to **Settings** > **UI**
- A small number of translations have been added for `Português (Brasil)` and `Polski`
- Translation contributions are always welcome!
- Classic Schedules: add `Troubleshoot` button to playout details table to show info that may be helpful in determining the source of a playout item
- Info includes schedule, schedule item, scheduler, playback order, random seed, collection index
- Add `Troubleshoot` button to playout details table to show info that may be helpful in determining the source of a playout item
- Classic schedule info includes schedule, schedule item, scheduler, playback order, random seed, collection index
- Block schedule info includes block, block item, playback order, random seed, collection index
- E.g. items with the same random seed are part of the same shuffle
### Changed

155
ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContextHandler.cs

@ -27,55 +27,114 @@ public class ProcessSchedulingContextHandler(IDbContextFactory<TvContext> dbCont @@ -27,55 +27,114 @@ public class ProcessSchedulingContextHandler(IDbContextFactory<TvContext> dbCont
}
var classicContext = JsonConvert.DeserializeObject<ClassicSchedulingContext>(request.SerializedContext);
if (classicContext is not null)
if (classicContext is not null && classicContext.ScheduleId > 0)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
string scheduleName = await dbContext.ProgramSchedules
.Where(s => s.Id == classicContext.ScheduleId)
.Select(s => s.Name)
.SingleOrDefaultAsync(cancellationToken);
var scheduleItem = await dbContext.ProgramScheduleItems
.AsNoTracking()
.AsSplitQuery()
.Include(si => si.SmartCollection)
.Include(si => si.Collection)
.Include(si => si.MultiCollection)
.Include(si => si.RerunCollection)
.Include(si => si.Playlist)
.SingleOrDefaultAsync(s => s.Id == classicContext.ItemId, cancellationToken);
ClassicContextScheduleItem item;
if (scheduleItem is not null)
{
string collectionName = scheduleItem.CollectionType switch
{
CollectionType.SmartCollection => scheduleItem.SmartCollection.Name,
CollectionType.Collection => scheduleItem.Collection.Name,
CollectionType.MultiCollection => scheduleItem.MultiCollection.Name,
CollectionType.RerunRerun or CollectionType.RerunFirstRun => scheduleItem.RerunCollection.Name,
CollectionType.Playlist => scheduleItem.Playlist.Name,
_ => null
};
item = new ClassicContextScheduleItem(scheduleItem.Id, scheduleItem.CollectionType, collectionName);
}
else
return await GetClassicDetails(classicContext, cancellationToken);
}
var blockContext = JsonConvert.DeserializeObject<BlockSchedulingContext>(request.SerializedContext);
if (blockContext is not null && blockContext.BlockId > 0)
{
return await GetBlockDetails(blockContext, cancellationToken);
}
return request.SerializedContext;
}
private async Task<Option<string>> GetClassicDetails(
ClassicSchedulingContext classicContext,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
string scheduleName = await dbContext.ProgramSchedules
.Where(s => s.Id == classicContext.ScheduleId)
.Select(s => s.Name)
.SingleOrDefaultAsync(cancellationToken);
var scheduleItem = await dbContext.ProgramScheduleItems
.AsNoTracking()
.AsSplitQuery()
.Include(si => si.Collection)
.Include(si => si.MultiCollection)
.Include(si => si.Playlist)
.Include(si => si.RerunCollection)
.Include(si => si.SmartCollection)
.SingleOrDefaultAsync(s => s.Id == classicContext.ItemId, cancellationToken);
ClassicContextScheduleItem item;
if (scheduleItem is not null)
{
string collectionName = scheduleItem.CollectionType switch
{
item = new ClassicContextScheduleItem(classicContext.ItemId, null, null);
}
CollectionType.Collection => scheduleItem.Collection.Name,
CollectionType.MultiCollection => scheduleItem.MultiCollection.Name,
CollectionType.Playlist => scheduleItem.Playlist.Name,
CollectionType.RerunRerun or CollectionType.RerunFirstRun => scheduleItem.RerunCollection.Name,
CollectionType.SmartCollection => scheduleItem.SmartCollection.Name,
_ => null
};
item = new ClassicContextScheduleItem(scheduleItem.Id, scheduleItem.CollectionType, collectionName);
}
else
{
item = new ClassicContextScheduleItem(classicContext.ItemId, null, null);
}
var context = new ClassicContext(
new ContextScheduler("Classic", classicContext.Scheduler),
new ClassicContextSchedule(classicContext.ScheduleId, scheduleName ?? string.Empty),
item,
new ContextEnumerator(classicContext.Enumerator, classicContext.Seed, classicContext.Index));
var context = new ClassicContext(
new ContextScheduler("Classic", classicContext.Scheduler),
new ClassicContextSchedule(classicContext.ScheduleId, scheduleName ?? string.Empty),
item,
new ContextEnumerator(classicContext.Enumerator, classicContext.Seed, classicContext.Index));
return JsonSerializer.Serialize(context, Options);
return JsonSerializer.Serialize(context, Options);
}
private async Task<Option<string>> GetBlockDetails(BlockSchedulingContext blockContext, CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
var block = await dbContext.Blocks
.Include(b => b.BlockGroup)
.SingleOrDefaultAsync(s => s.Id == blockContext.BlockId, cancellationToken);
var blockItem = await dbContext.BlockItems
.AsNoTracking()
.AsSplitQuery()
.Include(si => si.Collection)
.Include(si => si.MultiCollection)
.Include(si => si.SmartCollection)
.SingleOrDefaultAsync(s => s.Id == blockContext.BlockItemId, cancellationToken);
BlockContextBlockItem item;
if (blockItem is not null)
{
string collectionName = blockItem.CollectionType switch
{
CollectionType.Collection => blockItem.Collection.Name,
CollectionType.MultiCollection => blockItem.MultiCollection.Name,
CollectionType.SmartCollection => blockItem.SmartCollection.Name,
_ => null
};
item = new BlockContextBlockItem(blockItem.Id, blockItem.CollectionType, collectionName);
}
else
{
item = new BlockContextBlockItem(blockContext.BlockItemId, null, null);
}
return request.SerializedContext;
var context = new BlockContext(
new ContextScheduler("Block", null),
new BlockContextBlock(
blockContext.BlockId,
block?.BlockGroup?.Name ?? string.Empty,
block?.Name ?? string.Empty),
item,
new ContextEnumerator(blockContext.Enumerator, blockContext.Seed, blockContext.Index));
return JsonSerializer.Serialize(context, Options);
}
private sealed record ClassicContext(
@ -91,4 +150,14 @@ public class ProcessSchedulingContextHandler(IDbContextFactory<TvContext> dbCont @@ -91,4 +150,14 @@ public class ProcessSchedulingContextHandler(IDbContextFactory<TvContext> dbCont
private sealed record ClassicContextScheduleItem(int Id, CollectionType? CollectionType, string CollectionName);
private sealed record ContextEnumerator(string Name, int Seed, int Index);
private sealed record BlockContext(
ContextScheduler Scheduler,
BlockContextBlock Block,
BlockContextBlockItem BlockItem,
ContextEnumerator Enumerator);
private sealed record BlockContextBlock(int Id, string Group, string Name);
private sealed record BlockContextBlockItem(int Id, CollectionType? CollectionType, string CollectionName);
}

24
ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutBuilder.cs

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Domain.Scheduling;
@ -25,6 +27,13 @@ public class BlockPlayoutBuilder( @@ -25,6 +27,13 @@ public class BlockPlayoutBuilder(
NullValueHandling = NullValueHandling.Ignore
};
private static readonly JsonSerializerOptions Options = new()
{
Converters = { new JsonStringEnumConverter() },
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false
};
protected virtual ILogger Logger => logger;
public virtual async Task<Either<BaseError, PlayoutBuildResult>> Build(
@ -262,7 +271,8 @@ public class BlockPlayoutBuilder( @@ -262,7 +271,8 @@ public class BlockPlayoutBuilder(
CollectionKey = JsonConvert.SerializeObject(collectionKey, JsonSettings),
CollectionEtag = collectionEtags[collectionKey],
PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
PlayoutItemGraphicsElements = [],
SchedulingContext = GetSchedulingContext(blockItem, enumerator)
};
foreach (BlockItemWatermark blockItemWatermark in blockItem.BlockItemWatermarks ?? [])
@ -448,4 +458,16 @@ public class BlockPlayoutBuilder( @@ -448,4 +458,16 @@ public class BlockPlayoutBuilder(
return result;
}
private static string GetSchedulingContext(BlockItem blockItem, IMediaCollectionEnumerator enumerator)
{
var context = new BlockSchedulingContext(
blockItem.BlockId,
blockItem.Id,
enumerator.SchedulingContextName,
enumerator.State.Seed,
enumerator.State.Index);
return System.Text.Json.JsonSerializer.Serialize(context, Options);
}
}

8
ErsatzTV.Core/Scheduling/BlockSchedulingContext.cs

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
namespace ErsatzTV.Core.Scheduling;
public record BlockSchedulingContext(
int BlockId,
int BlockItemId,
string Enumerator,
int Seed,
int Index);
Loading…
Cancel
Save