mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* Add shading to filler rows in the playout view * Insert rows in Playout listing for gaps in the playout (station offline) * Make FillerKind in PlayoutItemViewModel optional. Remove Unscheduled enum in FillerKind. * Correctly handle "Show Filler" also for Unscheduled fillers. * Moved the Unscheduled item generation for the playout view to GetFuturePlayoutItemsByIdHandle to handle ShowFiller * Includes for the PlayoutItemDetails moved to an extension for maintainability. * Bugfix: Page size was more than the desired for pagination because of the inserted unscheduled items. * Add specified colours for playout fillers to make them less intense. * use common queryable * add playout gap model and migrations * insert playout gaps after playout build * optimize get future playout items handler * update changelog --------- Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>pull/2409/head
21 changed files with 13131 additions and 58 deletions
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
namespace ErsatzTV.Application.Playouts; |
||||
|
||||
public record InsertPlayoutGaps(int PlayoutId) : IRequest, IBackgroundServiceRequest; |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
using EFCore.BulkExtensions; |
||||
using ErsatzTV.Core.Domain; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using Microsoft.EntityFrameworkCore; |
||||
|
||||
namespace ErsatzTV.Application.Playouts; |
||||
|
||||
public class InsertPlayoutGapsHandler(IDbContextFactory<TvContext> dbContextFactory) |
||||
: IRequestHandler<InsertPlayoutGaps> |
||||
{ |
||||
public async Task Handle(InsertPlayoutGaps request, CancellationToken cancellationToken) |
||||
{ |
||||
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); |
||||
|
||||
var toAdd = new List<PlayoutGap>(); |
||||
|
||||
IOrderedQueryable<PlayoutItem> query = dbContext.PlayoutItems |
||||
.Filter(pi => pi.PlayoutId == request.PlayoutId) |
||||
.OrderBy(i => i.Start); |
||||
|
||||
var queue = new Queue<PlayoutItem>(query); |
||||
while (queue.Count > 1) |
||||
{ |
||||
PlayoutItem one = queue.Dequeue(); |
||||
PlayoutItem two = queue.Peek(); |
||||
|
||||
DateTimeOffset start = one.FinishOffset; |
||||
DateTimeOffset finish = two.StartOffset; |
||||
|
||||
if (start == finish) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
var gap = new PlayoutGap |
||||
{ |
||||
PlayoutId = request.PlayoutId, |
||||
Start = start.UtcDateTime, |
||||
Finish = finish.UtcDateTime |
||||
}; |
||||
|
||||
toAdd.Add(gap); |
||||
} |
||||
|
||||
// delete all existing gaps
|
||||
await dbContext.PlayoutGaps |
||||
.Where(pg => pg.PlayoutId == request.PlayoutId) |
||||
.ExecuteDeleteAsync(cancellationToken); |
||||
|
||||
// insert new gaps
|
||||
await dbContext.BulkInsertAsync(toAdd, cancellationToken: cancellationToken); |
||||
} |
||||
} |
||||
@ -1,3 +1,5 @@
@@ -1,3 +1,5 @@
|
||||
namespace ErsatzTV.Application.Playouts; |
||||
using ErsatzTV.Core.Domain.Filler; |
||||
|
||||
public record PlayoutItemViewModel(string Title, DateTimeOffset Start, DateTimeOffset Finish, string Duration); |
||||
namespace ErsatzTV.Application.Playouts; |
||||
|
||||
public record PlayoutItemViewModel(string Title, DateTimeOffset Start, DateTimeOffset Finish, string Duration, Option<FillerKind> FillerKind); |
||||
|
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
namespace ErsatzTV.Core.Domain; |
||||
|
||||
public class PlayoutGap |
||||
{ |
||||
public int Id { get; set; } |
||||
public int PlayoutId { get; set; } |
||||
public Playout Playout { get; set; } |
||||
public DateTime Start { get; set; } |
||||
public DateTime Finish { get; set; } |
||||
public DateTimeOffset StartOffset => new DateTimeOffset(Start, TimeSpan.Zero).ToLocalTime(); |
||||
public DateTimeOffset FinishOffset => new DateTimeOffset(Finish, TimeSpan.Zero).ToLocalTime(); |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
using System; |
||||
using Microsoft.EntityFrameworkCore.Metadata; |
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
#nullable disable |
||||
|
||||
namespace ErsatzTV.Infrastructure.MySql.Migrations |
||||
{ |
||||
/// <inheritdoc />
|
||||
public partial class Add_PlayoutGap : Migration |
||||
{ |
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.CreateTable( |
||||
name: "PlayoutGap", |
||||
columns: table => new |
||||
{ |
||||
Id = table.Column<int>(type: "int", nullable: false) |
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
||||
PlayoutId = table.Column<int>(type: "int", nullable: false), |
||||
Start = table.Column<DateTime>(type: "datetime(6)", nullable: false), |
||||
Finish = table.Column<DateTime>(type: "datetime(6)", nullable: false) |
||||
}, |
||||
constraints: table => |
||||
{ |
||||
table.PrimaryKey("PK_PlayoutGap", x => x.Id); |
||||
table.ForeignKey( |
||||
name: "FK_PlayoutGap_Playout_PlayoutId", |
||||
column: x => x.PlayoutId, |
||||
principalTable: "Playout", |
||||
principalColumn: "Id", |
||||
onDelete: ReferentialAction.Cascade); |
||||
}) |
||||
.Annotation("MySql:CharSet", "utf8mb4"); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_PlayoutGap_PlayoutId", |
||||
table: "PlayoutGap", |
||||
column: "PlayoutId"); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_PlayoutGap_Start_Finish", |
||||
table: "PlayoutGap", |
||||
columns: new[] { "Start", "Finish" }); |
||||
} |
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropTable( |
||||
name: "PlayoutGap"); |
||||
} |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
using System; |
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
#nullable disable |
||||
|
||||
namespace ErsatzTV.Infrastructure.Sqlite.Migrations |
||||
{ |
||||
/// <inheritdoc />
|
||||
public partial class Add_PlayoutGap : Migration |
||||
{ |
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.CreateTable( |
||||
name: "PlayoutGap", |
||||
columns: table => new |
||||
{ |
||||
Id = table.Column<int>(type: "INTEGER", nullable: false) |
||||
.Annotation("Sqlite:Autoincrement", true), |
||||
PlayoutId = table.Column<int>(type: "INTEGER", nullable: false), |
||||
Start = table.Column<DateTime>(type: "TEXT", nullable: false), |
||||
Finish = table.Column<DateTime>(type: "TEXT", nullable: false) |
||||
}, |
||||
constraints: table => |
||||
{ |
||||
table.PrimaryKey("PK_PlayoutGap", x => x.Id); |
||||
table.ForeignKey( |
||||
name: "FK_PlayoutGap_Playout_PlayoutId", |
||||
column: x => x.PlayoutId, |
||||
principalTable: "Playout", |
||||
principalColumn: "Id", |
||||
onDelete: ReferentialAction.Cascade); |
||||
}); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_PlayoutGap_PlayoutId", |
||||
table: "PlayoutGap", |
||||
column: "PlayoutId"); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_PlayoutGap_Start_Finish", |
||||
table: "PlayoutGap", |
||||
columns: new[] { "Start", "Finish" }); |
||||
} |
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropTable( |
||||
name: "PlayoutGap"); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
using ErsatzTV.Core.Domain; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders; |
||||
|
||||
namespace ErsatzTV.Infrastructure.Data.Configurations; |
||||
|
||||
public class PlayoutGapConfiguration : IEntityTypeConfiguration<PlayoutGap> |
||||
|
||||
{ |
||||
public void Configure(EntityTypeBuilder<PlayoutGap> builder) |
||||
{ |
||||
builder.ToTable("PlayoutGap"); |
||||
|
||||
builder.HasIndex(p => new { p.Start, p.Finish }) |
||||
.HasDatabaseName("IX_PlayoutGap_Start_Finish"); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue