Stream custom live channels using your own media
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

114 lines
4.3 KiB

using System.Collections.Immutable;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Scheduling;
using Newtonsoft.Json;
namespace ErsatzTV.Core.Scheduling.BlockScheduling;
internal static class BlockPlayoutChangeDetection
{
public static Dictionary<PlayoutItem, BlockKey> GetPlayoutItemToBlockKeyMap(Playout playout)
{
var itemBlockKeys = new Dictionary<PlayoutItem, BlockKey>();
foreach (PlayoutItem item in playout.Items)
{
if (!string.IsNullOrWhiteSpace(item.BlockKey))
{
BlockKey blockKey = JsonConvert.DeserializeObject<BlockKey>(item.BlockKey);
itemBlockKeys.Add(item, blockKey);
}
}
return itemBlockKeys.ToDictionary();
}
public static Tuple<List<EffectiveBlock>, List<PlayoutItem>> FindUpdatedItems(
Playout playout,
Dictionary<PlayoutItem, BlockKey> itemBlockKeys,
List<EffectiveBlock> blocksToSchedule)
{
DateTimeOffset lastScheduledItem = playout.Items.Count == 0
? SystemTime.MinValueUtc
: playout.Items.Max(i => i.StartOffset);
var existingBlockKeys = itemBlockKeys.Values.ToImmutableHashSet();
var blockKeysToSchedule = blocksToSchedule.Map(b => b.BlockKey).ToImmutableHashSet();
var updatedBlocks = new List<EffectiveBlock>();
var updatedItems = new List<PlayoutItem>();
var earliestEffectiveBlocks = new Dictionary<BlockKey, DateTimeOffset>();
var earliestBlocks = new Dictionary<int, DateTimeOffset>();
// process in sorted order to simplify checks
foreach (EffectiveBlock effectiveBlock in blocksToSchedule.OrderBy(b => b.Start))
{
// future blocks always need to be scheduled
if (effectiveBlock.Start > lastScheduledItem)
{
updatedBlocks.Add(effectiveBlock);
}
// if block key is not present in existingBlockKeys, the effective block is new or updated
else if (!existingBlockKeys.Contains(effectiveBlock.BlockKey))
{
updatedBlocks.Add(effectiveBlock);
if (!earliestEffectiveBlocks.ContainsKey(effectiveBlock.BlockKey))
{
earliestEffectiveBlocks[effectiveBlock.BlockKey] = effectiveBlock.Start;
}
if (!earliestBlocks.ContainsKey(effectiveBlock.Block.Id))
{
earliestBlocks[effectiveBlock.Block.Id] = effectiveBlock.Start;
}
}
// if id is present, the block has been modified earlier, so this effective block also needs to update
else if (earliestBlocks.ContainsKey(effectiveBlock.Block.Id))
{
updatedBlocks.Add(effectiveBlock);
}
}
foreach ((BlockKey key, DateTimeOffset value) in earliestEffectiveBlocks)
{
Serilog.Log.Logger.Debug("Earliest effective block: {Key} => {Value}", key, value);
}
foreach ((int blockId, DateTimeOffset value) in earliestBlocks)
{
Serilog.Log.Logger.Debug("Earliest block id: {Id} => {Value}", blockId, value);
}
// find affected playout items
foreach (PlayoutItem item in playout.Items)
{
BlockKey blockKey = itemBlockKeys[item];
bool blockKeyIsAffected = earliestEffectiveBlocks.TryGetValue(blockKey, out DateTimeOffset value) &&
value <= item.StartOffset;
bool blockIdIsAffected = earliestBlocks.TryGetValue(blockKey.b, out DateTimeOffset value2) &&
value2 <= item.StartOffset;
if (!blockKeysToSchedule.Contains(blockKey) || blockKeyIsAffected || blockIdIsAffected)
{
updatedItems.Add(item);
}
}
return Tuple(updatedBlocks, updatedItems);
}
public static void RemoveItemAndHistory(Playout playout, PlayoutItem playoutItem)
{
playout.Items.Remove(playoutItem);
Option<PlayoutHistory> historyToRemove = playout.PlayoutHistory
.Find(h => h.When == playoutItem.Start);
foreach (PlayoutHistory history in historyToRemove)
{
playout.PlayoutHistory.Remove(history);
}
}
}