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/).
- Sync Jellyfin and Emby library name and type changes - 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 - 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 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 ## [26.1.1] - 2026-01-08
### Fixed ### Fixed

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

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

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

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

Loading…
Cancel
Save