fix(api): resolve mirror channel now playing state
This commit is contained in:
@@ -25,7 +25,27 @@ public class GetChannelStatesForApiHandler(
|
||||
.ThenBy(c => c.Number)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
int[] channelIds = channels.Map(c => c.Id).ToArray();
|
||||
if (channels.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
Dictionary<int, (int SourceChannelId, TimeSpan Offset, DateTime LookupTime)> channelLookup = channels
|
||||
.ToDictionary(
|
||||
c => c.Id,
|
||||
c =>
|
||||
{
|
||||
TimeSpan offset = c.PlayoutOffset ?? TimeSpan.Zero;
|
||||
return (c.MirrorSourceChannelId ?? c.Id, offset, now - offset);
|
||||
});
|
||||
|
||||
int[] sourceChannelIds = channelLookup.Values
|
||||
.Map(v => v.SourceChannelId)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
DateTime minLookupTime = channelLookup.Values.Min(v => v.LookupTime);
|
||||
DateTime maxLookupTime = channelLookup.Values.Max(v => v.LookupTime);
|
||||
|
||||
List<PlayoutItem> currentItems = await dbContext.PlayoutItems
|
||||
.AsNoTracking()
|
||||
@@ -51,26 +71,32 @@ public class GetChannelStatesForApiHandler(
|
||||
.ThenInclude(mi => (mi as Image).ImageMetadata)
|
||||
.Include(pi => pi.MediaItem)
|
||||
.ThenInclude(mi => (mi as RemoteStream).RemoteStreamMetadata)
|
||||
.Where(pi => channelIds.Contains(pi.Playout.ChannelId))
|
||||
.Where(pi => pi.Start <= now && pi.Finish > now)
|
||||
.Where(pi => sourceChannelIds.Contains(pi.Playout.ChannelId))
|
||||
.Where(pi => pi.Start <= maxLookupTime && pi.Finish > minLookupTime)
|
||||
.OrderBy(pi => pi.Start)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
Dictionary<int, PlayoutItem> currentItemsByChannelId = currentItems
|
||||
Dictionary<int, List<PlayoutItem>> currentItemsBySourceChannelId = currentItems
|
||||
.GroupBy(pi => pi.Playout.ChannelId)
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
.ToDictionary(g => g.Key, g => g.OrderBy(pi => pi.Start).ToList());
|
||||
|
||||
return channels
|
||||
.Map(channel =>
|
||||
{
|
||||
currentItemsByChannelId.TryGetValue(channel.Id, out PlayoutItem playoutItem);
|
||||
(int sourceChannelId, TimeSpan offset, DateTime lookupTime) = channelLookup[channel.Id];
|
||||
PlayoutItem playoutItem = null;
|
||||
|
||||
if (currentItemsBySourceChannelId.TryGetValue(sourceChannelId, out List<PlayoutItem> candidates))
|
||||
{
|
||||
playoutItem = candidates.FirstOrDefault(pi => pi.Start <= lookupTime && pi.Finish > lookupTime);
|
||||
}
|
||||
|
||||
ChannelNowPlayingResponseModel nowPlaying = playoutItem is null
|
||||
? null
|
||||
: new ChannelNowPlayingResponseModel(
|
||||
PlayoutMapper.GetDisplayTitle(playoutItem.MediaItem, Optional(playoutItem.ChapterTitle)),
|
||||
new DateTimeOffset(playoutItem.Start, TimeSpan.Zero),
|
||||
new DateTimeOffset(playoutItem.Finish, TimeSpan.Zero));
|
||||
new DateTimeOffset(playoutItem.Start + offset, TimeSpan.Zero),
|
||||
new DateTimeOffset(playoutItem.Finish + offset, TimeSpan.Zero));
|
||||
|
||||
return new ChannelStateResponseModel(
|
||||
channel.Id,
|
||||
|
||||
@@ -105,6 +105,56 @@ public class GetChannelStatesForApiHandlerTests
|
||||
state.NowPlaying.Title.ShouldBe("Live Source");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Handle_Should_Resolve_Mirror_Channel_NowPlaying_From_Source_With_Offset()
|
||||
{
|
||||
TimeSpan offset = TimeSpan.FromHours(1);
|
||||
DateTime sourceStart = DateTime.UtcNow.AddMinutes(-70);
|
||||
DateTime sourceFinish = DateTime.UtcNow.AddMinutes(-40);
|
||||
|
||||
await using TvContext context = _db.CreateContext();
|
||||
Channel source = MakeChannel(10, "10");
|
||||
Channel mirror = MakeChannel(11, "11");
|
||||
mirror.PlayoutSource = ChannelPlayoutSource.Mirror;
|
||||
mirror.MirrorSourceChannelId = source.Id;
|
||||
mirror.PlayoutOffset = offset;
|
||||
|
||||
var movie = new Movie
|
||||
{
|
||||
Id = 110,
|
||||
MovieMetadata = [new MovieMetadata { Title = "Offset Feature" }]
|
||||
};
|
||||
var playout = new Playout { Id = 111, Channel = source, ChannelId = source.Id, Items = [] };
|
||||
var item = new PlayoutItem
|
||||
{
|
||||
Id = 112,
|
||||
MediaItem = movie,
|
||||
MediaItemId = movie.Id,
|
||||
Playout = playout,
|
||||
PlayoutId = playout.Id,
|
||||
Start = sourceStart,
|
||||
Finish = sourceFinish,
|
||||
ChapterTitle = string.Empty
|
||||
};
|
||||
|
||||
context.Channels.AddRange(source, mirror);
|
||||
context.Movies.Add(movie);
|
||||
context.Playouts.Add(playout);
|
||||
context.PlayoutItems.Add(item);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var handler = new GetChannelStatesForApiHandler(_db.Factory, _segmenter);
|
||||
|
||||
List<ChannelStateResponseModel> result =
|
||||
await handler.Handle(new GetChannelStatesForApi(), CancellationToken.None);
|
||||
|
||||
ChannelStateResponseModel mirrorState = result.Single(s => s.ChannelId == mirror.Id);
|
||||
mirrorState.NowPlaying.ShouldNotBeNull();
|
||||
mirrorState.NowPlaying.Title.ShouldBe("Offset Feature");
|
||||
mirrorState.NowPlaying.StartUtc.ShouldBe(new DateTimeOffset(sourceStart + offset, TimeSpan.Zero));
|
||||
mirrorState.NowPlaying.FinishUtc.ShouldBe(new DateTimeOffset(sourceFinish + offset, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
private async Task SeedChannelWithMovie(DateTime start, DateTime finish)
|
||||
{
|
||||
await using TvContext context = _db.CreateContext();
|
||||
|
||||
Reference in New Issue
Block a user