* refactor classic and block schedules to use same alternate schedule selector * handle start year and end year * add migrations for classic and block schedules * allow editing block template start and end year * add tests that include years * add date range editing to classic (alternate) schedules * fix running tests locally * restore media files load; needed for local folder scanners * update changelog * feedback
145 lines
5.6 KiB
C#
145 lines
5.6 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using ErsatzTV.Core;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Domain.Scheduling;
|
|
using ErsatzTV.Core.Interfaces.Scheduling;
|
|
using ErsatzTV.Core.Scheduling;
|
|
using ErsatzTV.Infrastructure.Data;
|
|
using ErsatzTV.Infrastructure.Extensions;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace ErsatzTV.Application.Scheduling;
|
|
|
|
[SuppressMessage("ReSharper", "SuggestBaseTypeForParameterInConstructor")]
|
|
public class PreviewBlockPlayoutHandler(
|
|
IDbContextFactory<TvContext> dbContextFactory,
|
|
IBlockPlayoutPreviewBuilder blockPlayoutBuilder)
|
|
: IRequestHandler<PreviewBlockPlayout, List<PlayoutItemPreviewViewModel>>
|
|
{
|
|
public async Task<List<PlayoutItemPreviewViewModel>> Handle(
|
|
PreviewBlockPlayout request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
var template = new Template
|
|
{
|
|
Items = []
|
|
};
|
|
|
|
template.Items.Add(
|
|
new TemplateItem
|
|
{
|
|
Block = MapToBlock(request.Data),
|
|
StartTime = TimeSpan.Zero,
|
|
Template = template
|
|
});
|
|
|
|
var playout = new Playout
|
|
{
|
|
Channel = new Channel(Guid.NewGuid())
|
|
{
|
|
Number = "1",
|
|
Name = "Block Preview"
|
|
},
|
|
Items = [],
|
|
ScheduleKind = PlayoutScheduleKind.Block,
|
|
PlayoutHistory = [],
|
|
Templates =
|
|
[
|
|
new PlayoutTemplate
|
|
{
|
|
DaysOfWeek = AlternateScheduleSelector.AllDaysOfWeek(),
|
|
DaysOfMonth = AlternateScheduleSelector.AllDaysOfMonth(),
|
|
MonthsOfYear = AlternateScheduleSelector.AllMonthsOfYear(),
|
|
Template = template
|
|
}
|
|
],
|
|
ProgramSchedule = new ProgramSchedule(),
|
|
ProgramScheduleAlternates = []
|
|
};
|
|
|
|
var referenceData = new PlayoutReferenceData(
|
|
playout.Channel,
|
|
Option<Deco>.None,
|
|
playout.Items,
|
|
playout.Templates.ToList(),
|
|
playout.ProgramSchedule,
|
|
playout.ProgramScheduleAlternates,
|
|
playout.PlayoutHistory.ToList(),
|
|
TimeSpan.Zero);
|
|
|
|
Either<BaseError, PlayoutBuildResult> buildResult =
|
|
await blockPlayoutBuilder.Build(
|
|
DateTimeOffset.Now,
|
|
playout,
|
|
referenceData,
|
|
PlayoutBuildMode.Reset,
|
|
cancellationToken);
|
|
|
|
return await buildResult.MatchAsync(
|
|
async result =>
|
|
{
|
|
// load playout item details for title
|
|
foreach (PlayoutItem playoutItem in result.AddedItems)
|
|
{
|
|
Option<MediaItem> maybeMediaItem = await dbContext.MediaItems
|
|
.AsNoTracking()
|
|
.Include(mi => (mi as Movie).MovieMetadata)
|
|
.Include(mi => (mi as Movie).MediaVersions)
|
|
.Include(mi => (mi as MusicVideo).MusicVideoMetadata)
|
|
.Include(mi => (mi as MusicVideo).MediaVersions)
|
|
.Include(mi => (mi as MusicVideo).Artist)
|
|
.ThenInclude(mm => mm.ArtistMetadata)
|
|
.Include(mi => (mi as Episode).EpisodeMetadata)
|
|
.Include(mi => (mi as Episode).MediaVersions)
|
|
.Include(mi => (mi as Episode).Season)
|
|
.ThenInclude(s => s.SeasonMetadata)
|
|
.Include(mi => (mi as Episode).Season.Show)
|
|
.ThenInclude(s => s.ShowMetadata)
|
|
.Include(mi => (mi as OtherVideo).OtherVideoMetadata)
|
|
.Include(mi => (mi as OtherVideo).MediaVersions)
|
|
.Include(mi => (mi as Song).SongMetadata)
|
|
.Include(mi => (mi as Song).MediaVersions)
|
|
.Include(mi => (mi as Image).ImageMetadata)
|
|
.Include(mi => (mi as Image).MediaVersions)
|
|
.Include(mi => (mi as RemoteStream).RemoteStreamMetadata)
|
|
.Include(mi => (mi as RemoteStream).MediaVersions)
|
|
.SelectOneAsync(mi => mi.Id, mi => mi.Id == playoutItem.MediaItemId, cancellationToken);
|
|
|
|
foreach (MediaItem mediaItem in maybeMediaItem)
|
|
{
|
|
playoutItem.MediaItem = mediaItem;
|
|
}
|
|
}
|
|
|
|
return result.AddedItems.Map(Mapper.ProjectToViewModel).ToList();
|
|
},
|
|
_ => []);
|
|
}
|
|
|
|
private static Block MapToBlock(ReplaceBlockItems request) =>
|
|
new()
|
|
{
|
|
Name = request.Name,
|
|
Minutes = request.Minutes,
|
|
StopScheduling = request.StopScheduling,
|
|
Items = request.Items.Map(MapToBlockItem).ToList()
|
|
};
|
|
|
|
private static BlockItem MapToBlockItem(int id, ReplaceBlockItem request) =>
|
|
new()
|
|
{
|
|
Id = id,
|
|
Index = request.Index,
|
|
CollectionType = request.CollectionType,
|
|
CollectionId = request.CollectionId,
|
|
MultiCollectionId = request.MultiCollectionId,
|
|
SmartCollectionId = request.SmartCollectionId,
|
|
SearchTitle = request.SearchTitle,
|
|
SearchQuery = request.SearchQuery,
|
|
MediaItemId = request.MediaItemId,
|
|
PlaybackOrder = request.PlaybackOrder
|
|
};
|
|
}
|