mirror of https://github.com/ErsatzTV/ErsatzTV.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
7.7 KiB
219 lines
7.7 KiB
using System.Collections.Immutable; |
|
using ErsatzTV.Core.Domain; |
|
using ErsatzTV.Core.Extensions; |
|
using ErsatzTV.Core.Interfaces.Repositories; |
|
|
|
namespace ErsatzTV.Core.Scheduling.Engine; |
|
|
|
public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository) |
|
{ |
|
public async Task<Option<PlaylistEnumerator>> GetEnumerator( |
|
List<MediaItem> mediaItems, |
|
MarathonGroupBy marathonGroupBy, |
|
bool marathonShuffleGroups, |
|
bool marathonShuffleItems, |
|
Option<int> marathonBatchSize, |
|
CollectionEnumeratorState state, |
|
CancellationToken cancellationToken) |
|
{ |
|
List<IGrouping<GroupKey, MediaItem>> groups = []; |
|
|
|
PlaybackOrder itemPlaybackOrder; |
|
|
|
// group by show |
|
switch (marathonGroupBy) |
|
{ |
|
case MarathonGroupBy.Show: |
|
groups.AddRange(mediaItems.GroupBy(MediaItemKeyByShow)); |
|
itemPlaybackOrder = marathonShuffleItems ? PlaybackOrder.Shuffle : PlaybackOrder.SeasonEpisode; |
|
break; |
|
case MarathonGroupBy.Season: |
|
groups.AddRange(mediaItems.GroupBy(MediaItemKeyBySeason)); |
|
itemPlaybackOrder = marathonShuffleItems ? PlaybackOrder.Shuffle : PlaybackOrder.SeasonEpisode; |
|
break; |
|
case MarathonGroupBy.Artist: |
|
groups.AddRange(mediaItems.GroupBy(MediaItemKeyByArtist)); |
|
itemPlaybackOrder = marathonShuffleItems ? PlaybackOrder.Shuffle : PlaybackOrder.Chronological; |
|
break; |
|
case MarathonGroupBy.Album: |
|
groups.AddRange(mediaItems.GroupBy(MediaItemKeyByAlbum)); |
|
itemPlaybackOrder = marathonShuffleItems ? PlaybackOrder.Shuffle : PlaybackOrder.Chronological; |
|
break; |
|
default: |
|
return Option<PlaylistEnumerator>.None; |
|
} |
|
|
|
Dictionary<PlaylistItem, List<MediaItem>> itemMap = []; |
|
|
|
for (var index = 0; index < groups.Count; index++) |
|
{ |
|
IGrouping<GroupKey, MediaItem> group = groups[index]; |
|
PlaylistItem playlistItem = GroupToPlaylistItem( |
|
index, |
|
marathonBatchSize.IsNone, |
|
itemPlaybackOrder, |
|
group); |
|
itemMap.Add(playlistItem, group.ToList()); |
|
} |
|
|
|
return await PlaylistEnumerator.Create( |
|
mediaCollectionRepository, |
|
itemMap, |
|
state, |
|
marathonShuffleGroups, |
|
marathonBatchSize, |
|
cancellationToken); |
|
} |
|
|
|
public async Task<Option<PlaylistContentResult>> GetEnumerator( |
|
Dictionary<string, List<string>> guids, |
|
List<string> searches, |
|
string groupBy, |
|
bool shuffleGroups, |
|
PlaybackOrder itemPlaybackOrder, |
|
bool playAllItems, |
|
CollectionEnumeratorState state, |
|
CancellationToken cancellationToken) |
|
{ |
|
var allMediaItems = new List<MediaItem>(); |
|
|
|
// grab items from each show guid |
|
foreach (string showGuid in guids.SelectMany(g => g.Value.Select(v => $"{g.Key}://{v}"))) |
|
{ |
|
allMediaItems.AddRange(await mediaCollectionRepository.GetShowItemsByShowGuids([showGuid])); |
|
} |
|
|
|
// grab items from each search |
|
foreach (string query in searches) |
|
{ |
|
allMediaItems.AddRange(await mediaCollectionRepository.GetSmartCollectionItems(query, string.Empty, cancellationToken)); |
|
} |
|
|
|
List<IGrouping<GroupKey, MediaItem>> groups = []; |
|
|
|
// group by show |
|
if (string.Equals(groupBy, "show", StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
groups.AddRange(allMediaItems.GroupBy(MediaItemKeyByShow)); |
|
} |
|
// group by season |
|
else if (string.Equals(groupBy, "season", StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
groups.AddRange(allMediaItems.GroupBy(MediaItemKeyBySeason)); |
|
} |
|
// group by artist |
|
else if (string.Equals(groupBy, "artist", StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
groups.AddRange(allMediaItems.GroupBy(MediaItemKeyByArtist)); |
|
} |
|
// group by album |
|
else if (string.Equals(groupBy, "album", StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
groups.AddRange(allMediaItems.GroupBy(MediaItemKeyByAlbum)); |
|
} |
|
|
|
Dictionary<PlaylistItem, List<MediaItem>> itemMap = []; |
|
|
|
for (var index = 0; index < groups.Count; index++) |
|
{ |
|
IGrouping<GroupKey, MediaItem> group = groups[index]; |
|
PlaylistItem playlistItem = GroupToPlaylistItem(index, playAllItems, itemPlaybackOrder, group); |
|
itemMap.Add(playlistItem, group.ToList()); |
|
} |
|
|
|
PlaylistEnumerator enumerator = await PlaylistEnumerator.Create( |
|
mediaCollectionRepository, |
|
itemMap, |
|
state, |
|
shuffleGroups, |
|
batchSize: Option<int>.None, |
|
cancellationToken); |
|
|
|
return new PlaylistContentResult( |
|
enumerator, |
|
itemMap.ToImmutableDictionary(x => CollectionKey.ForPlaylistItem(x.Key), x => x.Value)); |
|
} |
|
|
|
private static GroupKey MediaItemKeyByShow(MediaItem mediaItem) => |
|
mediaItem switch |
|
{ |
|
Episode e => new GroupKey( |
|
CollectionType.TelevisionShow, |
|
null, |
|
null, |
|
null, |
|
e.Season?.ShowId ?? 0), |
|
_ => new GroupKey(CollectionType.TelevisionShow, null, null, null, 0) |
|
}; |
|
|
|
private static GroupKey MediaItemKeyBySeason(MediaItem mediaItem) => |
|
mediaItem switch |
|
{ |
|
Episode e => new GroupKey( |
|
CollectionType.TelevisionSeason, |
|
null, |
|
null, |
|
null, |
|
e.SeasonId), |
|
_ => new GroupKey(CollectionType.TelevisionSeason, null, null, null, 0) |
|
}; |
|
|
|
private static GroupKey MediaItemKeyByArtist(MediaItem mediaItem) => |
|
mediaItem switch |
|
{ |
|
MusicVideo mv => new GroupKey( |
|
CollectionType.Artist, |
|
null, |
|
null, |
|
null, |
|
mv.ArtistId), |
|
_ => new GroupKey(CollectionType.Artist, null, null, null, 0) |
|
}; |
|
|
|
private static GroupKey MediaItemKeyByAlbum(MediaItem mediaItem) => |
|
mediaItem switch |
|
{ |
|
Song s => new GroupKey( |
|
CollectionType.Collection, |
|
s.SongMetadata.HeadOrNone().Map(sm => sm.Album.GetStableHashCode()).IfNone(0), |
|
null, |
|
null, |
|
null), |
|
MusicVideo mv => new GroupKey( |
|
CollectionType.Collection, |
|
mv.MusicVideoMetadata.HeadOrNone() |
|
.Map(mvm => $"{mv.ArtistId}-${mvm.Album}".GetStableHashCode()).IfNone(0), |
|
null, |
|
null, |
|
null), |
|
_ => new GroupKey(CollectionType.Collection, 0, null, null, null) |
|
}; |
|
|
|
private static PlaylistItem GroupToPlaylistItem( |
|
int index, |
|
bool playAllItems, |
|
PlaybackOrder playbackOrder, |
|
IGrouping<GroupKey, MediaItem> group) => |
|
new() |
|
{ |
|
Index = index, |
|
|
|
CollectionType = group.Key.CollectionType, |
|
CollectionId = group.Key.CollectionId, |
|
MultiCollectionId = group.Key.MultiCollectionId, |
|
SmartCollectionId = group.Key.SmartCollectionId, |
|
MediaItemId = group.Key.MediaItemId, |
|
|
|
PlayAll = playAllItems, |
|
PlaybackOrder = playbackOrder, |
|
|
|
IncludeInProgramGuide = true |
|
}; |
|
|
|
private record GroupKey( |
|
CollectionType CollectionType, |
|
int? CollectionId, |
|
int? MultiCollectionId, |
|
int? SmartCollectionId, |
|
int? MediaItemId); |
|
}
|
|
|