Browse Source

improve erasing playout items and history (#2805)

* improve erasing playout items and history

* fixes
pull/2806/head
Jason Dove 6 months ago committed by GitHub
parent
commit
bf8c821012
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 40
      ErsatzTV.Application/Scheduling/Commands/ErasePlayoutHistoryHandler.cs
  3. 56
      ErsatzTV.Application/Scheduling/Commands/ErasePlayoutItemsHandler.cs

2
CHANGELOG.md

@ -65,6 +65,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -65,6 +65,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Sync Jellyfin and Emby library name and type changes
- Library type (movies, shows) can only be changed when synchronization is *disabled* for the library in ETV
- Fix some sequential and scripted playout build failures when using playlists or marathons
- Fix erasing playout items and history so all related data is also erased
- This includes rerun history, unscheduled gaps, build status
## [26.1.1] - 2026-01-08
### Fixed

40
ErsatzTV.Application/Scheduling/Commands/ErasePlayoutHistoryHandler.cs

@ -21,27 +21,43 @@ public class ErasePlayoutHistoryHandler(IDbContextFactory<TvContext> dbContextFa @@ -21,27 +21,43 @@ public class ErasePlayoutHistoryHandler(IDbContextFactory<TvContext> dbContextFa
foreach (Playout playout in maybePlayout)
{
await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
int nextSeed = new Random().Next();
playout.Seed = nextSeed;
// this deletes the owned PlayoutAnchor
playout.Anchor = null;
playout.OnDemandCheckpoint = null;
await dbContext.SaveChangesAsync(cancellationToken);
await dbContext.Database.ExecuteSqlAsync(
$"DELETE FROM PlayoutItem WHERE PlayoutId = {playout.Id}",
cancellationToken);
await dbContext.PlayoutItems
.Where(pi => pi.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.PlayoutHistory
.Where(ph => ph.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.PlayoutProgramScheduleItemAnchors
.Where(a => a.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.RerunHistory
.Where(rh => rh.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.Database.ExecuteSqlAsync(
$"DELETE FROM PlayoutHistory WHERE PlayoutId = {playout.Id}",
cancellationToken);
await dbContext.PlayoutGaps
.Where(pg => pg.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.Database.ExecuteSqlAsync(
$"DELETE FROM PlayoutAnchor WHERE PlayoutId = {playout.Id}",
cancellationToken);
await dbContext.PlayoutBuildStatus
.Where(pb => pb.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.Database.ExecuteSqlAsync(
$"DELETE FROM PlayoutProgramScheduleAnchor WHERE PlayoutId = {playout.Id}",
cancellationToken);
await transaction.CommitAsync(cancellationToken);
}
}
}

56
ErsatzTV.Application/Scheduling/Commands/ErasePlayoutItemsHandler.cs

@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Scheduling;
@ -14,39 +12,49 @@ public class ErasePlayoutItemsHandler(IDbContextFactory<TvContext> dbContextFact @@ -14,39 +12,49 @@ public class ErasePlayoutItemsHandler(IDbContextFactory<TvContext> dbContextFact
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<Playout> maybePlayout = await dbContext.Playouts
.Include(p => p.Items)
.Include(p => p.PlayoutHistory)
.TagWithCallSite()
.AsNoTracking()
.Filter(p => p.ScheduleKind == PlayoutScheduleKind.Block ||
p.ScheduleKind == PlayoutScheduleKind.Sequential ||
p.ScheduleKind == PlayoutScheduleKind.Scripted)
.SelectOneAsync(p => p.Id, p => p.Id == request.PlayoutId, cancellationToken);
.SingleOrDefaultAsync(p => p.Id == request.PlayoutId, cancellationToken);
foreach (Playout playout in maybePlayout)
{
await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
// find the earliest item that finishes after "now"
Option<PlayoutItem> maybeFirstItem = playout.Items
.Filter(i => i.FinishOffset > DateTimeOffset.Now)
.OrderBy(i => i.StartOffset)
.HeadOrNone();
// delete all history starting with that item
// importantly, do NOT delete earlier history
foreach (PlayoutItem item in maybeFirstItem)
Option<PlayoutItem> maybeFirstItem = await dbContext.PlayoutItems
.TagWithCallSite()
.AsNoTracking()
.Where(pi => pi.PlayoutId == playout.Id)
.Where(pi => pi.Finish > DateTime.UtcNow)
.OrderBy(i => i.Start)
.FirstOrDefaultAsync(cancellationToken);
foreach (PlayoutItem firstItem in maybeFirstItem)
{
var toRemove = playout.PlayoutHistory.Filter(h => h.When >= item.Start).ToList();
foreach (PlayoutHistory history in toRemove)
{
playout.PlayoutHistory.Remove(history);
}
// delete all history starting with that item
// importantly, do NOT delete earlier history
await dbContext.PlayoutHistory
.Where(ph => ph.PlayoutId == playout.Id)
.Where(ph => ph.When >= firstItem.Start)
.ExecuteDeleteAsync(cancellationToken);
}
// save history changes
await dbContext.SaveChangesAsync(cancellationToken);
await dbContext.PlayoutItems
.Where(pi => pi.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.PlayoutGaps
.Where(pg => pg.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
await dbContext.PlayoutBuildStatus
.Where(pb => pb.PlayoutId == playout.Id)
.ExecuteDeleteAsync(cancellationToken);
// delete all playout items
await dbContext.Database.ExecuteSqlAsync(
$"DELETE FROM PlayoutItem WHERE PlayoutId = {playout.Id}",
cancellationToken);
await transaction.CommitAsync(cancellationToken);
}
}
}

Loading…
Cancel
Save