using ErsatzTV.Core.Domain; using ErsatzTV.Core.Extensions; using ErsatzTV.Core.Interfaces.Repositories; using static ErsatzTV.Application.ProgramSchedules.ScheduleItemDurationEstimator; namespace ErsatzTV.Application.ProgramSchedules; public class GetProgramScheduleItemsWithDurationsHandler( IMediator mediator, IMediaCollectionRepository mediaCollectionRepository) : IRequestHandler { public async Task Handle( GetProgramScheduleItemsWithDurations request, CancellationToken cancellationToken) { List items = await mediator.Send(new GetProgramScheduleItems(request.Id), cancellationToken); Dictionary durationsByCollectionId = await AggregateReferencedCollections(items); var itemsWithEstimates = items .Map(item => item with { DurationEstimate = Estimate(item, durationsByCollectionId) }) .ToList(); List estimates = itemsWithEstimates .Map(item => Optional(item.DurationEstimate)) .Somes() .ToList(); TimeSpan? total = estimates.Count > 0 ? TimeSpan.FromTicks(estimates.Sum(estimate => estimate.Ticks)) : null; return new ProgramScheduleItemsWithDurationViewModel(itemsWithEstimates, total); } // Aggregate MediaVersion.Duration once per distinct referenced collection (not per item). Only plain // collections are resolved here; other reference types are estimated as null (see DurationEstimate docs). private async Task> AggregateReferencedCollections( IReadOnlyList items) { List collectionIds = items .Filter(item => item.CollectionType is CollectionType.Collection && item.Collection is not null) .Filter(item => item.PlayoutMode is PlayoutMode.One or PlayoutMode.Multiple) .Map(item => item.Collection.Id) .Distinct() .ToList(); var result = new Dictionary(); foreach (int collectionId in collectionIds) { List mediaItems = await mediaCollectionRepository.GetItems(collectionId); List durations = mediaItems .Map(mediaItem => mediaItem.GetDurationForPlayout()) .Filter(duration => duration > TimeSpan.Zero) .ToList(); if (durations.Count > 0) { var total = TimeSpan.FromTicks(durations.Sum(duration => duration.Ticks)); result[collectionId] = new CollectionDuration(total, durations.Count); } } return result; } }