Browse Source

add marathon group by director (#2800)

pull/2801/head
Jason Dove 6 months ago committed by GitHub
parent
commit
e80f687612
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 3
      ErsatzTV.Core/Domain/MarathonGroupBy.cs
  3. 42
      ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs
  4. 12
      ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs
  5. 1
      ErsatzTV/Pages/ScheduleItemsEditor.razor

3
CHANGELOG.md

@ -21,6 +21,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -21,6 +21,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add health check to warn about incompatible ffmpeg due to missing filters
- This is directly applicable to homebrew `ffmpeg` on MacOS, which is no longer compatible with ErsatzTV
- `ffmpeg@7` or `ffmpeg-full` should be used instead
- Add `Marathon Group By` option `Director`
- This groups the *first* director on Movies, Episodes, Music Videos and Other Videos
- This is supported in classic schedules and sequential schedules
### Changed
- Disable automatic artwork database cleanup

3
ErsatzTV.Core/Domain/MarathonGroupBy.cs

@ -6,5 +6,6 @@ public enum MarathonGroupBy @@ -6,5 +6,6 @@ public enum MarathonGroupBy
Show = 1,
Season = 2,
Artist = 3,
Album = 4
Album = 4,
Director = 5
}

42
ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs

@ -39,6 +39,10 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository @@ -39,6 +39,10 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
groups.AddRange(mediaItems.GroupBy(MediaItemKeyByAlbum));
itemPlaybackOrder = marathonShuffleItems ? PlaybackOrder.Shuffle : PlaybackOrder.Chronological;
break;
case MarathonGroupBy.Director:
groups.AddRange(mediaItems.GroupBy(MediaItemKeyByDirector));
itemPlaybackOrder = marathonShuffleItems ? PlaybackOrder.Shuffle : PlaybackOrder.Chronological;
break;
default:
return Option<PlaylistEnumerator>.None;
}
@ -111,6 +115,11 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository @@ -111,6 +115,11 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
{
groups.AddRange(allMediaItems.GroupBy(MediaItemKeyByAlbum));
}
// group by (first) director
else if (string.Equals(groupBy, "director", StringComparison.OrdinalIgnoreCase))
{
groups.AddRange(allMediaItems.GroupBy(MediaItemKeyByDirector));
}
Dictionary<PlaylistItem, List<MediaItem>> itemMap = [];
@ -189,6 +198,39 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository @@ -189,6 +198,39 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
_ => new GroupKey(CollectionType.Collection, 0, null, null, null)
};
private static GroupKey MediaItemKeyByDirector(MediaItem mediaItem) =>
mediaItem switch
{
Movie m => new GroupKey(
CollectionType.Collection,
m.MovieMetadata.HeadOrNone().Map(mm => FirstDirectorHashCode(mm.Directors)).IfNone(0),
null,
null,
null),
Episode e => new GroupKey(
CollectionType.Collection,
e.EpisodeMetadata.HeadOrNone().Map(em => FirstDirectorHashCode(em.Directors)).IfNone(0),
null,
null,
null),
MusicVideo mv => new GroupKey(
CollectionType.Collection,
mv.MusicVideoMetadata.HeadOrNone().Map(mvm => FirstDirectorHashCode(mvm.Directors)).IfNone(0),
null,
null,
null),
OtherVideo ov => new GroupKey(
CollectionType.Collection,
ov.OtherVideoMetadata.HeadOrNone().Map(ovm => FirstDirectorHashCode(ovm.Directors)).IfNone(0),
null,
null,
null),
_ => new GroupKey(CollectionType.Collection, 0, null, null, null)
};
private static int FirstDirectorHashCode(List<Director> directors) =>
directors.HeadOrNone().Select(director => director.Name.GetStableHashCode()).FirstOrDefault();
private static PlaylistItem GroupToPlaylistItem(
int index,
bool playAllItems,

12
ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs

@ -1229,9 +1229,12 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -1229,9 +1229,12 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private static Task<List<Movie>> GetMovieItems(TvContext dbContext, IEnumerable<int> movieIds) =>
dbContext.Movies
.TagWithCallSite()
.AsNoTracking()
.Include(m => m.MovieMetadata)
.ThenInclude(mm => mm.Subtitles)
.Include(m => m.MovieMetadata)
.ThenInclude(mm => mm.Directors)
.Include(m => m.MediaVersions)
.ThenInclude(mv => mv.Chapters)
.Include(m => m.MediaVersions)
@ -1291,6 +1294,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -1291,6 +1294,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private static Task<List<MusicVideo>> GetMusicVideoItems(TvContext dbContext, IEnumerable<int> musicVideoIds) =>
dbContext.MusicVideos
.TagWithCallSite()
.AsNoTracking()
.Include(m => m.Artist)
.ThenInclude(a => a.ArtistMetadata)
@ -1298,6 +1302,8 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -1298,6 +1302,8 @@ public class MediaCollectionRepository : IMediaCollectionRepository
.ThenInclude(mvm => mvm.Subtitles)
.Include(m => m.MusicVideoMetadata)
.ThenInclude(mvm => mvm.Artists)
.Include(m => m.MusicVideoMetadata)
.ThenInclude(mvm => mvm.Directors)
.Include(m => m.MediaVersions)
.ThenInclude(mv => mv.Chapters)
.Include(m => m.MediaVersions)
@ -1318,9 +1324,12 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -1318,9 +1324,12 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private static Task<List<OtherVideo>> GetOtherVideoItems(TvContext dbContext, IEnumerable<int> otherVideoIds) =>
dbContext.OtherVideos
.TagWithCallSite()
.AsNoTracking()
.Include(m => m.OtherVideoMetadata)
.ThenInclude(ovm => ovm.Subtitles)
.Include(m => m.OtherVideoMetadata)
.ThenInclude(ovm => ovm.Directors)
.Include(m => m.MediaVersions)
.ThenInclude(mv => mv.Chapters)
.Include(m => m.MediaVersions)
@ -1492,9 +1501,12 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -1492,9 +1501,12 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private static Task<List<Episode>> GetEpisodeItems(TvContext dbContext, IEnumerable<int> episodeIds) =>
dbContext.Episodes
.TagWithCallSite()
.AsNoTracking()
.Include(e => e.EpisodeMetadata)
.ThenInclude(em => em.Subtitles)
.Include(e => e.EpisodeMetadata)
.ThenInclude(em => em.Directors)
.Include(e => e.MediaVersions)
.ThenInclude(mv => mv.Chapters)
.Include(m => m.MediaVersions)

1
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -450,6 +450,7 @@ @@ -450,6 +450,7 @@
<MudSelectItem Value="MarathonGroupBy.Artist">Artist</MudSelectItem>
<MudSelectItem Value="MarathonGroupBy.Season">Season</MudSelectItem>
<MudSelectItem Value="MarathonGroupBy.Show">Show</MudSelectItem>
<MudSelectItem Value="MarathonGroupBy.Director">Director</MudSelectItem>
</MudSelect>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">

Loading…
Cancel
Save