diff --git a/ErsatzTV.Application/MediaCards/SimpleMediaCollectionCardResultsViewModel.cs b/ErsatzTV.Application/MediaCards/CollectionCardResultsViewModel.cs similarity index 83% rename from ErsatzTV.Application/MediaCards/SimpleMediaCollectionCardResultsViewModel.cs rename to ErsatzTV.Application/MediaCards/CollectionCardResultsViewModel.cs index 0ac4bebb9..e84c2dc5f 100644 --- a/ErsatzTV.Application/MediaCards/SimpleMediaCollectionCardResultsViewModel.cs +++ b/ErsatzTV.Application/MediaCards/CollectionCardResultsViewModel.cs @@ -2,7 +2,7 @@ namespace ErsatzTV.Application.MediaCards { - public record SimpleMediaCollectionCardResultsViewModel( + public record CollectionCardResultsViewModel( string Name, List MovieCards, List ShowCards, diff --git a/ErsatzTV.Application/MediaCards/Mapper.cs b/ErsatzTV.Application/MediaCards/Mapper.cs index 23e88ad9e..90b07ade3 100644 --- a/ErsatzTV.Application/MediaCards/Mapper.cs +++ b/ErsatzTV.Application/MediaCards/Mapper.cs @@ -1,42 +1,41 @@ using System; using System.Collections.Generic; -using System.Linq; using ErsatzTV.Core.Domain; namespace ErsatzTV.Application.MediaCards { internal static class Mapper { - internal static TelevisionShowCardViewModel ProjectToViewModel(TelevisionShow televisionShow) => + internal static TelevisionShowCardViewModel ProjectToViewModel(ShowMetadata showMetadata) => new( - televisionShow.Id, - televisionShow.Metadata?.Title, - televisionShow.Metadata?.Year.ToString(), - televisionShow.Metadata?.SortTitle, - televisionShow.Poster); + showMetadata.ShowId, + showMetadata.Title, + showMetadata.ReleaseDate?.Year.ToString(), + showMetadata.SortTitle, + null); // TODO: artwork - internal static TelevisionSeasonCardViewModel ProjectToViewModel(TelevisionSeason televisionSeason) => + internal static TelevisionSeasonCardViewModel ProjectToViewModel(Season season) => new( - televisionSeason.TelevisionShow.Metadata?.Title, - televisionSeason.Id, - televisionSeason.Number, - GetSeasonName(televisionSeason.Number), + season.Show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), + season.Id, + season.SeasonNumber, + GetSeasonName(season.SeasonNumber), string.Empty, - GetSeasonName(televisionSeason.Number), - televisionSeason.Poster, - televisionSeason.Number == 0 ? "S" : televisionSeason.Number.ToString()); + GetSeasonName(season.SeasonNumber), + season.Poster, + season.SeasonNumber == 0 ? "S" : season.SeasonNumber.ToString()); internal static TelevisionEpisodeCardViewModel ProjectToViewModel( - TelevisionEpisodeMediaItem televisionEpisode) => + EpisodeMetadata episodeMetadata) => new( - televisionEpisode.Id, - televisionEpisode.Metadata?.Aired ?? DateTime.MinValue, - televisionEpisode.Season.TelevisionShow.Metadata.Title, - televisionEpisode.Metadata?.Title, - $"Episode {televisionEpisode.Metadata?.Episode}", - televisionEpisode.Metadata?.Episode.ToString(), - televisionEpisode.Poster, - televisionEpisode.Metadata?.Episode.ToString()); + episodeMetadata.EpisodeId, + episodeMetadata.ReleaseDate ?? DateTime.MinValue, + episodeMetadata.Episode.Season.Show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), + episodeMetadata.Title, + $"Episode {episodeMetadata.Episode.EpisodeNumber}", + episodeMetadata.Episode.EpisodeNumber.ToString(), + null, // TODO: artwork + episodeMetadata.Episode.EpisodeNumber.ToString()); internal static MovieCardViewModel ProjectToViewModel(MovieMetadata movieMetadata) => new( @@ -46,15 +45,15 @@ namespace ErsatzTV.Application.MediaCards movieMetadata.SortTitle, null); // TODO: artwork - internal static SimpleMediaCollectionCardResultsViewModel - ProjectToViewModel(SimpleMediaCollection collection) => + internal static CollectionCardResultsViewModel + ProjectToViewModel(Collection collection) => new( collection.Name, // TODO: fix this new List(), // collection.Movies.Map(ProjectToViewModel).ToList(), - collection.TelevisionShows.Map(ProjectToViewModel).ToList(), - collection.TelevisionSeasons.Map(ProjectToViewModel).ToList(), - collection.TelevisionEpisodes.Map(ProjectToViewModel).ToList()); + new List(), // collection.TelevisionShows.Map(ProjectToViewModel).ToList(), + new List(), // collection.TelevisionSeasons.Map(ProjectToViewModel).ToList(), + new List()); // collection.TelevisionEpisodes.Map(ProjectToViewModel).ToList()); private static string GetSeasonName(int number) => number == 0 ? "Specials" : $"Season {number}"; diff --git a/ErsatzTV.Application/MediaCards/Queries/GetCollectionCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetCollectionCards.cs new file mode 100644 index 000000000..cad08a468 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetCollectionCards.cs @@ -0,0 +1,9 @@ +using ErsatzTV.Core; +using LanguageExt; +using MediatR; + +namespace ErsatzTV.Application.MediaCards.Queries +{ + public record GetCollectionCards + (int Id) : IRequest>; +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetCollectionCardsHandler.cs b/ErsatzTV.Application/MediaCards/Queries/GetCollectionCardsHandler.cs new file mode 100644 index 000000000..018745e90 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetCollectionCardsHandler.cs @@ -0,0 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; +using MediatR; +using static ErsatzTV.Application.MediaCards.Mapper; + +namespace ErsatzTV.Application.MediaCards.Queries +{ + public class GetCollectionCardsHandler : IRequestHandler> + { + private readonly ICollectionRepository _collectionRepository; + + public GetCollectionCardsHandler(ICollectionRepository collectionRepository) => + _collectionRepository = collectionRepository; + + public async Task> Handle( + GetCollectionCards request, + CancellationToken cancellationToken) => + (await _collectionRepository.GetWithItemsUntracked(request.Id)) + .ToEither(BaseError.New("Unable to load collection")) + .Map(ProjectToViewModel); + } +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetSimpleMediaCollectionCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetSimpleMediaCollectionCards.cs deleted file mode 100644 index d99fc0ea0..000000000 --- a/ErsatzTV.Application/MediaCards/Queries/GetSimpleMediaCollectionCards.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; -using MediatR; - -namespace ErsatzTV.Application.MediaCards.Queries -{ - public record GetSimpleMediaCollectionCards - (int Id) : IRequest>; -} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetSimpleMediaCollectionCardsHandler.cs b/ErsatzTV.Application/MediaCards/Queries/GetSimpleMediaCollectionCardsHandler.cs deleted file mode 100644 index 07393be8a..000000000 --- a/ErsatzTV.Application/MediaCards/Queries/GetSimpleMediaCollectionCardsHandler.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core; -using ErsatzTV.Core.Interfaces.Repositories; -using LanguageExt; -using MediatR; -using static ErsatzTV.Application.MediaCards.Mapper; - -namespace ErsatzTV.Application.MediaCards.Queries -{ - public class GetSimpleMediaCollectionCardsHandler : IRequestHandler> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - - public GetSimpleMediaCollectionCardsHandler(IMediaCollectionRepository mediaCollectionRepository) => - _mediaCollectionRepository = mediaCollectionRepository; - - public async Task> Handle( - GetSimpleMediaCollectionCards request, - CancellationToken cancellationToken) => - (await _mediaCollectionRepository.GetSimpleMediaCollectionWithItemsUntracked(request.Id)) - .ToEither(BaseError.New("Unable to load collection")) - .Map(ProjectToViewModel); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollection.cs new file mode 100644 index 000000000..ae69c119c --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollection.cs @@ -0,0 +1,7 @@ +using ErsatzTV.Core; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record AddEpisodeToCollection(int CollectionId, int EpisodeId) : MediatR.IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs new file mode 100644 index 000000000..99ba614ac --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs @@ -0,0 +1,67 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public class + AddEpisodeToCollectionHandler : MediatR.IRequestHandler> + { + private readonly IMediaCollectionRepository _mediaCollectionRepository; + private readonly ITelevisionRepository _televisionRepository; + + public AddEpisodeToCollectionHandler( + IMediaCollectionRepository mediaCollectionRepository, + ITelevisionRepository televisionRepository) + { + _mediaCollectionRepository = mediaCollectionRepository; + _televisionRepository = televisionRepository; + } + + public Task> Handle( + AddEpisodeToCollection request, + CancellationToken cancellationToken) => + Validate(request) + .MapT(ApplyAddTelevisionEpisodeRequest) + .Bind(v => v.ToEitherAsync()); + + private async Task ApplyAddTelevisionEpisodeRequest(RequestParameters parameters) + { + if (parameters.Collection.MediaItems.All(s => s.Id != parameters.EpisodeToAdd.Id)) + { + parameters.Collection.MediaItems.Add(parameters.EpisodeToAdd); + await _mediaCollectionRepository.Update(parameters.Collection); + } + + return Unit.Default; + } + + private async Task> + Validate(AddEpisodeToCollection request) => + (await SimpleMediaCollectionMustExist(request), await ValidateEpisode(request)) + .Apply( + (collectionToUpdate, episode) => + new RequestParameters(collectionToUpdate, episode)); + + private Task> SimpleMediaCollectionMustExist( + AddEpisodeToCollection updateCollection) => + _mediaCollectionRepository.GetCollectionWithItems(updateCollection.CollectionId) + .Map(v => v.ToValidation("Collection does not exist.")); + + private Task> ValidateEpisode( + AddEpisodeToCollection request) => + LoadTelevisionEpisode(request) + .Map(v => v.ToValidation("Episode does not exist")); + + private Task> LoadTelevisionEpisode( + AddEpisodeToCollection request) => + _televisionRepository.GetEpisode(request.EpisodeId); + + private record RequestParameters(Collection Collection, Episode EpisodeToAdd); + } +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddMovieCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddMovieCollection.cs new file mode 100644 index 000000000..e9bc90deb --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddMovieCollection.cs @@ -0,0 +1,7 @@ +using ErsatzTV.Core; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record AddMovieToCollection(int CollectionId, int MovieId) : MediatR.IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddMovieToSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs similarity index 54% rename from ErsatzTV.Application/MediaCollections/Commands/AddMovieToSimpleMediaCollectionHandler.cs rename to ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs index 7920a4231..0b81eab03 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddMovieToSimpleMediaCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs @@ -8,13 +8,13 @@ using LanguageExt; namespace ErsatzTV.Application.MediaCollections.Commands { public class - AddMovieToSimpleMediaCollectionHandler : MediatR.IRequestHandler> { private readonly IMediaCollectionRepository _mediaCollectionRepository; private readonly IMovieRepository _movieRepository; - public AddMovieToSimpleMediaCollectionHandler( + public AddMovieToCollectionHandler( IMediaCollectionRepository mediaCollectionRepository, IMovieRepository movieRepository) { @@ -23,7 +23,7 @@ namespace ErsatzTV.Application.MediaCollections.Commands } public Task> Handle( - AddMovieToSimpleMediaCollection request, + AddMovieToCollection request, CancellationToken cancellationToken) => Validate(request) .MapT(ApplyAddMoviesRequest) @@ -31,32 +31,32 @@ namespace ErsatzTV.Application.MediaCollections.Commands private async Task ApplyAddMoviesRequest(RequestParameters parameters) { - parameters.Collection.Movies.Add(parameters.MovieToAdd); + parameters.Collection.MediaItems.Add(parameters.MovieToAdd); await _mediaCollectionRepository.Update(parameters.Collection); return Unit.Default; } private async Task> - Validate(AddMovieToSimpleMediaCollection request) => + Validate(AddMovieToCollection request) => (await SimpleMediaCollectionMustExist(request), await ValidateMovies(request)) .Apply( - (simpleMediaCollectionToUpdate, movieToAdd) => - new RequestParameters(simpleMediaCollectionToUpdate, movieToAdd)); + (collectionToUpdate, movieToAdd) => + new RequestParameters(collectionToUpdate, movieToAdd)); - private Task> SimpleMediaCollectionMustExist( - AddMovieToSimpleMediaCollection updateSimpleMediaCollection) => - _mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId) - .Map(v => v.ToValidation("SimpleMediaCollection does not exist.")); + private Task> SimpleMediaCollectionMustExist( + AddMovieToCollection updateCollection) => + _mediaCollectionRepository.GetCollectionWithItems(updateCollection.CollectionId) + .Map(v => v.ToValidation("Collection does not exist.")); private Task> ValidateMovies( - AddMovieToSimpleMediaCollection request) => + AddMovieToCollection request) => LoadMovie(request) - .Map(v => v.ToValidation("MovieMediaItem does not exist")); + .Map(v => v.ToValidation("Movie does not exist")); - private Task> LoadMovie(AddMovieToSimpleMediaCollection request) => + private Task> LoadMovie(AddMovieToCollection request) => _movieRepository.GetMovie(request.MovieId); - private record RequestParameters(SimpleMediaCollection Collection, Movie MovieToAdd); + private record RequestParameters(Collection Collection, Movie MovieToAdd); } } diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddMovieToSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddMovieToSimpleMediaCollection.cs deleted file mode 100644 index cacb5f4bd..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddMovieToSimpleMediaCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record AddMovieToSimpleMediaCollection - (int MediaCollectionId, int MovieId) : MediatR.IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollection.cs new file mode 100644 index 000000000..e3f795f82 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollection.cs @@ -0,0 +1,7 @@ +using ErsatzTV.Core; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record AddSeasonToCollection(int CollectionId, int SeasonId) : MediatR.IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs new file mode 100644 index 000000000..ee1c1038f --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs @@ -0,0 +1,67 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public class + AddSeasonToCollectionHandler : MediatR.IRequestHandler> + { + private readonly IMediaCollectionRepository _mediaCollectionRepository; + private readonly ITelevisionRepository _televisionRepository; + + public AddSeasonToCollectionHandler( + IMediaCollectionRepository mediaCollectionRepository, + ITelevisionRepository televisionRepository) + { + _mediaCollectionRepository = mediaCollectionRepository; + _televisionRepository = televisionRepository; + } + + public Task> Handle( + AddSeasonToCollection request, + CancellationToken cancellationToken) => + Validate(request) + .MapT(ApplyAddTelevisionSeasonRequest) + .Bind(v => v.ToEitherAsync()); + + private async Task ApplyAddTelevisionSeasonRequest(RequestParameters parameters) + { + if (parameters.Collection.MediaItems.All(s => s.Id != parameters.SeasonToAdd.Id)) + { + parameters.Collection.MediaItems.Add(parameters.SeasonToAdd); + await _mediaCollectionRepository.Update(parameters.Collection); + } + + return Unit.Default; + } + + private async Task> + Validate(AddSeasonToCollection request) => + (await SimpleMediaCollectionMustExist(request), await ValidateSeason(request)) + .Apply( + (collectionToUpdate, season) => + new RequestParameters(collectionToUpdate, season)); + + private Task> SimpleMediaCollectionMustExist( + AddSeasonToCollection updateCollection) => + _mediaCollectionRepository.GetCollectionWithItems(updateCollection.CollectionId) + .Map(v => v.ToValidation("Collection does not exist.")); + + private Task> ValidateSeason( + AddSeasonToCollection request) => + LoadTelevisionSeason(request) + .Map(v => v.ToValidation("Season does not exist")); + + private Task> LoadTelevisionSeason( + AddSeasonToCollection request) => + _televisionRepository.GetSeason(request.SeasonId); + + private record RequestParameters(Collection Collection, Season SeasonToAdd); + } +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollection.cs new file mode 100644 index 000000000..48233e6d4 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollection.cs @@ -0,0 +1,7 @@ +using ErsatzTV.Core; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record AddShowToCollection(int CollectionId, int ShowId) : MediatR.IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs new file mode 100644 index 000000000..d6b1aa5ba --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs @@ -0,0 +1,64 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public class AddShowToCollectionHandler : MediatR.IRequestHandler> + { + private readonly IMediaCollectionRepository _mediaCollectionRepository; + private readonly ITelevisionRepository _televisionRepository; + + public AddShowToCollectionHandler( + IMediaCollectionRepository mediaCollectionRepository, + ITelevisionRepository televisionRepository) + { + _mediaCollectionRepository = mediaCollectionRepository; + _televisionRepository = televisionRepository; + } + + public Task> Handle( + AddShowToCollection request, + CancellationToken cancellationToken) => + Validate(request) + .MapT(ApplyAddTelevisionShowRequest) + .Bind(v => v.ToEitherAsync()); + + private async Task ApplyAddTelevisionShowRequest(RequestParameters parameters) + { + if (parameters.Collection.MediaItems.All(s => s.Id != parameters.ShowToAdd.Id)) + { + parameters.Collection.MediaItems.Add(parameters.ShowToAdd); + await _mediaCollectionRepository.Update(parameters.Collection); + } + + return Unit.Default; + } + + private async Task> + Validate(AddShowToCollection request) => + (await SimpleMediaCollectionMustExist(request), await ValidateShow(request)) + .Apply( + (collectionToUpdate, show) => + new RequestParameters(collectionToUpdate, show)); + + private Task> SimpleMediaCollectionMustExist( + AddShowToCollection updateCollection) => + _mediaCollectionRepository.GetCollectionWithItems(updateCollection.CollectionId) + .Map(v => v.ToValidation("Collection does not exist.")); + + private Task> ValidateShow( + AddShowToCollection request) => + LoadTelevisionShow(request) + .Map(v => v.ToValidation("Show does not exist")); + + private Task> LoadTelevisionShow(AddShowToCollection request) => + _televisionRepository.GetShow(request.ShowId); + + private record RequestParameters(Collection Collection, Show ShowToAdd); + } +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionEpisodeToSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionEpisodeToSimpleMediaCollection.cs deleted file mode 100644 index 290d8d177..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionEpisodeToSimpleMediaCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record AddTelevisionEpisodeToSimpleMediaCollection - (int MediaCollectionId, int TelevisionEpisodeId) : MediatR.IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionEpisodeToSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionEpisodeToSimpleMediaCollectionHandler.cs deleted file mode 100644 index 9604b9ba3..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionEpisodeToSimpleMediaCollectionHandler.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core; -using ErsatzTV.Core.Domain; -using ErsatzTV.Core.Interfaces.Repositories; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public class - AddTelevisionEpisodeToSimpleMediaCollectionHandler : MediatR.IRequestHandler< - AddTelevisionEpisodeToSimpleMediaCollection, - Either> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - private readonly ITelevisionRepository _televisionRepository; - - public AddTelevisionEpisodeToSimpleMediaCollectionHandler( - IMediaCollectionRepository mediaCollectionRepository, - ITelevisionRepository televisionRepository) - { - _mediaCollectionRepository = mediaCollectionRepository; - _televisionRepository = televisionRepository; - } - - public Task> Handle( - AddTelevisionEpisodeToSimpleMediaCollection request, - CancellationToken cancellationToken) => - Validate(request) - .MapT(ApplyAddTelevisionEpisodeRequest) - .Bind(v => v.ToEitherAsync()); - - private async Task ApplyAddTelevisionEpisodeRequest(RequestParameters parameters) - { - if (parameters.Collection.TelevisionEpisodes.All(s => s.Id != parameters.EpisodeToAdd.Id)) - { - parameters.Collection.TelevisionEpisodes.Add(parameters.EpisodeToAdd); - await _mediaCollectionRepository.Update(parameters.Collection); - } - - return Unit.Default; - } - - private async Task> - Validate(AddTelevisionEpisodeToSimpleMediaCollection request) => - (await SimpleMediaCollectionMustExist(request), await ValidateEpisode(request)) - .Apply( - (simpleMediaCollectionToUpdate, episode) => - new RequestParameters(simpleMediaCollectionToUpdate, episode)); - - private Task> SimpleMediaCollectionMustExist( - AddTelevisionEpisodeToSimpleMediaCollection updateSimpleMediaCollection) => - _mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId) - .Map(v => v.ToValidation("SimpleMediaCollection does not exist.")); - - private Task> ValidateEpisode( - AddTelevisionEpisodeToSimpleMediaCollection request) => - LoadTelevisionEpisode(request) - .Map(v => v.ToValidation("TelevisionEpisode does not exist")); - - private Task> LoadTelevisionEpisode( - AddTelevisionEpisodeToSimpleMediaCollection request) => - _televisionRepository.GetEpisode(request.TelevisionEpisodeId); - - private record RequestParameters(SimpleMediaCollection Collection, TelevisionEpisodeMediaItem EpisodeToAdd); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionSeasonToSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionSeasonToSimpleMediaCollection.cs deleted file mode 100644 index 54cde04ad..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionSeasonToSimpleMediaCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record AddTelevisionSeasonToSimpleMediaCollection - (int MediaCollectionId, int TelevisionSeasonId) : MediatR.IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionSeasonToSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionSeasonToSimpleMediaCollectionHandler.cs deleted file mode 100644 index fb4ada450..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionSeasonToSimpleMediaCollectionHandler.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core; -using ErsatzTV.Core.Domain; -using ErsatzTV.Core.Interfaces.Repositories; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public class - AddTelevisionSeasonToSimpleMediaCollectionHandler : MediatR.IRequestHandler< - AddTelevisionSeasonToSimpleMediaCollection, - Either> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - private readonly ITelevisionRepository _televisionRepository; - - public AddTelevisionSeasonToSimpleMediaCollectionHandler( - IMediaCollectionRepository mediaCollectionRepository, - ITelevisionRepository televisionRepository) - { - _mediaCollectionRepository = mediaCollectionRepository; - _televisionRepository = televisionRepository; - } - - public Task> Handle( - AddTelevisionSeasonToSimpleMediaCollection request, - CancellationToken cancellationToken) => - Validate(request) - .MapT(ApplyAddTelevisionSeasonRequest) - .Bind(v => v.ToEitherAsync()); - - private async Task ApplyAddTelevisionSeasonRequest(RequestParameters parameters) - { - if (parameters.Collection.TelevisionSeasons.All(s => s.Id != parameters.SeasonToAdd.Id)) - { - parameters.Collection.TelevisionSeasons.Add(parameters.SeasonToAdd); - await _mediaCollectionRepository.Update(parameters.Collection); - } - - return Unit.Default; - } - - private async Task> - Validate(AddTelevisionSeasonToSimpleMediaCollection request) => - (await SimpleMediaCollectionMustExist(request), await ValidateSeason(request)) - .Apply( - (simpleMediaCollectionToUpdate, season) => - new RequestParameters(simpleMediaCollectionToUpdate, season)); - - private Task> SimpleMediaCollectionMustExist( - AddTelevisionSeasonToSimpleMediaCollection updateSimpleMediaCollection) => - _mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId) - .Map(v => v.ToValidation("SimpleMediaCollection does not exist.")); - - private Task> ValidateSeason( - AddTelevisionSeasonToSimpleMediaCollection request) => - LoadTelevisionSeason(request) - .Map(v => v.ToValidation("TelevisionSeason does not exist")); - - private Task> LoadTelevisionSeason( - AddTelevisionSeasonToSimpleMediaCollection request) => - _televisionRepository.GetSeason(request.TelevisionSeasonId); - - private record RequestParameters(SimpleMediaCollection Collection, TelevisionSeason SeasonToAdd); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionShowToSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionShowToSimpleMediaCollection.cs deleted file mode 100644 index faf5eb3f5..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionShowToSimpleMediaCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record AddTelevisionShowToSimpleMediaCollection - (int MediaCollectionId, int TelevisionShowId) : MediatR.IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionShowToSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionShowToSimpleMediaCollectionHandler.cs deleted file mode 100644 index 77197f624..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTelevisionShowToSimpleMediaCollectionHandler.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core; -using ErsatzTV.Core.Domain; -using ErsatzTV.Core.Interfaces.Repositories; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public class - AddTelevisionShowToSimpleMediaCollectionHandler : MediatR.IRequestHandler< - AddTelevisionShowToSimpleMediaCollection, - Either> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - private readonly ITelevisionRepository _televisionRepository; - - public AddTelevisionShowToSimpleMediaCollectionHandler( - IMediaCollectionRepository mediaCollectionRepository, - ITelevisionRepository televisionRepository) - { - _mediaCollectionRepository = mediaCollectionRepository; - _televisionRepository = televisionRepository; - } - - public Task> Handle( - AddTelevisionShowToSimpleMediaCollection request, - CancellationToken cancellationToken) => - Validate(request) - .MapT(ApplyAddTelevisionShowRequest) - .Bind(v => v.ToEitherAsync()); - - private async Task ApplyAddTelevisionShowRequest(RequestParameters parameters) - { - if (parameters.Collection.TelevisionShows.All(s => s.Id != parameters.ShowToAdd.Id)) - { - parameters.Collection.TelevisionShows.Add(parameters.ShowToAdd); - await _mediaCollectionRepository.Update(parameters.Collection); - } - - return Unit.Default; - } - - private async Task> - Validate(AddTelevisionShowToSimpleMediaCollection request) => - (await SimpleMediaCollectionMustExist(request), await ValidateShow(request)) - .Apply( - (simpleMediaCollectionToUpdate, show) => - new RequestParameters(simpleMediaCollectionToUpdate, show)); - - private Task> SimpleMediaCollectionMustExist( - AddTelevisionShowToSimpleMediaCollection updateSimpleMediaCollection) => - _mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId) - .Map(v => v.ToValidation("SimpleMediaCollection does not exist.")); - - private Task> ValidateShow( - AddTelevisionShowToSimpleMediaCollection request) => - LoadTelevisionShow(request) - .Map(v => v.ToValidation("TelevisionShow does not exist")); - - private Task> LoadTelevisionShow(AddTelevisionShowToSimpleMediaCollection request) => - _televisionRepository.GetShow(request.TelevisionShowId); - - private record RequestParameters(SimpleMediaCollection Collection, TelevisionShow ShowToAdd); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/CreateCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/CreateCollection.cs new file mode 100644 index 000000000..b4450b085 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/CreateCollection.cs @@ -0,0 +1,8 @@ +using ErsatzTV.Core; +using LanguageExt; +using MediatR; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record CreateCollection(string Name) : IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/CreateSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs similarity index 66% rename from ErsatzTV.Application/MediaCollections/Commands/CreateSimpleMediaCollectionHandler.cs rename to ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs index ecc90a757..f7355bdcc 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/CreateSimpleMediaCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs @@ -12,36 +12,33 @@ using static LanguageExt.Prelude; namespace ErsatzTV.Application.MediaCollections.Commands { - public class CreateSimpleMediaCollectionHandler : IRequestHandler> + public class + CreateCollectionHandler : IRequestHandler> { private readonly IMediaCollectionRepository _mediaCollectionRepository; - public CreateSimpleMediaCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => + public CreateCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => _mediaCollectionRepository = mediaCollectionRepository; public Task> Handle( - CreateSimpleMediaCollection request, + CreateCollection request, CancellationToken cancellationToken) => Validate(request).MapT(PersistCollection).Bind(v => v.ToEitherAsync()); - private Task PersistCollection(SimpleMediaCollection c) => + private Task PersistCollection(Collection c) => _mediaCollectionRepository.Add(c).Map(ProjectToViewModel); - private Task> Validate(CreateSimpleMediaCollection request) => + private Task> Validate(CreateCollection request) => ValidateName(request).MapT( - name => new SimpleMediaCollection + name => new Collection { Name = name, - Movies = new List(), - TelevisionShows = new List(), - TelevisionEpisodes = new List(), - TelevisionSeasons = new List() + MediaItems = new List() }); - private async Task> ValidateName(CreateSimpleMediaCollection createCollection) + private async Task> ValidateName(CreateCollection createCollection) { - List allNames = await _mediaCollectionRepository.GetSimpleMediaCollections() + List allNames = await _mediaCollectionRepository.GetAll() .Map(list => list.Map(c => c.Name).ToList()); Validation result1 = createCollection.NotEmpty(c => c.Name) diff --git a/ErsatzTV.Application/MediaCollections/Commands/CreateSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/CreateSimpleMediaCollection.cs deleted file mode 100644 index 11cff638e..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/CreateSimpleMediaCollection.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; -using MediatR; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record CreateSimpleMediaCollection - (string Name) : IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/DeleteSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/DeleteCollection.cs similarity index 57% rename from ErsatzTV.Application/MediaCollections/Commands/DeleteSimpleMediaCollection.cs rename to ErsatzTV.Application/MediaCollections/Commands/DeleteCollection.cs index 0251bbcb9..eb8bcbe72 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/DeleteSimpleMediaCollection.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/DeleteCollection.cs @@ -5,5 +5,5 @@ using MediatR; namespace ErsatzTV.Application.MediaCollections.Commands { - public record DeleteSimpleMediaCollection(int SimpleMediaCollectionId) : IRequest>; + public record DeleteCollection(int CollectionId) : IRequest>; } diff --git a/ErsatzTV.Application/MediaCollections/Commands/DeleteSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/DeleteCollectionHandler.cs similarity index 50% rename from ErsatzTV.Application/MediaCollections/Commands/DeleteSimpleMediaCollectionHandler.cs rename to ErsatzTV.Application/MediaCollections/Commands/DeleteCollectionHandler.cs index 0c7b405d9..57e8b2ef4 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/DeleteSimpleMediaCollectionHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/DeleteCollectionHandler.cs @@ -7,28 +7,27 @@ using MediatR; namespace ErsatzTV.Application.MediaCollections.Commands { - public class - DeleteSimpleMediaCollectionHandler : IRequestHandler> + public class DeleteCollectionHandler : IRequestHandler> { private readonly IMediaCollectionRepository _mediaCollectionRepository; - public DeleteSimpleMediaCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => + public DeleteCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => _mediaCollectionRepository = mediaCollectionRepository; public async Task> Handle( - DeleteSimpleMediaCollection request, + DeleteCollection request, CancellationToken cancellationToken) => - (await SimpleMediaCollectionMustExist(request)) + (await CollectionMustExist(request)) .Map(DoDeletion) .ToEither(); private Task DoDeletion(int mediaCollectionId) => _mediaCollectionRepository.Delete(mediaCollectionId); - private async Task> SimpleMediaCollectionMustExist( - DeleteSimpleMediaCollection deleteMediaCollection) => - (await _mediaCollectionRepository.GetSimpleMediaCollection(deleteMediaCollection.SimpleMediaCollectionId)) + private async Task> CollectionMustExist( + DeleteCollection deleteMediaCollection) => + (await _mediaCollectionRepository.Get(deleteMediaCollection.CollectionId)) .ToValidation( - $"SimpleMediaCollection {deleteMediaCollection.SimpleMediaCollectionId} does not exist.") + $"Collection {deleteMediaCollection.CollectionId} does not exist.") .Map(c => c.Id); } } diff --git a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollection.cs new file mode 100644 index 000000000..29aaa6703 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollection.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using ErsatzTV.Core; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record RemoveItemsFromCollection(int MediaCollectionId) : MediatR.IRequest> + { + public List MediaItemIds { get; set; } = new(); + } +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs new file mode 100644 index 000000000..f4341f2bd --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs @@ -0,0 +1,51 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public class + RemoveItemsFromCollectionHandler : MediatR.IRequestHandler> + { + private readonly IMediaCollectionRepository _mediaCollectionRepository; + + public RemoveItemsFromCollectionHandler( + IMediaCollectionRepository mediaCollectionRepository) => + _mediaCollectionRepository = mediaCollectionRepository; + + public Task> Handle( + RemoveItemsFromCollection request, + CancellationToken cancellationToken) => + Validate(request) + .MapT(collection => ApplyAddTelevisionEpisodeRequest(request, collection)) + .Bind(v => v.ToEitherAsync()); + + private Task ApplyAddTelevisionEpisodeRequest( + RemoveItemsFromCollection request, + Collection collection) + { + var itemsToRemove = collection.MediaItems + .Filter(m => request.MediaItemIds.Contains(m.Id)) + .ToList(); + + itemsToRemove.ForEach(m => collection.MediaItems.Remove(m)); + + return itemsToRemove.Any() + ? _mediaCollectionRepository.Update(collection).ToUnit() + : Task.FromResult(Unit.Default); + } + + private Task> Validate( + RemoveItemsFromCollection request) => + CollectionMustExist(request); + + private Task> CollectionMustExist( + RemoveItemsFromCollection updateCollection) => + _mediaCollectionRepository.GetCollectionWithItems(updateCollection.MediaCollectionId) + .Map(v => v.ToValidation("Collection does not exist.")); + } +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromSimpleMediaCollection.cs deleted file mode 100644 index a3ea0249d..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromSimpleMediaCollection.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; -using ErsatzTV.Core; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record RemoveItemsFromSimpleMediaCollection - (int MediaCollectionId) : MediatR.IRequest> - { - public List MovieIds { get; set; } = new(); - public List TelevisionShowIds { get; set; } = new(); - public List TelevisionSeasonIds { get; set; } = new(); - public List TelevisionEpisodeIds { get; set; } = new(); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromSimpleMediaCollectionHandler.cs deleted file mode 100644 index d7342ebab..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromSimpleMediaCollectionHandler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core; -using ErsatzTV.Core.Domain; -using ErsatzTV.Core.Interfaces.Repositories; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public class - RemoveItemsFromSimpleMediaCollectionHandler : MediatR.IRequestHandler< - RemoveItemsFromSimpleMediaCollection, - Either> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - - public RemoveItemsFromSimpleMediaCollectionHandler( - IMediaCollectionRepository mediaCollectionRepository) => - _mediaCollectionRepository = mediaCollectionRepository; - - public Task> Handle( - RemoveItemsFromSimpleMediaCollection request, - CancellationToken cancellationToken) => - Validate(request) - .MapT(collection => ApplyAddTelevisionEpisodeRequest(request, collection)) - .Bind(v => v.ToEitherAsync()); - - private Task ApplyAddTelevisionEpisodeRequest( - RemoveItemsFromSimpleMediaCollection request, - SimpleMediaCollection collection) - { - var moviesToRemove = collection.Movies - .Filter(m => request.MovieIds.Contains(m.Id)) - .ToList(); - - moviesToRemove.ForEach(m => collection.Movies.Remove(m)); - - var showsToRemove = collection.TelevisionShows - .Filter(s => request.TelevisionShowIds.Contains(s.Id)) - .ToList(); - - showsToRemove.ForEach(s => collection.TelevisionShows.Remove(s)); - - var seasonsToRemove = collection.TelevisionSeasons - .Filter(s => request.TelevisionSeasonIds.Contains(s.Id)) - .ToList(); - - seasonsToRemove.ForEach(s => collection.TelevisionSeasons.Remove(s)); - - var episodesToRemove = collection.TelevisionEpisodes - .Filter(e => request.TelevisionEpisodeIds.Contains(e.Id)) - .ToList(); - - episodesToRemove.ForEach(e => collection.TelevisionEpisodes.Remove(e)); - - if (moviesToRemove.Any() || showsToRemove.Any() || seasonsToRemove.Any() || episodesToRemove.Any()) - { - return _mediaCollectionRepository.Update(collection).ToUnit(); - } - - return Task.FromResult(Unit.Default); - } - - private Task> Validate( - RemoveItemsFromSimpleMediaCollection request) => - SimpleMediaCollectionMustExist(request); - - private Task> SimpleMediaCollectionMustExist( - RemoveItemsFromSimpleMediaCollection updateSimpleMediaCollection) => - _mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId) - .Map(v => v.ToValidation("SimpleMediaCollection does not exist.")); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs new file mode 100644 index 000000000..9a2e8c58a --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollection.cs @@ -0,0 +1,8 @@ +using ErsatzTV.Core; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public record UpdateCollection + (int CollectionId, string Name) : MediatR.IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs new file mode 100644 index 000000000..063bc8c00 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Commands/UpdateCollectionHandler.cs @@ -0,0 +1,45 @@ +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; + +namespace ErsatzTV.Application.MediaCollections.Commands +{ + public class UpdateCollectionHandler : MediatR.IRequestHandler> + { + private readonly IMediaCollectionRepository _mediaCollectionRepository; + + public UpdateCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => + _mediaCollectionRepository = mediaCollectionRepository; + + public Task> Handle( + UpdateCollection request, + CancellationToken cancellationToken) => + Validate(request) + .MapT(c => ApplyUpdateRequest(c, request)) + .Bind(v => v.ToEitherAsync()); + + private async Task ApplyUpdateRequest(Collection c, UpdateCollection update) + { + c.Name = update.Name; + await _mediaCollectionRepository.Update(c); + return Unit.Default; + } + + private async Task> + Validate(UpdateCollection request) => + (await CollectionMustExist(request), ValidateName(request)) + .Apply((collectionToUpdate, _) => collectionToUpdate); + + private Task> CollectionMustExist( + UpdateCollection updateCollection) => + _mediaCollectionRepository.Get(updateCollection.CollectionId) + .Map(v => v.ToValidation("Collection does not exist.")); + + private Validation ValidateName(UpdateCollection updateSimpleMediaCollection) => + updateSimpleMediaCollection.NotEmpty(c => c.Name) + .Bind(_ => updateSimpleMediaCollection.NotLongerThan(50)(c => c.Name)); + } +} diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateSimpleMediaCollection.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateSimpleMediaCollection.cs deleted file mode 100644 index 55ceb9f41..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateSimpleMediaCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ErsatzTV.Core; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public record UpdateSimpleMediaCollection - (int MediaCollectionId, string Name) : MediatR.IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Commands/UpdateSimpleMediaCollectionHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/UpdateSimpleMediaCollectionHandler.cs deleted file mode 100644 index cab486acc..000000000 --- a/ErsatzTV.Application/MediaCollections/Commands/UpdateSimpleMediaCollectionHandler.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core; -using ErsatzTV.Core.Domain; -using ErsatzTV.Core.Interfaces.Repositories; -using LanguageExt; - -namespace ErsatzTV.Application.MediaCollections.Commands -{ - public class - UpdateSimpleMediaCollectionHandler : MediatR.IRequestHandler> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - - public UpdateSimpleMediaCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => - _mediaCollectionRepository = mediaCollectionRepository; - - public Task> Handle( - UpdateSimpleMediaCollection request, - CancellationToken cancellationToken) => - Validate(request) - .MapT(c => ApplyUpdateRequest(c, request)) - .Bind(v => v.ToEitherAsync()); - - private async Task ApplyUpdateRequest(SimpleMediaCollection c, UpdateSimpleMediaCollection update) - { - c.Name = update.Name; - await _mediaCollectionRepository.Update(c); - return Unit.Default; - } - - private async Task> - Validate(UpdateSimpleMediaCollection request) => - (await SimpleMediaCollectionMustExist(request), ValidateName(request)) - .Apply((simpleMediaCollectionToUpdate, _) => simpleMediaCollectionToUpdate); - - private Task> SimpleMediaCollectionMustExist( - UpdateSimpleMediaCollection updateSimpleMediaCollection) => - _mediaCollectionRepository.GetSimpleMediaCollection(updateSimpleMediaCollection.MediaCollectionId) - .Map(v => v.ToValidation("SimpleMediaCollection does not exist.")); - - private Validation ValidateName(UpdateSimpleMediaCollection updateSimpleMediaCollection) => - updateSimpleMediaCollection.NotEmpty(c => c.Name) - .Bind(_ => updateSimpleMediaCollection.NotLongerThan(50)(c => c.Name)); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Mapper.cs b/ErsatzTV.Application/MediaCollections/Mapper.cs index 592174056..9144d1290 100644 --- a/ErsatzTV.Application/MediaCollections/Mapper.cs +++ b/ErsatzTV.Application/MediaCollections/Mapper.cs @@ -4,7 +4,7 @@ namespace ErsatzTV.Application.MediaCollections { internal static class Mapper { - internal static MediaCollectionViewModel ProjectToViewModel(MediaCollection mediaCollection) => - new(mediaCollection.Id, mediaCollection.Name); + internal static MediaCollectionViewModel ProjectToViewModel(Collection collection) => + new(collection.Id, collection.Name); } } diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetAllMediaCollections.cs b/ErsatzTV.Application/MediaCollections/Queries/GetAllCollections.cs similarity index 57% rename from ErsatzTV.Application/MediaCollections/Queries/GetAllMediaCollections.cs rename to ErsatzTV.Application/MediaCollections/Queries/GetAllCollections.cs index 678d5a80a..92cbd8427 100644 --- a/ErsatzTV.Application/MediaCollections/Queries/GetAllMediaCollections.cs +++ b/ErsatzTV.Application/MediaCollections/Queries/GetAllCollections.cs @@ -3,5 +3,5 @@ using MediatR; namespace ErsatzTV.Application.MediaCollections.Queries { - public record GetAllMediaCollections : IRequest>; + public record GetAllCollections : IRequest>; } diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetAllMediaCollectionsHandler.cs b/ErsatzTV.Application/MediaCollections/Queries/GetAllCollectionsHandler.cs similarity index 71% rename from ErsatzTV.Application/MediaCollections/Queries/GetAllMediaCollectionsHandler.cs rename to ErsatzTV.Application/MediaCollections/Queries/GetAllCollectionsHandler.cs index 5e2a68986..0efde96ee 100644 --- a/ErsatzTV.Application/MediaCollections/Queries/GetAllMediaCollectionsHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Queries/GetAllCollectionsHandler.cs @@ -9,15 +9,15 @@ using static ErsatzTV.Application.MediaCollections.Mapper; namespace ErsatzTV.Application.MediaCollections.Queries { - public class GetAllMediaCollectionsHandler : IRequestHandler> + public class GetAllCollectionsHandler : IRequestHandler> { private readonly IMediaCollectionRepository _mediaCollectionRepository; - public GetAllMediaCollectionsHandler(IMediaCollectionRepository mediaCollectionRepository) => + public GetAllCollectionsHandler(IMediaCollectionRepository mediaCollectionRepository) => _mediaCollectionRepository = mediaCollectionRepository; public Task> Handle( - GetAllMediaCollections request, + GetAllCollections request, CancellationToken cancellationToken) => _mediaCollectionRepository.GetAll().Map(list => list.Map(ProjectToViewModel).ToList()); } diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetAllSimpleMediaCollections.cs b/ErsatzTV.Application/MediaCollections/Queries/GetAllSimpleMediaCollections.cs deleted file mode 100644 index e8a9a87ff..000000000 --- a/ErsatzTV.Application/MediaCollections/Queries/GetAllSimpleMediaCollections.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Collections.Generic; -using MediatR; - -namespace ErsatzTV.Application.MediaCollections.Queries -{ - public record GetAllSimpleMediaCollections : IRequest>; -} diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetAllSimpleMediaCollectionsHandler.cs b/ErsatzTV.Application/MediaCollections/Queries/GetAllSimpleMediaCollectionsHandler.cs deleted file mode 100644 index 40b85740a..000000000 --- a/ErsatzTV.Application/MediaCollections/Queries/GetAllSimpleMediaCollectionsHandler.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using ErsatzTV.Core.Interfaces.Repositories; -using MediatR; -using static ErsatzTV.Application.MediaCollections.Mapper; - -namespace ErsatzTV.Application.MediaCollections.Queries -{ - public class - GetAllSimpleMediaCollectionsHandler : IRequestHandler> - { - private readonly IMediaCollectionRepository _mediaCollectionRepository; - - public GetAllSimpleMediaCollectionsHandler(IMediaCollectionRepository mediaCollectionRepository) => - _mediaCollectionRepository = mediaCollectionRepository; - - public async Task> Handle( - GetAllSimpleMediaCollections request, - CancellationToken cancellationToken) => - (await _mediaCollectionRepository.GetSimpleMediaCollections()).Map(ProjectToViewModel).ToList(); - } -} diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetCollectionById.cs b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionById.cs new file mode 100644 index 000000000..8d988eecd --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionById.cs @@ -0,0 +1,7 @@ +using LanguageExt; +using MediatR; + +namespace ErsatzTV.Application.MediaCollections.Queries +{ + public record GetCollectionById(int Id) : IRequest>; +} diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionByIdHandler.cs b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionByIdHandler.cs similarity index 66% rename from ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionByIdHandler.cs rename to ErsatzTV.Application/MediaCollections/Queries/GetCollectionByIdHandler.cs index a3a1a070a..e6bbb55b0 100644 --- a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionByIdHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionByIdHandler.cs @@ -8,18 +8,18 @@ using static ErsatzTV.Application.MediaCollections.Mapper; namespace ErsatzTV.Application.MediaCollections.Queries { public class - GetSimpleMediaCollectionByIdHandler : IRequestHandler> { private readonly IMediaCollectionRepository _mediaCollectionRepository; - public GetSimpleMediaCollectionByIdHandler(IMediaCollectionRepository mediaCollectionRepository) => + public GetCollectionByIdHandler(IMediaCollectionRepository mediaCollectionRepository) => _mediaCollectionRepository = mediaCollectionRepository; public Task> Handle( - GetSimpleMediaCollectionById request, + GetCollectionById request, CancellationToken cancellationToken) => - _mediaCollectionRepository.GetSimpleMediaCollection(request.Id) + _mediaCollectionRepository.Get(request.Id) .MapT(ProjectToViewModel); } } diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionItems.cs b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionItems.cs similarity index 61% rename from ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionItems.cs rename to ErsatzTV.Application/MediaCollections/Queries/GetCollectionItems.cs index ed0f21f74..35318b83d 100644 --- a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionItems.cs +++ b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionItems.cs @@ -5,5 +5,5 @@ using MediatR; namespace ErsatzTV.Application.MediaCollections.Queries { - public record GetSimpleMediaCollectionItems(int Id) : IRequest>>; + public record GetCollectionItems(int Id) : IRequest>>; } diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionItemsHandler.cs b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionItemsHandler.cs similarity index 67% rename from ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionItemsHandler.cs rename to ErsatzTV.Application/MediaCollections/Queries/GetCollectionItemsHandler.cs index 92e918fa6..11740f0cc 100644 --- a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionItemsHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Queries/GetCollectionItemsHandler.cs @@ -9,18 +9,18 @@ using static ErsatzTV.Application.MediaItems.Mapper; namespace ErsatzTV.Application.MediaCollections.Queries { - public class GetSimpleMediaCollectionItemsHandler : IRequestHandler>> { private readonly IMediaCollectionRepository _mediaCollectionRepository; - public GetSimpleMediaCollectionItemsHandler(IMediaCollectionRepository mediaCollectionRepository) => + public GetCollectionItemsHandler(IMediaCollectionRepository mediaCollectionRepository) => _mediaCollectionRepository = mediaCollectionRepository; public Task>> Handle( - GetSimpleMediaCollectionItems request, + GetCollectionItems request, CancellationToken cancellationToken) => - _mediaCollectionRepository.GetSimpleMediaCollectionItems(request.Id) + _mediaCollectionRepository.GetItems(request.Id) .MapT(mediaItems => mediaItems.Map(ProjectToViewModel)); } } diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionById.cs b/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionById.cs deleted file mode 100644 index 937e5e5c4..000000000 --- a/ErsatzTV.Application/MediaCollections/Queries/GetSimpleMediaCollectionById.cs +++ /dev/null @@ -1,7 +0,0 @@ -using LanguageExt; -using MediatR; - -namespace ErsatzTV.Application.MediaCollections.Queries -{ - public record GetSimpleMediaCollectionById(int Id) : IRequest>; -} diff --git a/ErsatzTV.Application/MediaItems/Mapper.cs b/ErsatzTV.Application/MediaItems/Mapper.cs index c68596f2c..1fe79a13b 100644 --- a/ErsatzTV.Application/MediaItems/Mapper.cs +++ b/ErsatzTV.Application/MediaItems/Mapper.cs @@ -15,12 +15,12 @@ namespace ErsatzTV.Application.MediaItems internal static MediaItemSearchResultViewModel ProjectToSearchViewModel(MediaItem mediaItem) => mediaItem switch { - TelevisionEpisodeMediaItem e => ProjectToSearchViewModel(e), + Episode e => ProjectToSearchViewModel(e), Movie m => ProjectToSearchViewModel(m), _ => throw new ArgumentOutOfRangeException() }; - private static MediaItemSearchResultViewModel ProjectToSearchViewModel(TelevisionEpisodeMediaItem mediaItem) => + private static MediaItemSearchResultViewModel ProjectToSearchViewModel(Episode mediaItem) => new( mediaItem.Id, GetLibraryName(mediaItem), @@ -40,9 +40,9 @@ namespace ErsatzTV.Application.MediaItems private static string GetDisplayTitle(MediaItem mediaItem) => mediaItem switch { - TelevisionEpisodeMediaItem e => e.Metadata != null - ? $"{e.Metadata.Title} - s{e.Metadata.Season:00}e{e.Metadata.Episode:00}" - : Path.GetFileName(e.Path), + Episode e => e.EpisodeMetadata.HeadOrNone() + .Map(em => $"{em.Title} - s{e.Season.SeasonNumber:00}e{e.EpisodeNumber:00}") + .IfNone(Path.GetFileName(e.Path)), Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Title).IfNone(Path.GetFileName(m.Path)), _ => string.Empty }; diff --git a/ErsatzTV.Application/Playouts/Mapper.cs b/ErsatzTV.Application/Playouts/Mapper.cs index c2bcdf677..01c2452da 100644 --- a/ErsatzTV.Application/Playouts/Mapper.cs +++ b/ErsatzTV.Application/Playouts/Mapper.cs @@ -24,9 +24,9 @@ namespace ErsatzTV.Application.Playouts private static string GetDisplayTitle(MediaItem mediaItem) => mediaItem switch { - TelevisionEpisodeMediaItem e => e.Metadata != null - ? $"{e.Metadata.Title} - s{e.Metadata.Season:00}e{e.Metadata.Episode:00}" - : Path.GetFileName(e.Path), + Episode e => e.EpisodeMetadata.HeadOrNone() + .Map(em => $"{em.Title} - s{e.Season.SeasonNumber:00}e{e.EpisodeNumber:00}") + .IfNone(Path.GetFileName(e.Path)), Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Title).IfNone(Path.GetFileName(m.Path)), _ => string.Empty }; diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs b/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs index bb7265c47..9eaf9086e 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs @@ -12,9 +12,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands TimeSpan? StartTime, PlayoutMode PlayoutMode, ProgramScheduleItemCollectionType CollectionType, - int? MediaCollectionId, - int? TelevisionShowId, - int? TelevisionSeasonId, + int? CollectionId, + int? MediaItemId, int? MultipleCount, TimeSpan? PlayoutDuration, bool? OfflineTail) : IRequest>, IProgramScheduleItemRequest; diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs b/ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs index be9def8d7..f7c1c232d 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs @@ -7,9 +7,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands { TimeSpan? StartTime { get; } ProgramScheduleItemCollectionType CollectionType { get; } - int? MediaCollectionId { get; } - int? TelevisionShowId { get; } - int? TelevisionSeasonId { get; } + int? CollectionId { get; } + int? MediaItemId { get; } PlayoutMode PlayoutMode { get; } int? MultipleCount { get; } TimeSpan? PlayoutDuration { get; } diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs b/ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs index f205279d8..a6788ca1f 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs @@ -60,23 +60,23 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands switch (item.CollectionType) { case ProgramScheduleItemCollectionType.Collection: - if (item.MediaCollectionId is null) + if (item.CollectionId is null) { - return BaseError.New("[MediaCollection] is required for collection type 'Collection'"); + return BaseError.New("[Collection] is required for collection type 'Collection'"); } break; case ProgramScheduleItemCollectionType.TelevisionShow: - if (item.TelevisionShowId is null) + if (item.MediaItemId is null) { - return BaseError.New("[TelevisionShow] is required for collection type 'TelevisionShow'"); + return BaseError.New("[MediaItem] is required for collection type 'TelevisionShow'"); } break; case ProgramScheduleItemCollectionType.TelevisionSeason: - if (item.TelevisionSeasonId is null) + if (item.MediaItemId is null) { - return BaseError.New("[TelevisionSeason] is required for collection type 'TelevisionSeason'"); + return BaseError.New("[MediaItem] is required for collection type 'TelevisionSeason'"); } break; @@ -99,9 +99,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands Index = index, StartTime = item.StartTime, CollectionType = item.CollectionType, - MediaCollectionId = item.MediaCollectionId, - TelevisionShowId = item.TelevisionShowId, - TelevisionSeasonId = item.TelevisionSeasonId + CollectionId = item.CollectionId, + MediaItemId = item.MediaItemId }, PlayoutMode.One => new ProgramScheduleItemOne { @@ -109,9 +108,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands Index = index, StartTime = item.StartTime, CollectionType = item.CollectionType, - MediaCollectionId = item.MediaCollectionId, - TelevisionShowId = item.TelevisionShowId, - TelevisionSeasonId = item.TelevisionSeasonId + CollectionId = item.CollectionId, + MediaItemId = item.MediaItemId }, PlayoutMode.Multiple => new ProgramScheduleItemMultiple { @@ -119,9 +117,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands Index = index, StartTime = item.StartTime, CollectionType = item.CollectionType, - MediaCollectionId = item.MediaCollectionId, - TelevisionShowId = item.TelevisionShowId, - TelevisionSeasonId = item.TelevisionSeasonId, + CollectionId = item.CollectionId, + MediaItemId = item.MediaItemId, Count = item.MultipleCount.GetValueOrDefault() }, PlayoutMode.Duration => new ProgramScheduleItemDuration @@ -130,9 +127,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands Index = index, StartTime = item.StartTime, CollectionType = item.CollectionType, - MediaCollectionId = item.MediaCollectionId, - TelevisionShowId = item.TelevisionShowId, - TelevisionSeasonId = item.TelevisionSeasonId, + CollectionId = item.CollectionId, + MediaItemId = item.MediaItemId, PlayoutDuration = item.PlayoutDuration.GetValueOrDefault(), OfflineTail = item.OfflineTail.GetValueOrDefault() }, diff --git a/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs b/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs index 50c7a18e2..2e9a37c4a 100644 --- a/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs +++ b/ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs @@ -13,9 +13,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands TimeSpan? StartTime, PlayoutMode PlayoutMode, ProgramScheduleItemCollectionType CollectionType, - int? MediaCollectionId, - int? TelevisionShowId, - int? TelevisionSeasonId, + int? CollectionId, + int? MediaItemId, int? MultipleCount, TimeSpan? PlayoutDuration, bool? OfflineTail) : IProgramScheduleItemRequest; diff --git a/ErsatzTV.Application/ProgramSchedules/Mapper.cs b/ErsatzTV.Application/ProgramSchedules/Mapper.cs index 9d8ea1e68..5149d46fb 100644 --- a/ErsatzTV.Application/ProgramSchedules/Mapper.cs +++ b/ErsatzTV.Application/ProgramSchedules/Mapper.cs @@ -18,14 +18,14 @@ namespace ErsatzTV.Application.ProgramSchedules duration.StartType, duration.StartTime, duration.CollectionType, - duration.MediaCollection != null - ? MediaCollections.Mapper.ProjectToViewModel(duration.MediaCollection) + duration.Collection != null + ? MediaCollections.Mapper.ProjectToViewModel(duration.Collection) : null, - duration.TelevisionShow != null - ? Television.Mapper.ProjectToViewModel(duration.TelevisionShow) + duration.MediaItem is Show show + ? Television.Mapper.ProjectToViewModel(show) : null, - duration.TelevisionSeason != null - ? Television.Mapper.ProjectToViewModel(duration.TelevisionSeason) + duration.MediaItem is Season season + ? Television.Mapper.ProjectToViewModel(season) : null, duration.PlayoutDuration, duration.OfflineTail), @@ -36,14 +36,14 @@ namespace ErsatzTV.Application.ProgramSchedules flood.StartType, flood.StartTime, flood.CollectionType, - flood.MediaCollection != null - ? MediaCollections.Mapper.ProjectToViewModel(flood.MediaCollection) + flood.Collection != null + ? MediaCollections.Mapper.ProjectToViewModel(flood.Collection) : null, - flood.TelevisionShow != null - ? Television.Mapper.ProjectToViewModel(flood.TelevisionShow) + flood.MediaItem is Show show + ? Television.Mapper.ProjectToViewModel(show) : null, - flood.TelevisionSeason != null - ? Television.Mapper.ProjectToViewModel(flood.TelevisionSeason) + flood.MediaItem is Season season + ? Television.Mapper.ProjectToViewModel(season) : null), ProgramScheduleItemMultiple multiple => new ProgramScheduleItemMultipleViewModel( @@ -52,14 +52,14 @@ namespace ErsatzTV.Application.ProgramSchedules multiple.StartType, multiple.StartTime, multiple.CollectionType, - multiple.MediaCollection != null - ? MediaCollections.Mapper.ProjectToViewModel(multiple.MediaCollection) + multiple.Collection != null + ? MediaCollections.Mapper.ProjectToViewModel(multiple.Collection) : null, - multiple.TelevisionShow != null - ? Television.Mapper.ProjectToViewModel(multiple.TelevisionShow) + multiple.MediaItem is Show show + ? Television.Mapper.ProjectToViewModel(show) : null, - multiple.TelevisionSeason != null - ? Television.Mapper.ProjectToViewModel(multiple.TelevisionSeason) + multiple.MediaItem is Season season + ? Television.Mapper.ProjectToViewModel(season) : null, multiple.Count), ProgramScheduleItemOne one => @@ -69,12 +69,14 @@ namespace ErsatzTV.Application.ProgramSchedules one.StartType, one.StartTime, one.CollectionType, - one.MediaCollection != null - ? MediaCollections.Mapper.ProjectToViewModel(one.MediaCollection) + one.Collection != null + ? MediaCollections.Mapper.ProjectToViewModel(one.Collection) : null, - one.TelevisionShow != null ? Television.Mapper.ProjectToViewModel(one.TelevisionShow) : null, - one.TelevisionSeason != null - ? Television.Mapper.ProjectToViewModel(one.TelevisionSeason) + one.MediaItem is Show show + ? Television.Mapper.ProjectToViewModel(show) + : null, + one.MediaItem is Season season + ? Television.Mapper.ProjectToViewModel(season) : null), _ => throw new NotSupportedException( $"Unsupported program schedule item type {programScheduleItem.GetType().Name}") diff --git a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs index 6071ffc9b..67caeaf2e 100644 --- a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs +++ b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs @@ -13,7 +13,7 @@ namespace ErsatzTV.Application.ProgramSchedules StartType startType, TimeSpan? startTime, ProgramScheduleItemCollectionType collectionType, - MediaCollectionViewModel mediaCollection, + MediaCollectionViewModel collection, TelevisionShowViewModel televisionShow, TelevisionSeasonViewModel televisionSeason, TimeSpan playoutDuration, @@ -24,7 +24,7 @@ namespace ErsatzTV.Application.ProgramSchedules startTime, PlayoutMode.Duration, collectionType, - mediaCollection, + collection, televisionShow, televisionSeason) { diff --git a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs index e1f13b322..f62c63f71 100644 --- a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs +++ b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs @@ -13,7 +13,7 @@ namespace ErsatzTV.Application.ProgramSchedules StartType startType, TimeSpan? startTime, ProgramScheduleItemCollectionType collectionType, - MediaCollectionViewModel mediaCollection, + MediaCollectionViewModel collection, TelevisionShowViewModel televisionShow, TelevisionSeasonViewModel televisionSeason) : base( id, @@ -22,7 +22,7 @@ namespace ErsatzTV.Application.ProgramSchedules startTime, PlayoutMode.Flood, collectionType, - mediaCollection, + collection, televisionShow, televisionSeason) { diff --git a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs index 4106836f6..b8bc7a4a3 100644 --- a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs +++ b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs @@ -13,7 +13,7 @@ namespace ErsatzTV.Application.ProgramSchedules StartType startType, TimeSpan? startTime, ProgramScheduleItemCollectionType collectionType, - MediaCollectionViewModel mediaCollection, + MediaCollectionViewModel collection, TelevisionShowViewModel televisionShow, TelevisionSeasonViewModel televisionSeason, int count) : base( @@ -23,7 +23,7 @@ namespace ErsatzTV.Application.ProgramSchedules startTime, PlayoutMode.Multiple, collectionType, - mediaCollection, + collection, televisionShow, televisionSeason) => Count = count; diff --git a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs index e77e55667..a221c7577 100644 --- a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs +++ b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs @@ -13,7 +13,7 @@ namespace ErsatzTV.Application.ProgramSchedules StartType startType, TimeSpan? startTime, ProgramScheduleItemCollectionType collectionType, - MediaCollectionViewModel mediaCollection, + MediaCollectionViewModel collection, TelevisionShowViewModel televisionShow, TelevisionSeasonViewModel televisionSeason) : base( id, @@ -22,7 +22,7 @@ namespace ErsatzTV.Application.ProgramSchedules startTime, PlayoutMode.One, collectionType, - mediaCollection, + collection, televisionShow, televisionSeason) { diff --git a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs index dc7392ab7..2dc6bf34a 100644 --- a/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs +++ b/ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs @@ -12,13 +12,13 @@ namespace ErsatzTV.Application.ProgramSchedules TimeSpan? StartTime, PlayoutMode PlayoutMode, ProgramScheduleItemCollectionType CollectionType, - MediaCollectionViewModel MediaCollection, + MediaCollectionViewModel Collection, TelevisionShowViewModel TelevisionShow, TelevisionSeasonViewModel TelevisionSeason) { public string Name => CollectionType switch { - ProgramScheduleItemCollectionType.Collection => MediaCollection?.Name, + ProgramScheduleItemCollectionType.Collection => Collection?.Name, ProgramScheduleItemCollectionType.TelevisionShow => $"{TelevisionShow?.Title} ({TelevisionShow?.Year})", ProgramScheduleItemCollectionType.TelevisionSeason => $"{TelevisionSeason?.Title} ({TelevisionSeason?.Plot})", diff --git a/ErsatzTV.Application/Television/Mapper.cs b/ErsatzTV.Application/Television/Mapper.cs index 983e973d2..df4fcca53 100644 --- a/ErsatzTV.Application/Television/Mapper.cs +++ b/ErsatzTV.Application/Television/Mapper.cs @@ -4,25 +4,30 @@ namespace ErsatzTV.Application.Television { internal static class Mapper { - internal static TelevisionShowViewModel ProjectToViewModel(TelevisionShow show) => - new(show.Id, show.Metadata.Title, show.Metadata.Year?.ToString(), show.Metadata.Plot, show.Poster); + internal static TelevisionShowViewModel ProjectToViewModel(Show show) => + new( + show.Id, + show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), + show.ShowMetadata.HeadOrNone().Map(m => m.ReleaseDate?.Year.ToString()).IfNone(string.Empty), + show.ShowMetadata.HeadOrNone().Map(m => m.Plot).IfNone(string.Empty), + null); // TODO: artwork - internal static TelevisionSeasonViewModel ProjectToViewModel(TelevisionSeason season) => + internal static TelevisionSeasonViewModel ProjectToViewModel(Season season) => new( season.Id, - season.TelevisionShowId, - season.TelevisionShow.Metadata.Title, - season.TelevisionShow.Metadata.Year?.ToString(), - season.Number == 0 ? "Specials" : $"Season {season.Number}", - season.Poster); + season.ShowId, + season.Show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), + season.Show.ShowMetadata.HeadOrNone().Map(m => m.ReleaseDate?.Year.ToString()).IfNone(string.Empty), + season.SeasonNumber == 0 ? "Specials" : $"Season {season.SeasonNumber}", + null); // TODO: artwork - internal static TelevisionEpisodeViewModel ProjectToViewModel(TelevisionEpisodeMediaItem episode) => + internal static TelevisionEpisodeViewModel ProjectToViewModel(Episode episode) => new( - episode.Season.TelevisionShowId, + episode.Season.ShowId, episode.SeasonId, - episode.Metadata.Episode, - episode.Metadata.Title, - episode.Metadata.Plot, - episode.Poster); + episode.EpisodeNumber, + episode.EpisodeMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), + episode.EpisodeMetadata.HeadOrNone().Map(m => m.Plot).IfNone(string.Empty), + null); // TODO: artwork } } diff --git a/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs b/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs index eb788716c..e344b8cdd 100644 --- a/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs +++ b/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs @@ -11,34 +11,25 @@ namespace ErsatzTV.Core.Tests.Fakes { public class FakeMediaCollectionRepository : IMediaCollectionRepository { - private readonly Map> _data; + private readonly Map> _data; - public FakeMediaCollectionRepository(Map> data) => _data = data; + public FakeMediaCollectionRepository(Map> data) => _data = data; - public Task Add(SimpleMediaCollection collection) => throw new NotSupportedException(); + public Task Add(Collection collection) => throw new NotSupportedException(); - public Task> Get(int id) => throw new NotSupportedException(); + public Task> Get(int id) => throw new NotSupportedException(); - public Task> GetSimpleMediaCollection(int id) => - throw new NotSupportedException(); + public Task> GetCollectionWithItems(int id) => throw new NotSupportedException(); - public Task> GetSimpleMediaCollectionWithItems(int id) => - throw new NotSupportedException(); + public Task> GetCollectionWithItemsUntracked(int id) => throw new NotSupportedException(); - public Task> GetSimpleMediaCollectionWithItemsUntracked(int id) => - throw new NotSupportedException(); + public Task> GetAll() => throw new NotSupportedException(); - public Task> GetSimpleMediaCollections() => throw new NotSupportedException(); + public Task>> GetItems(int id) => Some(_data[id].ToList()).AsTask(); + public Task>> GetSimpleMediaCollectionItems(int id) => throw new NotSupportedException(); - public Task> GetAll() => throw new NotSupportedException(); + public Task Update(Collection collection) => throw new NotSupportedException(); - public Task>> GetItems(int id) => Some(_data[id].OfType().ToList()).AsTask(); - - public Task>> GetSimpleMediaCollectionItems(int id) => - throw new NotSupportedException(); - - public Task Update(SimpleMediaCollection collection) => throw new NotSupportedException(); - - public Task Delete(int mediaCollectionId) => throw new NotSupportedException(); + public Task Delete(int collectionId) => throw new NotSupportedException(); } } diff --git a/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs b/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs index 70eb00d8a..ddc79e45c 100644 --- a/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs +++ b/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs @@ -9,66 +9,54 @@ namespace ErsatzTV.Core.Tests.Fakes { public class FakeTelevisionRepository : ITelevisionRepository { - public Task Update(TelevisionShow show) => throw new NotSupportedException(); + public Task Update(Show show) => throw new NotSupportedException(); - public Task Update(TelevisionSeason season) => throw new NotSupportedException(); + public Task Update(Season season) => throw new NotSupportedException(); - public Task Update(TelevisionEpisodeMediaItem episode) => throw new NotSupportedException(); + public Task Update(Episode episode) => throw new NotSupportedException(); - public Task> GetAllShows() => throw new NotSupportedException(); + public Task> GetAllShows() => throw new NotSupportedException(); - public Task> GetShow(int televisionShowId) => throw new NotSupportedException(); + public Task> GetShow(int televisionShowId) => throw new NotSupportedException(); public Task GetShowCount() => throw new NotSupportedException(); - public Task> GetPagedShows(int pageNumber, int pageSize) => + public Task> GetPagedShows(int pageNumber, int pageSize) => throw new NotSupportedException(); - public Task> GetShowItems(int televisionShowId) => - throw new NotSupportedException(); + public Task> GetShowItems(int televisionShowId) => throw new NotSupportedException(); - public Task> GetAllSeasons() => throw new NotSupportedException(); + public Task> GetAllSeasons() => throw new NotSupportedException(); - public Task> GetSeason(int televisionSeasonId) => throw new NotSupportedException(); + public Task> GetSeason(int televisionSeasonId) => throw new NotSupportedException(); public Task GetSeasonCount(int televisionShowId) => throw new NotSupportedException(); - public Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize) => + public Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize) => throw new NotSupportedException(); - public Task> GetSeasonItems(int televisionSeasonId) => - throw new NotSupportedException(); + public Task> GetSeasonItems(int televisionSeasonId) => throw new NotSupportedException(); - public Task> GetEpisode(int televisionEpisodeId) => - throw new NotSupportedException(); + public Task> GetEpisode(int televisionEpisodeId) => throw new NotSupportedException(); public Task GetEpisodeCount(int televisionSeasonId) => throw new NotSupportedException(); - public Task> GetPagedEpisodes( - int televisionSeasonId, - int pageNumber, - int pageSize) => throw new NotSupportedException(); - - public Task> GetShowByPath(int mediaSourceId, string path) => + public Task> GetPagedEpisodes(int televisionSeasonId, int pageNumber, int pageSize) => throw new NotSupportedException(); - public Task> GetShowByMetadata(TelevisionShowMetadata metadata) => - throw new NotSupportedException(); + public Task> GetShowByPath(int mediaSourceId, string path) => throw new NotSupportedException(); - public Task> AddShow( - int localMediaSourceId, - string showFolder, - TelevisionShowMetadata metadata) => throw new NotSupportedException(); + public Task> GetShowByMetadata(ShowMetadata metadata) => throw new NotSupportedException(); - public Task> GetOrAddSeason( - TelevisionShow show, - string path, - int seasonNumber) => throw new NotSupportedException(); + public Task> + AddShow(int localMediaSourceId, string showFolder, ShowMetadata metadata) => + throw new NotSupportedException(); + + public Task> GetOrAddSeason(Show show, string path, int seasonNumber) => + throw new NotSupportedException(); - public Task> GetOrAddEpisode( - TelevisionSeason season, - LibraryPath libraryPath, - string path) => throw new NotSupportedException(); + public Task> GetOrAddEpisode(Season season, LibraryPath libraryPath, string path) => + throw new NotSupportedException(); public Task DeleteMissingSources(int localMediaSourceId, List allFolders) => throw new NotSupportedException(); diff --git a/ErsatzTV.Core.Tests/Metadata/FallbackMetadataProviderTests.cs b/ErsatzTV.Core.Tests/Metadata/FallbackMetadataProviderTests.cs index 6136db275..937357aa5 100644 --- a/ErsatzTV.Core.Tests/Metadata/FallbackMetadataProviderTests.cs +++ b/ErsatzTV.Core.Tests/Metadata/FallbackMetadataProviderTests.cs @@ -37,13 +37,14 @@ namespace ErsatzTV.Core.Tests.Metadata 2)] public void GetFallbackMetadata_ShouldHandleVariousFormats(string path, string title, int season, int episode) { - TelevisionEpisodeMetadata metadata = FallbackMetadataProvider.GetFallbackMetadata( - new TelevisionEpisodeMediaItem + EpisodeMetadata metadata = FallbackMetadataProvider.GetFallbackMetadata( + new Episode { Path = path, LibraryPath = new LibraryPath() }); metadata.Title.Should().Be(title); - metadata.Season.Should().Be(season); - metadata.Episode.Should().Be(episode); + // metadata.Season.Should().Be(season); + // metadata.Episode.Should().Be(episode); + // TODO: how do we test season and episode number? } } } diff --git a/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs b/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs index c0022aa6a..06d603043 100644 --- a/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs @@ -16,7 +16,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void Episodes_Should_Sort_By_Aired() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); + var state = new CollectionEnumeratorState(); var chronologicalContent = new ChronologicalMediaCollectionEnumerator(contents, state); @@ -32,7 +32,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void State_Index_Should_Increment() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); + var state = new CollectionEnumeratorState(); var chronologicalContent = new ChronologicalMediaCollectionEnumerator(contents, state); @@ -47,7 +47,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void State_Should_Impact_Iterator_Start() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState { Index = 5 }; + var state = new CollectionEnumeratorState { Index = 5 }; var chronologicalContent = new ChronologicalMediaCollectionEnumerator(contents, state); @@ -62,12 +62,15 @@ namespace ErsatzTV.Core.Tests.Scheduling private static List Episodes(int count) => Range(1, count).Map( - i => (MediaItem) new TelevisionEpisodeMediaItem + i => (MediaItem) new Episode { Id = i, - Metadata = new TelevisionEpisodeMetadata + EpisodeMetadata = new List { - Aired = new DateTime(2020, 1, i) + new() + { + ReleaseDate = new DateTime(2020, 1, i) + } } }) .Reverse() diff --git a/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs b/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs index ec80fc07b..332382a3d 100644 --- a/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs @@ -40,7 +40,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task InitialFlood_Should_StartAtMidnight() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(6), DateTime.Today) }; @@ -59,7 +59,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task InitialFlood_Should_StartAtMidnight_With_LateStart() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(6), DateTime.Today) }; @@ -79,7 +79,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task ChronologicalContent_Should_CreateChronologicalItems() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1)) @@ -105,7 +105,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task ChronologicalFlood_Should_AnchorAndMaintainExistingPlayout() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(6), DateTime.Today), TestMovie(2, TimeSpan.FromHours(6), DateTime.Today.AddHours(1)) @@ -142,7 +142,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task ChronologicalFlood_Should_AnchorAndReturnNewPlayoutItems() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(6), DateTime.Today), TestMovie(2, TimeSpan.FromHours(6), DateTime.Today.AddHours(1)) @@ -180,7 +180,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task ShuffleFloodRebuild_Should_IgnoreAnchors() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), DateTime.Today), TestMovie(2, TimeSpan.FromHours(1), DateTime.Today.AddHours(1)), @@ -223,7 +223,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task ShuffleFlood_Should_MaintainRandomSeed() { - var mediaItems = new List + var mediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), DateTime.Today), TestMovie(2, TimeSpan.FromHours(1), DateTime.Today.AddHours(1)), @@ -255,22 +255,22 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task FloodContent_Should_FloodAroundFixedContent_One() { - var floodCollection = new SimpleMediaCollection + var floodCollection = new Collection { Id = 1, Name = "Flood Items", - Movies = new List + MediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1)) } }; - var fixedCollection = new SimpleMediaCollection + var fixedCollection = new Collection { Id = 2, Name = "Fixed Items", - Movies = new List + MediaItems = new List { TestMovie(3, TimeSpan.FromHours(2), new DateTime(2020, 1, 1)) } @@ -278,23 +278,23 @@ namespace ErsatzTV.Core.Tests.Scheduling var fakeRepository = new FakeMediaCollectionRepository( Map( - (floodCollection.Id, floodCollection.Movies.ToList()), - (fixedCollection.Id, fixedCollection.Movies.ToList()))); + (floodCollection.Id, floodCollection.MediaItems.ToList()), + (fixedCollection.Id, fixedCollection.MediaItems.ToList()))); var items = new List { new ProgramScheduleItemFlood { Index = 1, - MediaCollection = floodCollection, - MediaCollectionId = floodCollection.Id, + Collection = floodCollection, + CollectionId = floodCollection.Id, StartTime = null }, new ProgramScheduleItemOne { Index = 2, - MediaCollection = fixedCollection, - MediaCollectionId = fixedCollection.Id, + Collection = fixedCollection, + CollectionId = fixedCollection.Id, StartTime = TimeSpan.FromHours(3) } }; @@ -333,22 +333,22 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task FloodContent_Should_FloodAroundFixedContent_Multiple() { - var floodCollection = new SimpleMediaCollection + var floodCollection = new Collection { Id = 1, Name = "Flood Items", - Movies = new List + MediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1)) } }; - var fixedCollection = new SimpleMediaCollection + var fixedCollection = new Collection { Id = 2, Name = "Fixed Items", - Movies = new List + MediaItems = new List { TestMovie(3, TimeSpan.FromHours(2), new DateTime(2020, 1, 1)), TestMovie(4, TimeSpan.FromHours(1), new DateTime(2020, 1, 2)) @@ -357,23 +357,23 @@ namespace ErsatzTV.Core.Tests.Scheduling var fakeRepository = new FakeMediaCollectionRepository( Map( - (floodCollection.Id, floodCollection.Movies.ToList()), - (fixedCollection.Id, fixedCollection.Movies.ToList()))); + (floodCollection.Id, floodCollection.MediaItems.ToList()), + (fixedCollection.Id, fixedCollection.MediaItems.ToList()))); var items = new List { new ProgramScheduleItemFlood { Index = 1, - MediaCollection = floodCollection, - MediaCollectionId = floodCollection.Id, + Collection = floodCollection, + CollectionId = floodCollection.Id, StartTime = null }, new ProgramScheduleItemMultiple { Index = 2, - MediaCollection = fixedCollection, - MediaCollectionId = fixedCollection.Id, + Collection = fixedCollection, + CollectionId = fixedCollection.Id, StartTime = TimeSpan.FromHours(3), Count = 2 } @@ -418,22 +418,22 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task FloodContent_Should_FloodAroundFixedContent_DurationWithoutOfflineTail() { - var floodCollection = new SimpleMediaCollection + var floodCollection = new Collection { Id = 1, Name = "Flood Items", - Movies = new List + MediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1)) } }; - var fixedCollection = new SimpleMediaCollection + var fixedCollection = new Collection { Id = 2, Name = "Fixed Items", - Movies = new List + MediaItems = new List { TestMovie(3, TimeSpan.FromHours(0.75), new DateTime(2020, 1, 1)), TestMovie(4, TimeSpan.FromHours(1.5), new DateTime(2020, 1, 2)) @@ -442,23 +442,23 @@ namespace ErsatzTV.Core.Tests.Scheduling var fakeRepository = new FakeMediaCollectionRepository( Map( - (floodCollection.Id, floodCollection.Movies.ToList()), - (fixedCollection.Id, fixedCollection.Movies.ToList()))); + (floodCollection.Id, floodCollection.MediaItems.ToList()), + (fixedCollection.Id, fixedCollection.MediaItems.ToList()))); var items = new List { new ProgramScheduleItemFlood { Index = 1, - MediaCollection = floodCollection, - MediaCollectionId = floodCollection.Id, + Collection = floodCollection, + CollectionId = floodCollection.Id, StartTime = null }, new ProgramScheduleItemDuration { Index = 2, - MediaCollection = fixedCollection, - MediaCollectionId = fixedCollection.Id, + Collection = fixedCollection, + CollectionId = fixedCollection.Id, StartTime = TimeSpan.FromHours(2), PlayoutDuration = TimeSpan.FromHours(2), OfflineTail = false // immediately continue @@ -507,22 +507,22 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] public async Task MultipleContent_Should_WrapAroundDynamicContent_DurationWithoutOfflineTail() { - var multipleCollection = new SimpleMediaCollection + var multipleCollection = new Collection { Id = 1, Name = "Multiple Items", - Movies = new List + MediaItems = new List { TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1)) } }; - var dynamicCollection = new SimpleMediaCollection + var dynamicCollection = new Collection { Id = 2, Name = "Dynamic Items", - Movies = new List + MediaItems = new List { TestMovie(3, TimeSpan.FromHours(0.75), new DateTime(2020, 1, 1)), TestMovie(4, TimeSpan.FromHours(1.5), new DateTime(2020, 1, 2)) @@ -531,24 +531,24 @@ namespace ErsatzTV.Core.Tests.Scheduling var fakeRepository = new FakeMediaCollectionRepository( Map( - (multipleCollection.Id, multipleCollection.Movies.ToList()), - (dynamicCollection.Id, dynamicCollection.Movies.ToList()))); + (multipleCollection.Id, multipleCollection.MediaItems.ToList()), + (dynamicCollection.Id, dynamicCollection.MediaItems.ToList()))); var items = new List { new ProgramScheduleItemMultiple { Index = 1, - MediaCollection = multipleCollection, - MediaCollectionId = multipleCollection.Id, + Collection = multipleCollection, + CollectionId = multipleCollection.Id, StartTime = null, Count = 2 }, new ProgramScheduleItemDuration { Index = 2, - MediaCollection = dynamicCollection, - MediaCollectionId = dynamicCollection.Id, + Collection = dynamicCollection, + CollectionId = dynamicCollection.Id, StartTime = null, PlayoutDuration = TimeSpan.FromHours(2), OfflineTail = false // immediately continue @@ -598,12 +598,12 @@ namespace ErsatzTV.Core.Tests.Scheduling return now - now.TimeOfDay + TimeSpan.FromHours(hours); } - private static ProgramScheduleItem Flood(MediaCollection mediaCollection) => + private static ProgramScheduleItem Flood(Collection mediaCollection) => new ProgramScheduleItemFlood { Index = 1, - MediaCollection = mediaCollection, - MediaCollectionId = mediaCollection.Id, + Collection = mediaCollection, + CollectionId = mediaCollection.Id, StartTime = null }; @@ -615,12 +615,12 @@ namespace ErsatzTV.Core.Tests.Scheduling Statistics = new MediaItemStatistics { Duration = duration } }; - private TestData TestDataFloodForItems(List mediaItems, PlaybackOrder playbackOrder) + private TestData TestDataFloodForItems(List mediaItems, PlaybackOrder playbackOrder) { - var mediaCollection = new SimpleMediaCollection + var mediaCollection = new Collection { Id = 1, - Movies = mediaItems + MediaItems = mediaItems }; var collectionRepo = new FakeMediaCollectionRepository(Map((mediaCollection.Id, mediaItems))); diff --git a/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs b/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs index 13f3d8f0d..c4832ebbe 100644 --- a/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs @@ -26,7 +26,7 @@ namespace ErsatzTV.Core.Tests.Scheduling { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); + var state = new CollectionEnumeratorState(); var randomizedContent = new RandomizedMediaCollectionEnumerator(contents, state); @@ -47,7 +47,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void State_Index_Should_Increment() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); + var state = new CollectionEnumeratorState(); var randomizedContent = new RandomizedMediaCollectionEnumerator(contents, state); @@ -63,7 +63,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void State_Should_Impact_Iterator_Start() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState { Index = 5, Seed = KnownSeed }; + var state = new CollectionEnumeratorState { Index = 5, Seed = KnownSeed }; var randomizedContent = new RandomizedMediaCollectionEnumerator(contents, state); @@ -80,12 +80,15 @@ namespace ErsatzTV.Core.Tests.Scheduling private static List Episodes(int count) => Range(1, count).Map( - i => (MediaItem) new TelevisionEpisodeMediaItem + i => (MediaItem) new Episode { Id = i, - Metadata = new TelevisionEpisodeMetadata + EpisodeMetadata = new List { - Aired = new DateTime(2020, 1, i) + new() + { + ReleaseDate = new DateTime(2020, 1, i) + } } }) .Reverse() diff --git a/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs b/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs index eeeaef98f..9240de89f 100644 --- a/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs @@ -20,7 +20,7 @@ namespace ErsatzTV.Core.Tests.Scheduling { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); + var state = new CollectionEnumeratorState(); var shuffledContent = new ShuffledMediaCollectionEnumerator(contents, state); @@ -40,7 +40,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void State_Index_Should_Increment() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); + var state = new CollectionEnumeratorState(); var shuffledContent = new ShuffledMediaCollectionEnumerator(contents, state); @@ -55,7 +55,7 @@ namespace ErsatzTV.Core.Tests.Scheduling public void State_Should_Impact_Iterator_Start() { List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState { Index = 5, Seed = MagicSeed }; + var state = new CollectionEnumeratorState { Index = 5, Seed = MagicSeed }; var shuffledContent = new ShuffledMediaCollectionEnumerator(contents, state); @@ -70,12 +70,15 @@ namespace ErsatzTV.Core.Tests.Scheduling private static List Episodes(int count) => Range(1, count).Map( - i => (MediaItem) new TelevisionEpisodeMediaItem + i => (MediaItem) new Episode { Id = i, - Metadata = new TelevisionEpisodeMetadata + EpisodeMetadata = new List { - Aired = new DateTime(2020, 1, i) + new() + { + ReleaseDate = new DateTime(2020, 1, i) + } } }) .Reverse() diff --git a/ErsatzTV.Core/Domain/MediaCollectionEnumeratorState.cs b/ErsatzTV.Core/Domain/CollectionEnumeratorState.cs similarity index 72% rename from ErsatzTV.Core/Domain/MediaCollectionEnumeratorState.cs rename to ErsatzTV.Core/Domain/CollectionEnumeratorState.cs index 9c0013f94..9f843f193 100644 --- a/ErsatzTV.Core/Domain/MediaCollectionEnumeratorState.cs +++ b/ErsatzTV.Core/Domain/CollectionEnumeratorState.cs @@ -1,6 +1,6 @@ namespace ErsatzTV.Core.Domain { - public class MediaCollectionEnumeratorState + public class CollectionEnumeratorState { public int Seed { get; set; } public int Index { get; set; } diff --git a/ErsatzTV.Core/Domain/LocalTelevisionShowSource.cs b/ErsatzTV.Core/Domain/LocalTelevisionShowSource.cs deleted file mode 100644 index 055158091..000000000 --- a/ErsatzTV.Core/Domain/LocalTelevisionShowSource.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ErsatzTV.Core.Domain -{ - public class LocalTelevisionShowSource : TelevisionShowSource - { - public int MediaSourceId { get; set; } - public LocalMediaSource MediaSource { get; set; } - public string Path { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/MediaCollection.cs b/ErsatzTV.Core/Domain/MediaCollection.cs deleted file mode 100644 index 67d13016a..000000000 --- a/ErsatzTV.Core/Domain/MediaCollection.cs +++ /dev/null @@ -1,10 +0,0 @@ -using LanguageExt; - -namespace ErsatzTV.Core.Domain -{ - public abstract class MediaCollection : Record - { - public int Id { get; set; } - public string Name { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/MediaItem/Movie.cs b/ErsatzTV.Core/Domain/MediaItem/Movie.cs index 6465026e2..39e1f3297 100644 --- a/ErsatzTV.Core/Domain/MediaItem/Movie.cs +++ b/ErsatzTV.Core/Domain/MediaItem/Movie.cs @@ -5,10 +5,6 @@ namespace ErsatzTV.Core.Domain public class Movie : MediaItem { public List MovieMetadata { get; set; } - public List MediaVersions { get; set; } - - // TODO: remove SimpleMediaCollections - public List SimpleMediaCollections { get; set; } } } diff --git a/ErsatzTV.Core/Domain/PlayoutProgramScheduleAnchor.cs b/ErsatzTV.Core/Domain/PlayoutProgramScheduleAnchor.cs index e09bcbb1c..81f53b972 100644 --- a/ErsatzTV.Core/Domain/PlayoutProgramScheduleAnchor.cs +++ b/ErsatzTV.Core/Domain/PlayoutProgramScheduleAnchor.cs @@ -18,6 +18,6 @@ public Collection Collection { get; set; } public int? MediaItemId { get; set; } public MediaItem MediaItem { get; set; } - public MediaCollectionEnumeratorState EnumeratorState { get; set; } + public CollectionEnumeratorState EnumeratorState { get; set; } } } diff --git a/ErsatzTV.Core/Domain/ProgramScheduleItem.cs b/ErsatzTV.Core/Domain/ProgramScheduleItem.cs index f51e45855..deb069d01 100644 --- a/ErsatzTV.Core/Domain/ProgramScheduleItem.cs +++ b/ErsatzTV.Core/Domain/ProgramScheduleItem.cs @@ -8,19 +8,9 @@ namespace ErsatzTV.Core.Domain public int Index { get; set; } public StartType StartType => StartTime.HasValue ? StartType.Fixed : StartType.Dynamic; public TimeSpan? StartTime { get; set; } - public ProgramScheduleItemCollectionType CollectionType { get; set; } - - // TODO: remove these - public int? MediaCollectionId { get; set; } - public MediaCollection MediaCollection { get; set; } - public int? TelevisionShowId { get; set; } - public TelevisionShow TelevisionShow { get; set; } - public int? TelevisionSeasonId { get; set; } - public TelevisionSeason TelevisionSeason { get; set; } public int ProgramScheduleId { get; set; } public ProgramSchedule ProgramSchedule { get; set; } - public int? CollectionId { get; set; } public Collection Collection { get; set; } public int? MediaItemId { get; set; } diff --git a/ErsatzTV.Core/Domain/SimpleMediaCollection.cs b/ErsatzTV.Core/Domain/SimpleMediaCollection.cs deleted file mode 100644 index 69fb39432..000000000 --- a/ErsatzTV.Core/Domain/SimpleMediaCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace ErsatzTV.Core.Domain -{ - public class SimpleMediaCollection : MediaCollection - { - public List Movies { get; set; } - public List TelevisionShows { get; set; } - public List TelevisionSeasons { get; set; } - public List TelevisionEpisodes { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/TelevisionEpisodeMediaItem.cs b/ErsatzTV.Core/Domain/TelevisionEpisodeMediaItem.cs deleted file mode 100644 index bd2d66bc7..000000000 --- a/ErsatzTV.Core/Domain/TelevisionEpisodeMediaItem.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace ErsatzTV.Core.Domain -{ - public class TelevisionEpisodeMediaItem : MediaItem - { - public int SeasonId { get; set; } - public TelevisionSeason Season { get; set; } - public TelevisionEpisodeMetadata Metadata { get; set; } - public List SimpleMediaCollections { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/TelevisionEpisodeMetadata.cs b/ErsatzTV.Core/Domain/TelevisionEpisodeMetadata.cs deleted file mode 100644 index 9b210e4ea..000000000 --- a/ErsatzTV.Core/Domain/TelevisionEpisodeMetadata.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ErsatzTV.Core.Domain -{ - public class TelevisionEpisodeMetadata : MediaItemMetadata - { - public int Id { get; set; } - public int TelevisionEpisodeId { get; set; } - public TelevisionEpisodeMediaItem TelevisionEpisode { get; set; } - public int Season { get; set; } - public int Episode { get; set; } - public string Plot { get; set; } - public DateTime? Aired { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/TelevisionSeason.cs b/ErsatzTV.Core/Domain/TelevisionSeason.cs deleted file mode 100644 index 009bbf3ce..000000000 --- a/ErsatzTV.Core/Domain/TelevisionSeason.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using ErsatzTV.Core.Interfaces.Domain; - -namespace ErsatzTV.Core.Domain -{ - public class TelevisionSeason : IHasAPoster - { - public int Id { get; set; } - public int TelevisionShowId { get; set; } - public TelevisionShow TelevisionShow { get; set; } - public int Number { get; set; } - public List Episodes { get; set; } - public List SimpleMediaCollections { get; set; } - public string Path { get; set; } - public string Poster { get; set; } - public DateTime? PosterLastWriteTime { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/TelevisionShow.cs b/ErsatzTV.Core/Domain/TelevisionShow.cs deleted file mode 100644 index e50793d2a..000000000 --- a/ErsatzTV.Core/Domain/TelevisionShow.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ErsatzTV.Core.Domain -{ - public class TelevisionShow - { - public int Id { get; set; } - public List Sources { get; set; } - public TelevisionShowMetadata Metadata { get; set; } - public List Seasons { get; set; } - public string Poster { get; set; } - public DateTime? PosterLastWriteTime { get; set; } - public List SimpleMediaCollections { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/TelevisionShowMetadata.cs b/ErsatzTV.Core/Domain/TelevisionShowMetadata.cs deleted file mode 100644 index fcbf5c39c..000000000 --- a/ErsatzTV.Core/Domain/TelevisionShowMetadata.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace ErsatzTV.Core.Domain -{ - public class TelevisionShowMetadata - { - public int Id { get; set; } - public int TelevisionShowId { get; set; } - - public TelevisionShow TelevisionShow { get; set; } - - // public int ShowId { get; set; } - // public Show Show { get; set; } - public MetadataSource Source { get; set; } - public DateTime? LastWriteTime { get; set; } - public string Title { get; set; } - public string SortTitle { get; set; } - public int? Year { get; set; } - public string Plot { get; set; } - } -} diff --git a/ErsatzTV.Core/Domain/TelevisionShowSource.cs b/ErsatzTV.Core/Domain/TelevisionShowSource.cs deleted file mode 100644 index 877f1332d..000000000 --- a/ErsatzTV.Core/Domain/TelevisionShowSource.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ErsatzTV.Core.Domain -{ - // used for shows split across sources (folders) - // won't need to convert, since shows will be linked via metadata - public class TelevisionShowSource - { - public int Id { get; set; } - public int TelevisionShowId { get; set; } - public TelevisionShow TelevisionShow { get; set; } - } -} diff --git a/ErsatzTV.Core/Interfaces/Metadata/IFallbackMetadataProvider.cs b/ErsatzTV.Core/Interfaces/Metadata/IFallbackMetadataProvider.cs index 4325b1fda..52125561c 100644 --- a/ErsatzTV.Core/Interfaces/Metadata/IFallbackMetadataProvider.cs +++ b/ErsatzTV.Core/Interfaces/Metadata/IFallbackMetadataProvider.cs @@ -4,6 +4,6 @@ namespace ErsatzTV.Core.Interfaces.Metadata { public interface IFallbackMetadataProvider { - TelevisionShowMetadata GetFallbackMetadataForShow(string showFolder); + ShowMetadata GetFallbackMetadataForShow(string showFolder); } } diff --git a/ErsatzTV.Core/Interfaces/Metadata/ILocalMetadataProvider.cs b/ErsatzTV.Core/Interfaces/Metadata/ILocalMetadataProvider.cs index 317e35884..c4f29c4f3 100644 --- a/ErsatzTV.Core/Interfaces/Metadata/ILocalMetadataProvider.cs +++ b/ErsatzTV.Core/Interfaces/Metadata/ILocalMetadataProvider.cs @@ -6,10 +6,10 @@ namespace ErsatzTV.Core.Interfaces.Metadata { public interface ILocalMetadataProvider { - Task GetMetadataForShow(string showFolder); + Task GetMetadataForShow(string showFolder); Task RefreshSidecarMetadata(MediaItem mediaItem, string path); - Task RefreshSidecarMetadata(TelevisionShow televisionShow, string showFolder); + Task RefreshSidecarMetadata(Show televisionShow, string showFolder); Task RefreshFallbackMetadata(MediaItem mediaItem); - Task RefreshFallbackMetadata(TelevisionShow televisionShow, string showFolder); + Task RefreshFallbackMetadata(Show televisionShow, string showFolder); } } diff --git a/ErsatzTV.Core/Interfaces/Repositories/ICollectionRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/ICollectionRepository.cs new file mode 100644 index 000000000..7d743ff90 --- /dev/null +++ b/ErsatzTV.Core/Interfaces/Repositories/ICollectionRepository.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using ErsatzTV.Core.Domain; +using LanguageExt; + +namespace ErsatzTV.Core.Interfaces.Repositories +{ + public interface ICollectionRepository + { + public Task> GetWithItemsUntracked(int collectionId); + } +} diff --git a/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs index 4dd81dfbd..7fe621efc 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs @@ -7,16 +7,13 @@ namespace ErsatzTV.Core.Interfaces.Repositories { public interface IMediaCollectionRepository { - Task Add(SimpleMediaCollection collection); - Task> Get(int id); - Task> GetSimpleMediaCollection(int id); - Task> GetSimpleMediaCollectionWithItems(int id); - Task> GetSimpleMediaCollectionWithItemsUntracked(int id); - Task> GetSimpleMediaCollections(); - Task> GetAll(); + Task Add(Collection collection); + Task> Get(int id); + Task> GetCollectionWithItems(int id); + Task> GetCollectionWithItemsUntracked(int id); + Task> GetAll(); Task>> GetItems(int id); - Task>> GetSimpleMediaCollectionItems(int id); - Task Update(SimpleMediaCollection collection); - Task Delete(int mediaCollectionId); + Task Update(Collection collection); + Task Delete(int collectionId); } } diff --git a/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs index 990706bbb..c24a8d705 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs @@ -7,41 +7,39 @@ namespace ErsatzTV.Core.Interfaces.Repositories { public interface ITelevisionRepository { - Task Update(TelevisionShow show); - Task Update(TelevisionSeason season); - Task Update(TelevisionEpisodeMediaItem episode); - Task> GetAllShows(); - Task> GetShow(int televisionShowId); + Task Update(Show show); + Task Update(Season season); + Task Update(Episode episode); + Task> GetAllShows(); + Task> GetShow(int televisionShowId); Task GetShowCount(); - Task> GetPagedShows(int pageNumber, int pageSize); - Task> GetShowItems(int televisionShowId); - Task> GetAllSeasons(); - Task> GetSeason(int televisionSeasonId); + Task> GetPagedShows(int pageNumber, int pageSize); + Task> GetShowItems(int televisionShowId); + Task> GetAllSeasons(); + Task> GetSeason(int televisionSeasonId); Task GetSeasonCount(int televisionShowId); - Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize); - Task> GetSeasonItems(int televisionSeasonId); - Task> GetEpisode(int televisionEpisodeId); + Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize); + Task> GetSeasonItems(int televisionSeasonId); + Task> GetEpisode(int televisionEpisodeId); Task GetEpisodeCount(int televisionSeasonId); - Task> GetPagedEpisodes(int televisionSeasonId, int pageNumber, int pageSize); - Task> GetShowByPath(int mediaSourceId, string path); - Task> GetShowByMetadata(TelevisionShowMetadata metadata); + Task> GetPagedEpisodes(int televisionSeasonId, int pageNumber, int pageSize); + Task> GetShowByMetadata(ShowMetadata metadata); - Task> AddShow( + Task> AddShow( int localMediaSourceId, string showFolder, - TelevisionShowMetadata metadata); + ShowMetadata metadata); - Task> GetOrAddSeason( - TelevisionShow show, + Task> GetOrAddSeason( + Show show, string path, int seasonNumber); - Task> GetOrAddEpisode( - TelevisionSeason season, + Task> GetOrAddEpisode( + Season season, LibraryPath libraryPath, string path); - Task DeleteMissingSources(int localMediaSourceId, List allFolders); Task DeleteEmptyShows(); } } diff --git a/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs b/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs index 7d36941ab..a45b92d45 100644 --- a/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs @@ -5,7 +5,7 @@ namespace ErsatzTV.Core.Interfaces.Scheduling { public interface IMediaCollectionEnumerator { - MediaCollectionEnumeratorState State { get; } + CollectionEnumeratorState State { get; } Option Current { get; } void MoveNext(); } diff --git a/ErsatzTV.Core/Iptv/ChannelGuide.cs b/ErsatzTV.Core/Iptv/ChannelGuide.cs index 54fc0efae..ba0e8baaf 100644 --- a/ErsatzTV.Core/Iptv/ChannelGuide.cs +++ b/ErsatzTV.Core/Iptv/ChannelGuide.cs @@ -61,14 +61,14 @@ namespace ErsatzTV.Core.Iptv string title = playoutItem.MediaItem switch { Movie m => m.MovieMetadata.HeadOrNone().Match(mm => mm.Title, () => m.Path), - TelevisionEpisodeMediaItem e => e.Metadata?.Title ?? e.Path, + Episode e => e.EpisodeMetadata.HeadOrNone().Match(em => em.Title, () => e.Path), _ => "[unknown]" }; string description = playoutItem.MediaItem switch { Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Plot).IfNone(string.Empty), - TelevisionEpisodeMediaItem e => e.Metadata?.Plot, + Episode e => e.EpisodeMetadata.HeadOrNone().Map(em => em.Plot).IfNone(string.Empty), _ => string.Empty }; @@ -96,10 +96,10 @@ namespace ErsatzTV.Core.Iptv xml.WriteAttributeString("lang", "en"); xml.WriteEndElement(); // sub-title - if (playoutItem.MediaItem is TelevisionEpisodeMediaItem episode) + if (playoutItem.MediaItem is Episode episode) { - int s = Optional(episode.Metadata?.Season).IfNone(0); - int e = Optional(episode.Metadata?.Episode).IfNone(0); + int s = Optional(episode.Season?.SeasonNumber).IfNone(0); + int e = episode.EpisodeNumber; if (s > 0 && e > 0) { xml.WriteStartElement("episode-num"); diff --git a/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs b/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs index c8cd12c3c..6e85e2379 100644 --- a/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs +++ b/ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs @@ -8,19 +8,19 @@ namespace ErsatzTV.Core.Metadata { public class FallbackMetadataProvider : IFallbackMetadataProvider { - public TelevisionShowMetadata GetFallbackMetadataForShow(string showFolder) + public ShowMetadata GetFallbackMetadataForShow(string showFolder) { string fileName = Path.GetFileName(showFolder); - var metadata = new TelevisionShowMetadata - { Source = MetadataSource.Fallback, Title = fileName ?? showFolder }; + var metadata = new ShowMetadata + { MetadataKind = MetadataKind.Fallback, Title = fileName ?? showFolder }; return GetTelevisionShowMetadata(fileName, metadata); } - public static TelevisionEpisodeMetadata GetFallbackMetadata(TelevisionEpisodeMediaItem mediaItem) + public static EpisodeMetadata GetFallbackMetadata(Episode episode) { - string fileName = Path.GetFileName(mediaItem.Path); - var metadata = new TelevisionEpisodeMetadata - { Source = MetadataSource.Fallback, Title = fileName ?? mediaItem.Path }; + string fileName = Path.GetFileName(episode.Path); + var metadata = new EpisodeMetadata + { MetadataKind = MetadataKind.Fallback, Title = fileName ?? episode.Path }; if (fileName != null) { @@ -55,7 +55,7 @@ namespace ErsatzTV.Core.Metadata return metadata; } - private static TelevisionEpisodeMetadata GetEpisodeMetadata(string fileName, TelevisionEpisodeMetadata metadata) + private static EpisodeMetadata GetEpisodeMetadata(string fileName, EpisodeMetadata metadata) { try { @@ -64,8 +64,9 @@ namespace ErsatzTV.Core.Metadata if (match.Success) { metadata.Title = match.Groups[1].Value; - metadata.Season = int.Parse(match.Groups[2].Value); - metadata.Episode = int.Parse(match.Groups[3].Value); + // TODO: set episode number? + // metadata.Season = int.Parse(match.Groups[2].Value); + // metadata.Episode = int.Parse(match.Groups[3].Value); } } catch (Exception) @@ -96,9 +97,9 @@ namespace ErsatzTV.Core.Metadata return metadata; } - private static TelevisionShowMetadata GetTelevisionShowMetadata( + private static ShowMetadata GetTelevisionShowMetadata( string fileName, - TelevisionShowMetadata metadata) + ShowMetadata metadata) { try { @@ -107,7 +108,7 @@ namespace ErsatzTV.Core.Metadata if (match.Success) { metadata.Title = match.Groups[1].Value; - metadata.Year = int.Parse(match.Groups[2].Value); + metadata.ReleaseDate = new DateTime(int.Parse(match.Groups[2].Value), 1, 1); } } catch (Exception) diff --git a/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs b/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs index 0ab740781..7fd09f8b8 100644 --- a/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs +++ b/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs @@ -38,7 +38,7 @@ namespace ErsatzTV.Core.Metadata _logger = logger; } - public Task GetMetadataForShow(string showFolder) + public Task GetMetadataForShow(string showFolder) { string nfoFileName = Path.Combine(showFolder, "tvshow.nfo"); return Optional(_localFileSystem.FileExists(nfoFileName)) @@ -56,43 +56,49 @@ namespace ErsatzTV.Core.Metadata public Task RefreshSidecarMetadata(MediaItem mediaItem, string path) => mediaItem switch { - TelevisionEpisodeMediaItem e => LoadMetadata(e, path) + Episode e => LoadMetadata(e, path) .Bind(maybeMetadata => maybeMetadata.IfSomeAsync(metadata => ApplyMetadataUpdate(e, metadata))), Movie m => LoadMetadata(m, path) .Bind(maybeMetadata => maybeMetadata.IfSomeAsync(metadata => ApplyMetadataUpdate(m, metadata))), _ => Task.FromResult(Unit.Default) }; - public Task RefreshSidecarMetadata(TelevisionShow televisionShow, string showFolder) => + public Task RefreshSidecarMetadata(Show televisionShow, string showFolder) => LoadMetadata(televisionShow, showFolder).Bind( maybeMetadata => maybeMetadata.IfSomeAsync(metadata => ApplyMetadataUpdate(televisionShow, metadata))); public Task RefreshFallbackMetadata(MediaItem mediaItem) => mediaItem switch { - TelevisionEpisodeMediaItem e => ApplyMetadataUpdate(e, FallbackMetadataProvider.GetFallbackMetadata(e)) + Episode e => ApplyMetadataUpdate(e, FallbackMetadataProvider.GetFallbackMetadata(e)) .ToUnit(), Movie m => ApplyMetadataUpdate(m, FallbackMetadataProvider.GetFallbackMetadata(m)).ToUnit(), _ => Task.FromResult(Unit.Default) }; - public Task RefreshFallbackMetadata(TelevisionShow televisionShow, string showFolder) => + public Task RefreshFallbackMetadata(Show televisionShow, string showFolder) => ApplyMetadataUpdate(televisionShow, _fallbackMetadataProvider.GetFallbackMetadataForShow(showFolder)) .ToUnit(); - private async Task ApplyMetadataUpdate(TelevisionEpisodeMediaItem mediaItem, TelevisionEpisodeMetadata metadata) + private async Task ApplyMetadataUpdate(Episode episode, EpisodeMetadata metadata) { - mediaItem.Metadata ??= new TelevisionEpisodeMetadata { TelevisionEpisodeId = mediaItem.Id }; - mediaItem.Metadata.Source = metadata.Source; - mediaItem.Metadata.LastWriteTime = metadata.LastWriteTime; - mediaItem.Metadata.Title = metadata.Title; - mediaItem.Metadata.SortTitle = GetSortTitle(metadata.Title); - mediaItem.Metadata.Season = metadata.Season; - mediaItem.Metadata.Episode = metadata.Episode; - mediaItem.Metadata.Plot = metadata.Plot; - mediaItem.Metadata.Aired = metadata.Aired; - - await _televisionRepository.Update(mediaItem); + episode.EpisodeMetadata.HeadOrNone().Match( + existing => + { + existing.Outline = metadata.Outline; + existing.Plot = metadata.Plot; + existing.Tagline = metadata.Tagline; + existing.Title = metadata.Title; + existing.DateAdded = metadata.DateAdded; + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.OriginalTitle = metadata.OriginalTitle; + existing.ReleaseDate = metadata.ReleaseDate; + existing.SortTitle = metadata.SortTitle ?? GetSortTitle(metadata.Title); + }, + () => episode.EpisodeMetadata = new List { metadata }); + + await _televisionRepository.Update(episode); } private async Task ApplyMetadataUpdate(Movie movie, MovieMetadata metadata) @@ -109,24 +115,32 @@ namespace ErsatzTV.Core.Metadata existing.MetadataKind = metadata.MetadataKind; existing.OriginalTitle = metadata.OriginalTitle; existing.ReleaseDate = metadata.ReleaseDate; - existing.SortTitle = metadata.SortTitle; + existing.SortTitle = metadata.SortTitle ?? GetSortTitle(metadata.Title); }, () => movie.MovieMetadata = new List { metadata }); await _mediaItemRepository.Update(movie); } - private async Task ApplyMetadataUpdate(TelevisionShow televisionShow, TelevisionShowMetadata metadata) + private async Task ApplyMetadataUpdate(Show show, ShowMetadata metadata) { - televisionShow.Metadata ??= new TelevisionShowMetadata(); - televisionShow.Metadata.Source = metadata.Source; - televisionShow.Metadata.LastWriteTime = metadata.LastWriteTime; - televisionShow.Metadata.Title = metadata.Title; - televisionShow.Metadata.Plot = metadata.Plot; - televisionShow.Metadata.Year = metadata.Year; - televisionShow.Metadata.SortTitle = GetSortTitle(metadata.Title); - - await _televisionRepository.Update(televisionShow); + show.ShowMetadata.HeadOrNone().Match( + existing => + { + existing.Outline = metadata.Outline; + existing.Plot = metadata.Plot; + existing.Tagline = metadata.Tagline; + existing.Title = metadata.Title; + existing.DateAdded = metadata.DateAdded; + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.OriginalTitle = metadata.OriginalTitle; + existing.ReleaseDate = metadata.ReleaseDate; + existing.SortTitle = metadata.SortTitle ?? GetSortTitle(metadata.Title); + }, + () => show.ShowMetadata = new List { metadata }); + + await _televisionRepository.Update(show); } private async Task> LoadMetadata(Movie mediaItem, string nfoFileName) @@ -146,9 +160,7 @@ namespace ErsatzTV.Core.Metadata return await LoadMovieMetadata(mediaItem, nfoFileName); } - private async Task> LoadMetadata( - TelevisionEpisodeMediaItem mediaItem, - string nfoFileName) + private async Task> LoadMetadata(Episode mediaItem, string nfoFileName) { if (nfoFileName == null || !File.Exists(nfoFileName)) { @@ -165,8 +177,8 @@ namespace ErsatzTV.Core.Metadata return await LoadEpisodeMetadata(mediaItem, nfoFileName); } - private async Task> LoadMetadata( - TelevisionShow televisionShow, + private async Task> LoadMetadata( + Show televisionShow, string nfoFileName) { if (nfoFileName == null || !File.Exists(nfoFileName)) @@ -178,20 +190,20 @@ namespace ErsatzTV.Core.Metadata return await LoadTelevisionShowMetadata(nfoFileName); } - private async Task> LoadTelevisionShowMetadata(string nfoFileName) + private async Task> LoadTelevisionShowMetadata(string nfoFileName) { try { await using FileStream fileStream = File.Open(nfoFileName, FileMode.Open, FileAccess.Read); Option maybeNfo = TvShowSerializer.Deserialize(fileStream) as TvShowNfo; - return maybeNfo.Match>( - nfo => new TelevisionShowMetadata + return maybeNfo.Match>( + nfo => new ShowMetadata { - Source = MetadataSource.Sidecar, - LastWriteTime = File.GetLastWriteTimeUtc(nfoFileName), + MetadataKind = MetadataKind.Sidecar, + DateUpdated = File.GetLastWriteTimeUtc(nfoFileName), Title = nfo.Title, Plot = nfo.Plot, - Year = nfo.Year + ReleaseDate = new DateTime(nfo.Year, 1, 1) }, None); } @@ -202,23 +214,24 @@ namespace ErsatzTV.Core.Metadata } } - private async Task> LoadEpisodeMetadata( - TelevisionEpisodeMediaItem mediaItem, + private async Task> LoadEpisodeMetadata( + Episode mediaItem, string nfoFileName) { try { await using FileStream fileStream = File.Open(nfoFileName, FileMode.Open, FileAccess.Read); Option maybeNfo = EpisodeSerializer.Deserialize(fileStream) as TvShowEpisodeNfo; - return maybeNfo.Match>( - nfo => new TelevisionEpisodeMetadata + return maybeNfo.Match>( + nfo => new EpisodeMetadata { - Source = MetadataSource.Sidecar, - LastWriteTime = File.GetLastWriteTimeUtc(nfoFileName), + MetadataKind = MetadataKind.Sidecar, + DateUpdated = File.GetLastWriteTimeUtc(nfoFileName), Title = nfo.Title, - Aired = GetAired(nfo.Aired), - Episode = nfo.Episode, - Season = nfo.Season, + ReleaseDate = GetAired(nfo.Aired), + // Episode = nfo.Episode, + // Season = nfo.Season, + // TODO: save episode number somewhere? Plot = nfo.Plot }, None); diff --git a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs index c37c57a85..673c1ed43 100644 --- a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs +++ b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs @@ -53,7 +53,7 @@ namespace ErsatzTV.Core.Metadata foreach (string showFolder in allShowFolders) { // TODO: check all sources for latest metadata? - Either maybeShow = + Either maybeShow = await FindOrCreateShow(libraryPath.Id, showFolder) .BindT(show => UpdateMetadataForShow(show, showFolder)) .BindT(show => UpdatePosterForShow(show, showFolder)); @@ -70,39 +70,21 @@ namespace ErsatzTV.Core.Metadata return Unit.Default; } - private async Task> FindOrCreateShow( + private async Task> FindOrCreateShow( int libraryPathId, string showFolder) { - Option maybeShowByPath = - await _televisionRepository.GetShowByPath(libraryPathId, showFolder); - return await maybeShowByPath.Match( - show => Right(show).AsTask(), - async () => - { - TelevisionShowMetadata metadata = await _localMetadataProvider.GetMetadataForShow(showFolder); - Option maybeShow = await _televisionRepository.GetShowByMetadata(metadata); - return await maybeShow.Match( - async show => - { - show.Sources.Add( - new LocalTelevisionShowSource - { - MediaSourceId = libraryPathId, - Path = showFolder, - TelevisionShow = show - }); - await _televisionRepository.Update(show); - return Right(show); - }, - async () => await _televisionRepository.AddShow(libraryPathId, showFolder, metadata)); - }); + ShowMetadata metadata = await _localMetadataProvider.GetMetadataForShow(showFolder); + Option maybeShow = await _televisionRepository.GetShowByMetadata(metadata); + return await maybeShow.Match( + show => Right(show).AsTask(), + async () => await _televisionRepository.AddShow(libraryPathId, showFolder, metadata)); } private async Task ScanSeasons( LibraryPath libraryPath, string ffprobePath, - TelevisionShow show, + Show show, string showPath) { foreach (string seasonFolder in _localFileSystem.ListSubdirectories(showPath).Filter(ShouldIncludeFolder) @@ -112,7 +94,7 @@ namespace ErsatzTV.Core.Metadata await maybeSeasonNumber.IfSomeAsync( async seasonNumber => { - Either maybeSeason = await _televisionRepository + Either maybeSeason = await _televisionRepository .GetOrAddSeason(show, seasonFolder, seasonNumber) .BindT(UpdatePoster); @@ -128,13 +110,13 @@ namespace ErsatzTV.Core.Metadata private async Task ScanEpisodes( LibraryPath libraryPath, string ffprobePath, - TelevisionSeason season) + Season season) { foreach (string file in _localFileSystem.ListFiles(season.Path) .Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f))).OrderBy(identity)) { // TODO: figure out how to rebuild playlists - Either maybeEpisode = await _televisionRepository + Either maybeEpisode = await _televisionRepository .GetOrAddEpisode(season, libraryPath, file) .BindT(episode => UpdateStatistics(episode, ffprobePath).MapT(_ => episode)) .BindT(UpdateMetadata) @@ -147,8 +129,8 @@ namespace ErsatzTV.Core.Metadata return Unit.Default; } - private async Task> UpdateMetadataForShow( - TelevisionShow show, + private async Task> UpdateMetadataForShow( + Show show, string showFolder) { try @@ -156,9 +138,12 @@ namespace ErsatzTV.Core.Metadata await LocateNfoFileForShow(showFolder).Match( async nfoFile => { - if (show.Metadata == null || show.Metadata.Source == MetadataSource.Fallback || - (show.Metadata.LastWriteTime ?? DateTime.MinValue) < - _localFileSystem.GetLastWriteTime(nfoFile)) + bool shouldUpdate = show.ShowMetadata.HeadOrNone().Match( + m => m.MetadataKind == MetadataKind.Fallback || + m.DateUpdated < _localFileSystem.GetLastWriteTime(nfoFile), + true); + + if (shouldUpdate) { _logger.LogDebug("Refreshing {Attribute} from {Path}", "Sidecar Metadata", nfoFile); await _localMetadataProvider.RefreshSidecarMetadata(show, nfoFile); @@ -166,7 +151,7 @@ namespace ErsatzTV.Core.Metadata }, async () => { - if (show.Metadata == null) + if (!show.ShowMetadata.Any()) { _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", showFolder); await _localMetadataProvider.RefreshFallbackMetadata(show, showFolder); @@ -181,17 +166,20 @@ namespace ErsatzTV.Core.Metadata } } - private async Task> UpdateMetadata( - TelevisionEpisodeMediaItem episode) + private async Task> UpdateMetadata( + Episode episode) { try { await LocateNfoFile(episode).Match( async nfoFile => { - if (episode.Metadata == null || episode.Metadata.Source == MetadataSource.Fallback || - (episode.Metadata.LastWriteTime ?? DateTime.MinValue) < - _localFileSystem.GetLastWriteTime(nfoFile)) + bool shouldUpdate = episode.EpisodeMetadata.HeadOrNone().Match( + m => m.MetadataKind == MetadataKind.Fallback || + m.DateUpdated < _localFileSystem.GetLastWriteTime(nfoFile), + true); + + if (shouldUpdate) { _logger.LogDebug("Refreshing {Attribute} from {Path}", "Sidecar Metadata", nfoFile); await _localMetadataProvider.RefreshSidecarMetadata(episode, nfoFile); @@ -199,7 +187,7 @@ namespace ErsatzTV.Core.Metadata }, async () => { - if (episode.Metadata == null) + if (!episode.EpisodeMetadata.Any()) { _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", episode.Path); await _localMetadataProvider.RefreshFallbackMetadata(episode); @@ -214,8 +202,8 @@ namespace ErsatzTV.Core.Metadata } } - private async Task> UpdatePosterForShow( - TelevisionShow show, + private async Task> UpdatePosterForShow( + Show show, string showFolder) { try @@ -255,7 +243,7 @@ namespace ErsatzTV.Core.Metadata } } - private async Task> UpdatePoster(TelevisionSeason season) + private async Task> UpdatePoster(Season season) { try { @@ -279,8 +267,8 @@ namespace ErsatzTV.Core.Metadata } } - private async Task> UpdateThumbnail( - TelevisionEpisodeMediaItem episode) + private async Task> UpdateThumbnail( + Episode episode) { try { @@ -308,7 +296,7 @@ namespace ErsatzTV.Core.Metadata Optional(Path.Combine(showFolder, "tvshow.nfo")) .Filter(s => _localFileSystem.FileExists(s)); - private Option LocateNfoFile(TelevisionEpisodeMediaItem episode) => + private Option LocateNfoFile(Episode episode) => Optional(Path.ChangeExtension(episode.Path, "nfo")) .Filter(s => _localFileSystem.FileExists(s)); @@ -319,16 +307,16 @@ namespace ErsatzTV.Core.Metadata .Filter(s => _localFileSystem.FileExists(s)) .HeadOrNone(); - private Option LocatePoster(TelevisionSeason season) + private Option LocatePoster(Season season) { string folder = Path.GetDirectoryName(season.Path) ?? string.Empty; return ImageFileExtensions - .Map(ext => Path.Combine(folder, $"season{season.Number:00}-poster.{ext}")) + .Map(ext => Path.Combine(folder, $"season{season.SeasonNumber:00}-poster.{ext}")) .Filter(s => _localFileSystem.FileExists(s)) .HeadOrNone(); } - private Option LocateThumbnail(TelevisionEpisodeMediaItem episode) + private Option LocateThumbnail(Episode episode) { string folder = Path.GetDirectoryName(episode.Path) ?? string.Empty; return ImageFileExtensions diff --git a/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs index ab4b8ab44..adc3b0284 100644 --- a/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs @@ -14,18 +14,18 @@ namespace ErsatzTV.Core.Scheduling public ChronologicalMediaCollectionEnumerator( IEnumerable mediaItems, - MediaCollectionEnumeratorState state) + CollectionEnumeratorState state) { _sortedMediaItems = mediaItems.OrderBy(identity, new ChronologicalComparer()).ToList(); - State = new MediaCollectionEnumeratorState { Seed = state.Seed }; + State = new CollectionEnumeratorState { Seed = state.Seed }; while (State.Index < state.Index) { MoveNext(); } } - public MediaCollectionEnumeratorState State { get; } + public CollectionEnumeratorState State { get; } public Option Current => _sortedMediaItems.Any() ? _sortedMediaItems[State.Index] : None; @@ -42,7 +42,9 @@ namespace ErsatzTV.Core.Scheduling DateTime date1 = x switch { - TelevisionEpisodeMediaItem e => e.Metadata?.Aired ?? DateTime.MaxValue, + Episode e => e.EpisodeMetadata.HeadOrNone().Match( + em => em.ReleaseDate ?? DateTime.MaxValue, + () => DateTime.MaxValue), Movie m => m.MovieMetadata.HeadOrNone().Match( mm => mm.ReleaseDate ?? DateTime.MaxValue, () => DateTime.MaxValue), @@ -51,7 +53,9 @@ namespace ErsatzTV.Core.Scheduling DateTime date2 = y switch { - TelevisionEpisodeMediaItem e => e.Metadata?.Aired ?? DateTime.MaxValue, + Episode e => e.EpisodeMetadata.HeadOrNone().Match( + em => em.ReleaseDate ?? DateTime.MaxValue, + () => DateTime.MaxValue), Movie m => m.MovieMetadata.HeadOrNone().Match( mm => mm.ReleaseDate ?? DateTime.MaxValue, () => DateTime.MaxValue), @@ -65,13 +69,13 @@ namespace ErsatzTV.Core.Scheduling int season1 = x switch { - TelevisionEpisodeMediaItem e => e.Metadata?.Season ?? int.MaxValue, + Episode e => e.Season?.SeasonNumber ?? int.MaxValue, _ => int.MaxValue }; int season2 = y switch { - TelevisionEpisodeMediaItem e => e.Metadata?.Season ?? int.MaxValue, + Episode e => e.Season?.SeasonNumber ?? int.MaxValue, _ => int.MaxValue }; @@ -82,13 +86,13 @@ namespace ErsatzTV.Core.Scheduling int episode1 = x switch { - TelevisionEpisodeMediaItem e => e.Metadata?.Episode ?? int.MaxValue, + Episode e => e.EpisodeNumber, _ => int.MaxValue }; int episode2 = y switch { - TelevisionEpisodeMediaItem e => e.Metadata?.Episode ?? int.MaxValue, + Episode e => e.EpisodeNumber, _ => int.MaxValue }; diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs index 8c35b26a1..3d55fb9b3 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs @@ -58,11 +58,11 @@ namespace ErsatzTV.Core.Scheduling await _mediaCollectionRepository.GetItems(collectionKey.Id); return Tuple(collectionKey, maybeItems.IfNone(new List())); case ProgramScheduleItemCollectionType.TelevisionShow: - List showItems = + List showItems = await _televisionRepository.GetShowItems(collectionKey.Id); return Tuple(collectionKey, showItems.Cast().ToList()); case ProgramScheduleItemCollectionType.TelevisionSeason: - List seasonItems = + List seasonItems = await _televisionRepository.GetSeasonItems(collectionKey.Id); return Tuple(collectionKey, seasonItems.Cast().ToList()); default: @@ -364,9 +364,9 @@ namespace ErsatzTV.Core.Scheduling collectionKey.CollectionType && a.CollectionId == collectionKey.Id); - MediaCollectionEnumeratorState state = maybeAnchor.Match( + CollectionEnumeratorState state = maybeAnchor.Match( anchor => anchor.EnumeratorState, - () => new MediaCollectionEnumeratorState { Seed = Random.Next(), Index = 0 }); + () => new CollectionEnumeratorState { Seed = Random.Next(), Index = 0 }); switch (playout.ProgramSchedule.MediaCollectionPlaybackOrder) { @@ -385,11 +385,11 @@ namespace ErsatzTV.Core.Scheduling private static string DisplayTitle(MediaItem mediaItem) => mediaItem switch { - TelevisionEpisodeMediaItem e => e.Metadata != null - ? $"{e.Metadata.Title} - s{e.Metadata.Season:00}e{e.Metadata.Episode:00}" + Episode e => e.EpisodeMetadata.Any() && e.Season != null + ? $"{e.EpisodeMetadata.Head().Title} - s{e.Season.SeasonNumber:00}e{e.EpisodeNumber:00}" : Path.GetFileName(e.Path), Movie m => m.MovieMetadata.HeadOrNone().Match( - mm => mm.Title, + mm => mm.Title ?? string.Empty, () => Path.GetFileName(m.Path)), _ => string.Empty }; @@ -400,17 +400,17 @@ namespace ErsatzTV.Core.Scheduling ProgramScheduleItemCollectionType.Collection => new CollectionKey { CollectionType = item.CollectionType, - Id = item.MediaCollectionId.Value + Id = item.CollectionId.Value }, ProgramScheduleItemCollectionType.TelevisionShow => new CollectionKey { CollectionType = item.CollectionType, - Id = item.TelevisionShowId.Value + Id = item.MediaItemId.Value }, ProgramScheduleItemCollectionType.TelevisionSeason => new CollectionKey { CollectionType = item.CollectionType, - Id = item.TelevisionSeasonId.Value + Id = item.MediaItemId.Value }, _ => throw new ArgumentOutOfRangeException(nameof(item)) }; diff --git a/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs index 660c72109..9d866d4e8 100644 --- a/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs @@ -14,12 +14,12 @@ namespace ErsatzTV.Core.Scheduling private readonly Random _random; private int _index; - public RandomizedMediaCollectionEnumerator(IList mediaItems, MediaCollectionEnumeratorState state) + public RandomizedMediaCollectionEnumerator(IList mediaItems, CollectionEnumeratorState state) { _mediaItems = mediaItems; _random = new Random(state.Seed); - State = new MediaCollectionEnumeratorState { Seed = state.Seed }; + State = new CollectionEnumeratorState { Seed = state.Seed }; // we want to move at least once so we start with a random item and not the first // because _index defaults to 0 while (State.Index <= state.Index) @@ -28,7 +28,7 @@ namespace ErsatzTV.Core.Scheduling } } - public MediaCollectionEnumeratorState State { get; } + public CollectionEnumeratorState State { get; } public Option Current => _mediaItems.Any() ? _mediaItems[_index] : None; diff --git a/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs index a81bae44d..d51ca9fb1 100644 --- a/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs @@ -15,20 +15,20 @@ namespace ErsatzTV.Core.Scheduling private IList _shuffled; - public ShuffledMediaCollectionEnumerator(IList mediaItems, MediaCollectionEnumeratorState state) + public ShuffledMediaCollectionEnumerator(IList mediaItems, CollectionEnumeratorState state) { _mediaItems = mediaItems; _random = new Random(state.Seed); _shuffled = Shuffle(_mediaItems, _random); - State = new MediaCollectionEnumeratorState { Seed = state.Seed }; + State = new CollectionEnumeratorState { Seed = state.Seed }; while (State.Index < state.Index) { MoveNext(); } } - public MediaCollectionEnumeratorState State { get; } + public CollectionEnumeratorState State { get; } public Option Current => _shuffled.Any() ? _shuffled[State.Index % _mediaItems.Count] : None; diff --git a/ErsatzTV.Infrastructure/Data/Configurations/MediaCollectionConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/MediaCollectionConfiguration.cs deleted file mode 100644 index b566ec857..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/MediaCollectionConfiguration.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class MediaCollectionConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("MediaCollection"); - - builder.HasIndex(c => c.Name).IsUnique(); - } - } -} diff --git a/ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleItemConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleItemConfiguration.cs index 2796298ef..71ce2c1a7 100644 --- a/ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleItemConfiguration.cs +++ b/ErsatzTV.Infrastructure/Data/Configurations/ProgramScheduleItemConfiguration.cs @@ -10,21 +10,6 @@ namespace ErsatzTV.Infrastructure.Data.Configurations { builder.ToTable("ProgramScheduleItem"); - builder.HasOne(i => i.MediaCollection) - .WithMany() - .HasForeignKey(i => i.MediaCollectionId) - .IsRequired(false); - - builder.HasOne(i => i.TelevisionShow) - .WithMany() - .HasForeignKey(i => i.TelevisionShowId) - .IsRequired(false); - - builder.HasOne(i => i.TelevisionSeason) - .WithMany() - .HasForeignKey(i => i.TelevisionSeasonId) - .IsRequired(false); - builder.HasOne(i => i.Collection) .WithMany() .HasForeignKey(i => i.CollectionId) diff --git a/ErsatzTV.Infrastructure/Data/Configurations/SimpleMediaCollectionConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/SimpleMediaCollectionConfiguration.cs deleted file mode 100644 index 43fcb9cc5..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/SimpleMediaCollectionConfiguration.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class SimpleMediaCollectionConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("SimpleMediaCollection"); - - builder.HasMany(c => c.Movies) - .WithMany(m => m.SimpleMediaCollections) - .UsingEntity(join => join.ToTable("SimpleMediaCollectionMovie")); - - builder.HasMany(c => c.TelevisionShows) - .WithMany(s => s.SimpleMediaCollections) - .UsingEntity(join => join.ToTable("SimpleMediaCollectionShow")); - - builder.HasMany(c => c.TelevisionSeasons) - .WithMany(s => s.SimpleMediaCollections) - .UsingEntity(join => join.ToTable("SimpleMediaCollectionSeason")); - - builder.HasMany(c => c.TelevisionEpisodes) - .WithMany(e => e.SimpleMediaCollections) - .UsingEntity(join => join.ToTable("SimpleMediaCollectionEpisode")); - } - } -} diff --git a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionEpisodeMediaItemConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/TelevisionEpisodeMediaItemConfiguration.cs deleted file mode 100644 index 01bc60372..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionEpisodeMediaItemConfiguration.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class TelevisionEpisodeMediaItemConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("TelevisionEpisode"); - - builder.HasOne(i => i.Metadata) - .WithOne(m => m.TelevisionEpisode) - .HasForeignKey(m => m.TelevisionEpisodeId) - .OnDelete(DeleteBehavior.Cascade); - } - } -} diff --git a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionEpisodeMetadataConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/TelevisionEpisodeMetadataConfiguration.cs deleted file mode 100644 index 08c84c143..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionEpisodeMetadataConfiguration.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class TelevisionEpisodeMetadataConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) => - builder.ToTable("TelevisionEpisodeMetadata"); - } -} diff --git a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionSeasonConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/TelevisionSeasonConfiguration.cs deleted file mode 100644 index 2e6d78deb..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionSeasonConfiguration.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class TelevisionSeasonConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("TelevisionSeason"); - - builder.HasMany(season => season.Episodes) - .WithOne(episode => episode.Season) - .HasForeignKey(episode => episode.SeasonId) - .OnDelete(DeleteBehavior.Cascade); - } - } -} diff --git a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionShowConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/TelevisionShowConfiguration.cs deleted file mode 100644 index abc0a8fbd..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionShowConfiguration.cs +++ /dev/null @@ -1,27 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class TelevisionShowConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("TelevisionShow"); - - builder.HasOne(show => show.Metadata) - .WithOne(metadata => metadata.TelevisionShow) - .HasForeignKey(metadata => metadata.TelevisionShowId) - .OnDelete(DeleteBehavior.Cascade); - - builder.HasMany(show => show.Seasons) - .WithOne(season => season.TelevisionShow); - - builder.HasMany(show => show.Sources) - .WithOne(source => source.TelevisionShow) - .HasForeignKey(source => source.TelevisionShowId) - .OnDelete(DeleteBehavior.Cascade); - } - } -} diff --git a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionShowMetadataConfiguration.cs b/ErsatzTV.Infrastructure/Data/Configurations/TelevisionShowMetadataConfiguration.cs deleted file mode 100644 index 145dbc1c8..000000000 --- a/ErsatzTV.Infrastructure/Data/Configurations/TelevisionShowMetadataConfiguration.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ErsatzTV.Core.Domain; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace ErsatzTV.Infrastructure.Data.Configurations -{ - public class TelevisionShowMetadataConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) => - builder.ToTable("TelevisionShowMetadata"); - } -} diff --git a/ErsatzTV.Infrastructure/Data/Repositories/ChannelRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/ChannelRepository.cs index c99959207..717bd74b7 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/ChannelRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/ChannelRepository.cs @@ -38,7 +38,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories .Include(c => c.Playouts) .ThenInclude(p => p.Items) .ThenInclude(i => i.MediaItem) - .ThenInclude(i => (i as TelevisionEpisodeMediaItem).Metadata) + .ThenInclude(i => (i as Episode).EpisodeMetadata) .Include(c => c.Playouts) .ThenInclude(p => p.Items) .ThenInclude(i => i.MediaItem) diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs index 0132616e6..d8ad01f9f 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs @@ -23,174 +23,152 @@ namespace ErsatzTV.Infrastructure.Data.Repositories _dbConnection = dbConnection; } - public async Task Add(SimpleMediaCollection collection) + public async Task Add(Collection collection) { - await _dbContext.SimpleMediaCollections.AddAsync(collection); + await _dbContext.Collections.AddAsync(collection); await _dbContext.SaveChangesAsync(); return collection; } - public Task> Get(int id) => - _dbContext.MediaCollections.SingleOrDefaultAsync(c => c.Id == id).Map(Optional); + public Task> Get(int id) => + _dbContext.Collections.SingleOrDefaultAsync(c => c.Id == id).Map(Optional); - public Task> GetSimpleMediaCollection(int id) => - _dbContext.SimpleMediaCollections - .SingleOrDefaultAsync(c => c.Id == id) - .Map(Optional); - - public Task> GetSimpleMediaCollectionWithItems(int id) => - _dbContext.SimpleMediaCollections - .Include(s => s.Movies) - .ThenInclude(m => m.LibraryPath) - .Include(s => s.TelevisionShows) - .ThenInclude(s => s.Metadata) - .Include(s => s.TelevisionSeasons) - .Include(s => s.TelevisionEpisodes) - .ThenInclude(s => s.Metadata) + public Task> GetCollectionWithItems(int id) => + _dbContext.Collections + .Include(c => c.MediaItems) + .ThenInclude(i => i.LibraryPath) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Movie).MovieMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Show).ShowMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Season).Show) + .ThenInclude(s => s.ShowMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Episode).EpisodeMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Episode).Season) + .ThenInclude(s => s.Show) + .ThenInclude(s => s.ShowMetadata) .SingleOrDefaultAsync(c => c.Id == id) .Map(Optional); - public Task> GetSimpleMediaCollectionWithItemsUntracked(int id) => - _dbContext.SimpleMediaCollections + public Task> GetCollectionWithItemsUntracked(int id) => + _dbContext.Collections .AsNoTracking() - .Include(s => s.Movies) + .Include(c => c.MediaItems) .ThenInclude(i => i.LibraryPath) - .Include(s => s.Movies) - .ThenInclude(m => m.MovieMetadata) - .Include(s => s.TelevisionShows) - .ThenInclude(s => s.Metadata) - .Include(s => s.TelevisionSeasons) - .ThenInclude(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) - .Include(s => s.TelevisionEpisodes) - .ThenInclude(s => s.Metadata) - .Include(s => s.TelevisionEpisodes) - .ThenInclude(e => e.Season) - .ThenInclude(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Movie).MovieMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Show).ShowMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Season).Show) + .ThenInclude(s => s.ShowMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Episode).EpisodeMetadata) + .Include(c => c.MediaItems) + .ThenInclude(i => (i as Episode).Season) + .ThenInclude(s => s.Show) + .ThenInclude(s => s.ShowMetadata) .SingleOrDefaultAsync(c => c.Id == id) .Map(Optional); - public Task> GetSimpleMediaCollections() => - _dbContext.SimpleMediaCollections.ToListAsync(); - - public Task> GetAll() => - _dbContext.MediaCollections.ToListAsync(); + public Task> GetAll() => + _dbContext.Collections.ToListAsync(); public Task>> GetItems(int id) => - Get(id).MapT( - collection => collection switch - { - SimpleMediaCollection s => SimpleItems(s), - _ => throw new NotSupportedException($"Unsupported collection type {collection.GetType().Name}") - }).Bind(x => x.Sequence()); + Get(id).MapT(c => c.MediaItems); - public Task>> GetSimpleMediaCollectionItems(int id) => - GetSimpleMediaCollection(id).MapT(SimpleItems).Bind(x => x.Sequence()); - - public Task Update(SimpleMediaCollection collection) + public Task Update(Collection collection) { - _dbContext.SimpleMediaCollections.Update(collection); + _dbContext.Collections.Update(collection); return _dbContext.SaveChangesAsync(); } - public async Task Delete(int mediaCollectionId) + public async Task Delete(int collectionId) { - MediaCollection mediaCollection = await _dbContext.MediaCollections.FindAsync(mediaCollectionId); - _dbContext.MediaCollections.Remove(mediaCollection); + Collection mediaCollection = await _dbContext.Collections.FindAsync(collectionId); + _dbContext.Collections.Remove(mediaCollection); await _dbContext.SaveChangesAsync(); } - private async Task> SimpleItems(SimpleMediaCollection collection) - { - var result = new List(); - - await _dbContext.Entry(collection).Collection(c => c.Movies).LoadAsync(); - result.AddRange(collection.Movies); - - result.AddRange(await GetTelevisionShowItems(collection)); - result.AddRange(await GetTelevisionSeasonItems(collection)); - result.AddRange(await GetTelevisionEpisodeItems(collection)); - - return result.Distinct().ToList(); - } - - private async Task> GetTelevisionShowItems(SimpleMediaCollection collection) - { - var parameters = new { CollectionId = collection.Id }; - return await _dbConnection - .QueryAsync( - @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, -mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, -mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, -tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle -from TelevisionEpisode tmi -inner join MediaItem mi on tmi.Id = mi.Id -inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id -inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId -inner join TelevisionShow ts on ts.Id = tsn.TelevisionShowId -inner join SimpleMediaCollectionShow s on s.TelevisionShowsId = ts.Id -where s.SimpleMediaCollectionsId = @CollectionId", - (episode, statistics, metadata) => - { - episode.Statistics = statistics; - episode.Metadata = metadata; - return episode; - }, - parameters, - splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); - } - - private async Task> GetTelevisionSeasonItems(SimpleMediaCollection collection) - { - var parameters = new { CollectionId = collection.Id }; - return await _dbConnection - .QueryAsync( - @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, -mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, -mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, -tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle -from TelevisionEpisode tmi -inner join MediaItem mi on tmi.Id = mi.Id -inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id -inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId -inner join SimpleMediaCollectionSeason s on s.TelevisionSeasonsId = tsn.Id -where s.SimpleMediaCollectionsId = @CollectionId", - (episode, statistics, metadata) => - { - episode.Statistics = statistics; - episode.Metadata = metadata; - return episode; - }, - parameters, - splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); - } - - private async Task> GetTelevisionEpisodeItems(SimpleMediaCollection collection) - { - var parameters = new { CollectionId = collection.Id }; - return await _dbConnection - .QueryAsync( - @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, -mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, -mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, -tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle -from TelevisionEpisode tmi -inner join MediaItem mi on tmi.Id = mi.Id -inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id -inner join SimpleMediaCollectionEpisode s on s.TelevisionEpisodesId = tmi.Id -where s.SimpleMediaCollectionsId = @CollectionId", - (episode, statistics, metadata) => - { - episode.Statistics = statistics; - episode.Metadata = metadata; - return episode; - }, - parameters, - splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); - } +// private async Task> GetTelevisionShowItems(SimpleMediaCollection collection) +// { +// var parameters = new { CollectionId = collection.Id }; +// return await _dbConnection +// .QueryAsync( +// @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, +// mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, +// mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, +// tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle +// from TelevisionEpisode tmi +// inner join MediaItem mi on tmi.Id = mi.Id +// inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id +// inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId +// inner join TelevisionShow ts on ts.Id = tsn.TelevisionShowId +// inner join SimpleMediaCollectionShow s on s.TelevisionShowsId = ts.Id +// where s.SimpleMediaCollectionsId = @CollectionId", +// (episode, statistics, metadata) => +// { +// episode.Statistics = statistics; +// episode.Metadata = metadata; +// return episode; +// }, +// parameters, +// splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); +// } +// +// private async Task> GetTelevisionSeasonItems(SimpleMediaCollection collection) +// { +// var parameters = new { CollectionId = collection.Id }; +// return await _dbConnection +// .QueryAsync( +// @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, +// mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, +// mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, +// tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle +// from TelevisionEpisode tmi +// inner join MediaItem mi on tmi.Id = mi.Id +// inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id +// inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId +// inner join SimpleMediaCollectionSeason s on s.TelevisionSeasonsId = tsn.Id +// where s.SimpleMediaCollectionsId = @CollectionId", +// (episode, statistics, metadata) => +// { +// episode.Statistics = statistics; +// episode.Metadata = metadata; +// return episode; +// }, +// parameters, +// splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); +// } +// +// private async Task> GetTelevisionEpisodeItems(SimpleMediaCollection collection) +// { +// var parameters = new { CollectionId = collection.Id }; +// return await _dbConnection +// .QueryAsync( +// @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, +// mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, +// mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, +// tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle +// from TelevisionEpisode tmi +// inner join MediaItem mi on tmi.Id = mi.Id +// inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id +// inner join SimpleMediaCollectionEpisode s on s.TelevisionEpisodesId = tmi.Id +// where s.SimpleMediaCollectionsId = @CollectionId", +// (episode, statistics, metadata) => +// { +// episode.Statistics = statistics; +// episode.Metadata = metadata; +// return episode; +// }, +// parameters, +// splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); +// } } } diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs index ddfc1662d..1248e347f 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs @@ -25,24 +25,25 @@ namespace ErsatzTV.Infrastructure.Data.Repositories public Task> Search(string searchString) { - IQueryable episodeData = - from c in _dbContext.TelevisionEpisodeMediaItems.Include(c => c.LibraryPath) select c; - - if (!string.IsNullOrEmpty(searchString)) - { - episodeData = episodeData.Where(c => EF.Functions.Like(c.Metadata.Title, $"%{searchString}%")); - } - - IQueryable movieData = - from c in _dbContext.Movies.Include(c => c.LibraryPath) select c; - // TODO: fix this when we need to search + // IQueryable episodeData = + // from c in _dbContext.TelevisionEpisodeMediaItems.Include(c => c.LibraryPath) select c; + // // if (!string.IsNullOrEmpty(searchString)) // { - // movieData = movieData.Where(c => EF.Functions.Like(c.Metadata.Title, $"%{searchString}%")); + // episodeData = episodeData.Where(c => EF.Functions.Like(c.Metadata.Title, $"%{searchString}%")); // } - - return episodeData.OfType().Concat(movieData.OfType()).ToListAsync(); + // + // IQueryable movieData = + // from c in _dbContext.Movies.Include(c => c.LibraryPath) select c; + // + // // if (!string.IsNullOrEmpty(searchString)) + // // { + // // movieData = movieData.Where(c => EF.Functions.Like(c.Metadata.Title, $"%{searchString}%")); + // // } + // + // return episodeData.OfType().Concat(movieData.OfType()).ToListAsync(); + return new List().AsTask(); } public async Task Update(MediaItem mediaItem) diff --git a/ErsatzTV.Infrastructure/Data/Repositories/PlayoutRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/PlayoutRepository.cs index f2b5b6b53..049bae717 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/PlayoutRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/PlayoutRepository.cs @@ -34,10 +34,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories .Include(p => p.ProgramScheduleAnchors) .Include(p => p.ProgramSchedule) .ThenInclude(ps => ps.Items) - .ThenInclude(psi => psi.MediaCollection) + .ThenInclude(psi => psi.Collection) .Include(p => p.ProgramSchedule) .ThenInclude(ps => ps.Items) - .ThenInclude(psi => psi.TelevisionShow) + .ThenInclude(psi => psi.MediaItem) .OrderBy(p => p.Id) // https://github.com/dotnet/efcore/issues/22579#issuecomment-694772289 .SingleOrDefaultAsync(p => p.Id == id); @@ -60,7 +60,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories .Include(i => i.MediaItem) .ThenInclude(m => (m as Movie).MovieMetadata) .Include(i => i.MediaItem) - .ThenInclude(m => (m as TelevisionEpisodeMediaItem).Metadata) + .ThenInclude(m => (m as Episode).EpisodeMetadata) .Filter(i => i.PlayoutId == playoutId) .ToListAsync(); diff --git a/ErsatzTV.Infrastructure/Data/Repositories/ProgramScheduleRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/ProgramScheduleRepository.cs index 315abeaac..170b46685 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/ProgramScheduleRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/ProgramScheduleRepository.cs @@ -37,7 +37,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories { _dbContext.ProgramSchedules.Update(programSchedule); await _dbContext.SaveChangesAsync(); - await _dbContext.Entry(programSchedule).Collection(s => s.Items).Query().Include(i => i.MediaCollection) + await _dbContext.Entry(programSchedule).Collection(s => s.Items).Query().Include(i => i.Collection) .LoadAsync(); await _dbContext.Entry(programSchedule).Collection(s => s.Playouts).LoadAsync(); } @@ -57,12 +57,13 @@ namespace ErsatzTV.Infrastructure.Data.Repositories { await _dbContext.Entry(programSchedule).Collection(s => s.Items).LoadAsync(); await _dbContext.Entry(programSchedule).Collection(s => s.Items).Query() - .Include(i => i.MediaCollection) - .Include(i => i.TelevisionShow) - .ThenInclude(s => s.Metadata) - .Include(i => i.TelevisionSeason) - .ThenInclude(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) + .Include(i => i.Collection) + .Include(i => i.MediaItem) + .ThenInclude(i => (i as Movie).MovieMetadata) + .Include(i => i.MediaItem) + .ThenInclude(i => (i as Episode).EpisodeMetadata) + .Include(i => i.MediaItem) + .ThenInclude(i => (i as Show).ShowMetadata) .LoadAsync(); return programSchedule.Items; }).Sequence(); diff --git a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs index 031890d2c..bafcf8c8f 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; -using Dapper; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; @@ -24,171 +23,152 @@ namespace ErsatzTV.Infrastructure.Data.Repositories _dbConnection = dbConnection; } - public async Task Update(TelevisionShow show) + public async Task Update(Show show) { - _dbContext.TelevisionShows.Update(show); + _dbContext.Shows.Update(show); return await _dbContext.SaveChangesAsync() > 0; } - public async Task Update(TelevisionSeason season) + public async Task Update(Season season) { - _dbContext.TelevisionSeasons.Update(season); + _dbContext.Seasons.Update(season); return await _dbContext.SaveChangesAsync() > 0; } - public async Task Update(TelevisionEpisodeMediaItem episode) + public async Task Update(Episode episode) { - _dbContext.TelevisionEpisodeMediaItems.Update(episode); + _dbContext.Episodes.Update(episode); return await _dbContext.SaveChangesAsync() > 0; } - public Task> GetAllShows() => - _dbContext.TelevisionShows + public Task> GetAllShows() => + _dbContext.Shows .AsNoTracking() - .Include(s => s.Metadata) + .Include(s => s.ShowMetadata) .ToListAsync(); - public Task> GetShow(int televisionShowId) => - _dbContext.TelevisionShows + public Task> GetShow(int televisionShowId) => + _dbContext.Shows .AsNoTracking() .Filter(s => s.Id == televisionShowId) - .Include(s => s.Metadata) + .Include(s => s.ShowMetadata) .SingleOrDefaultAsync() .Map(Optional); public Task GetShowCount() => - _dbContext.TelevisionShows + _dbContext.Shows .AsNoTracking() .CountAsync(); - public Task> GetPagedShows(int pageNumber, int pageSize) => - _dbContext.TelevisionShows + public Task> GetPagedShows(int pageNumber, int pageSize) => + // TODO: fix this + new List().AsTask(); + // _dbContext.ShowMetadata + // .AsNoTracking() + // .Include(s => s.Show) + // .OrderBy(s => s.Metadata == null ? string.Empty : s.Metadata.SortTitle) + // .Skip((pageNumber - 1) * pageSize) + // .Take(pageSize) + // .ToListAsync(); + + public Task> GetAllSeasons() => + _dbContext.Seasons .AsNoTracking() - .Include(s => s.Metadata) - .OrderBy(s => s.Metadata == null ? string.Empty : s.Metadata.SortTitle) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) - .ToListAsync(); - - public Task> GetAllSeasons() => - _dbContext.TelevisionSeasons - .AsNoTracking() - .Include(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) + .Include(s => s.Show) + .ThenInclude(s => s.ShowMetadata) .ToListAsync(); - public Task> GetSeason(int televisionSeasonId) => - _dbContext.TelevisionSeasons + public Task> GetSeason(int televisionSeasonId) => + _dbContext.Seasons .AsNoTracking() - .Include(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) + .Include(s => s.Show) + .ThenInclude(s => s.ShowMetadata) .SingleOrDefaultAsync(s => s.Id == televisionSeasonId) .Map(Optional); public Task GetSeasonCount(int televisionShowId) => - _dbContext.TelevisionSeasons + _dbContext.Seasons .AsNoTracking() - .Where(s => s.TelevisionShowId == televisionShowId) + .Where(s => s.ShowId == televisionShowId) .CountAsync(); - public Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize) => - _dbContext.TelevisionSeasons + public Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize) => + _dbContext.Seasons .AsNoTracking() - .Where(s => s.TelevisionShowId == televisionShowId) - .Include(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) - .OrderBy(s => s.Number) + .Where(s => s.ShowId == televisionShowId) + .Include(s => s.Show) + .ThenInclude(s => s.ShowMetadata) + .OrderBy(s => s.SeasonNumber) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .ToListAsync(); - public Task> GetEpisode(int televisionEpisodeId) => - _dbContext.TelevisionEpisodeMediaItems + public Task> GetEpisode(int televisionEpisodeId) => + _dbContext.Episodes .AsNoTracking() - .Include(s => s.Season) - .Include(s => s.Metadata) + .Include(e => e.Season) + .Include(e => e.EpisodeMetadata) .SingleOrDefaultAsync(s => s.Id == televisionEpisodeId) .Map(Optional); public Task GetEpisodeCount(int televisionSeasonId) => - _dbContext.TelevisionEpisodeMediaItems + _dbContext.Episodes .AsNoTracking() .Where(e => e.SeasonId == televisionSeasonId) .CountAsync(); - public Task> GetPagedEpisodes( + public Task> GetPagedEpisodes( int televisionSeasonId, int pageNumber, int pageSize) => - _dbContext.TelevisionEpisodeMediaItems - .AsNoTracking() - .Include(e => e.Metadata) - .Include(e => e.Season) - .ThenInclude(s => s.TelevisionShow) - .ThenInclude(s => s.Metadata) - .Where(e => e.SeasonId == televisionSeasonId) - .OrderBy(s => s.Metadata.Episode) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) - .ToListAsync(); - - // TODO: lookup by library path id, not media source id - public async Task> GetShowByPath(int mediaSourceId, string path) + // TODO: fix this + new List().AsTask(); + // _dbContext.EpisodeMetadata + // .AsNoTracking() + // .Include(e => e.Metadata) + // .Include(e => e.Season) + // .ThenInclude(s => s.TelevisionShow) + // .ThenInclude(s => s.Metadata) + // .Where(e => e.SeasonId == televisionSeasonId) + // .OrderBy(s => s.Metadata.Episode) + // .Skip((pageNumber - 1) * pageSize) + // .Take(pageSize) + // .ToListAsync(); + + public async Task> GetShowByMetadata(ShowMetadata metadata) { - Option maybeShowId = await _dbContext.LocalTelevisionShowSources - .SingleOrDefaultAsync(s => s.MediaSourceId == mediaSourceId && s.Path == path) - .Map(Optional) - .MapT(s => s.TelevisionShowId); - - return await maybeShowId.Match>>( - async id => await _dbContext.TelevisionShows - .Include(s => s.Metadata) - .Include(s => s.Sources) - .SingleOrDefaultAsync(s => s.Id == id), - () => Task.FromResult(Option.None)); - } - - public async Task> GetShowByMetadata(TelevisionShowMetadata metadata) - { - Option maybeShow = await _dbContext.TelevisionShows - .Include(s => s.Metadata) - .Where(s => s.Metadata.Title == metadata.Title && s.Metadata.Year == metadata.Year) + Option maybeId = await _dbContext.ShowMetadata + .Where(s => s.Title == metadata.Title && s.ReleaseDate == metadata.ReleaseDate) .SingleOrDefaultAsync() + .Map(sm => sm.ShowId) .Map(Optional); - await maybeShow.IfSomeAsync( - async show => + return await maybeId.Match( + id => { - await _dbContext.Entry(show).Reference(s => s.Metadata).LoadAsync(); - await _dbContext.Entry(show).Collection(s => s.Sources).LoadAsync(); - }); - - return maybeShow; + return _dbContext.Shows + .Include(s => s.ShowMetadata) + .Filter(s => s.Id == id) + .SingleOrDefaultAsync() + .Map(Optional); + }, + () => Option.None.AsTask()); } - public async Task> AddShow( + public async Task> AddShow( int localMediaSourceId, string showFolder, - TelevisionShowMetadata metadata) + ShowMetadata metadata) { try { - var show = new TelevisionShow + var show = new Show { - Sources = new List(), - Metadata = metadata, - Seasons = new List() + ShowMetadata = new List { metadata }, + Seasons = new List() }; - show.Sources.Add( - new LocalTelevisionShowSource - { - MediaSourceId = localMediaSourceId, - Path = showFolder, - TelevisionShow = show - }); - - await _dbContext.TelevisionShows.AddAsync(show); + await _dbContext.Shows.AddAsync(show); await _dbContext.SaveChangesAsync(); return show; @@ -199,123 +179,111 @@ namespace ErsatzTV.Infrastructure.Data.Repositories } } - public async Task> GetOrAddSeason( - TelevisionShow show, + public async Task> GetOrAddSeason( + Show show, string path, int seasonNumber) { - Option maybeExisting = await _dbContext.TelevisionSeasons + Option maybeExisting = await _dbContext.Seasons .SingleOrDefaultAsync(i => i.Path == path); return await maybeExisting.Match( - season => Right(season).AsTask(), + season => Right(season).AsTask(), () => AddSeason(show, path, seasonNumber)); } // TODO: don't use mediaSourceId, use library path id - public async Task> GetOrAddEpisode( - TelevisionSeason season, + public async Task> GetOrAddEpisode( + Season season, LibraryPath libraryPath, string path) { - Option maybeExisting = await _dbContext.TelevisionEpisodeMediaItems - .Include(i => i.Metadata) + Option maybeExisting = await _dbContext.Episodes + .Include(i => i.EpisodeMetadata) .Include(i => i.Statistics) .SingleOrDefaultAsync(i => i.Path == path); return await maybeExisting.Match( - episode => Right(episode).AsTask(), + episode => Right(episode).AsTask(), () => AddEpisode(season, libraryPath.Id, path)); } - public Task DeleteMissingSources(int localMediaSourceId, List allFolders) => - _dbContext.LocalTelevisionShowSources - .Where(s => s.MediaSourceId == localMediaSourceId && !allFolders.Contains(s.Path)) - .ToListAsync() - .Bind( - list => - { - _dbContext.LocalTelevisionShowSources.RemoveRange(list); - return _dbContext.SaveChangesAsync(); - }) - .ToUnit(); - public Task DeleteEmptyShows() => - _dbContext.TelevisionShows - .Where(s => s.Sources.Count == 0) + _dbContext.Shows + .Where(s => s.Seasons.Count == 0) .ToListAsync() .Bind( list => { - _dbContext.TelevisionShows.RemoveRange(list); + _dbContext.Shows.RemoveRange(list); return _dbContext.SaveChangesAsync(); }) .ToUnit(); - public async Task> GetShowItems(int televisionShowId) - { - var parameters = new { ShowId = televisionShowId }; - return await _dbConnection - .QueryAsync( - @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, -mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, -mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, -tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle -from TelevisionEpisode tmi -inner join MediaItem mi on tmi.Id = mi.Id -inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id -inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId -inner join TelevisionShow ts on ts.Id = tsn.TelevisionShowId -where ts.Id = @ShowId", - (episode, statistics, metadata) => - { - episode.Statistics = statistics; - episode.Metadata = metadata; - return episode; - }, - parameters, - splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); - } - - public async Task> GetSeasonItems(int televisionSeasonId) - { - var parameters = new { SeasonId = televisionSeasonId }; - return await _dbConnection - .QueryAsync( - @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, -mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, -mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, -tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle -from TelevisionEpisode tmi -inner join MediaItem mi on tmi.Id = mi.Id -inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id -inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId -where tsn.Id = @SeasonId", - (episode, statistics, metadata) => - { - episode.Statistics = statistics; - episode.Metadata = metadata; - return episode; - }, - parameters, - splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); - } - - private async Task> AddSeason( - TelevisionShow show, + public async Task> GetShowItems(int televisionShowId) => + // TODO: fix this + new(); + + // var parameters = new { ShowId = televisionShowId }; + // return await _dbConnection + // .QueryAsync( + // @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, + // mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, + // mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, + // tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle + // from TelevisionEpisode tmi + // inner join MediaItem mi on tmi.Id = mi.Id + // inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id + // inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId + // inner join TelevisionShow ts on ts.Id = tsn.TelevisionShowId + // where ts.Id = @ShowId", + // (episode, statistics, metadata) => + // { + // episode.Statistics = statistics; + // episode.Metadata = metadata; + // return episode; + // }, + // parameters, + // splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); + public async Task> GetSeasonItems(int televisionSeasonId) => + // TODO: fix this + new(); + + // var parameters = new { SeasonId = televisionSeasonId }; + // return await _dbConnection + // .QueryAsync( + // @"select tmi.Id, tmi.SeasonId, mi.LibraryPathId, mi.LastWriteTime, mi.Path, mi.Poster, mi.PosterLastWriteTime, + // mi.Statistics_AudioCodec as AudioCodec, mi.Statistics_DisplayAspectRatio as DisplayAspectRatio, mi.Statistics_Duration as Duration, mi.Statistics_Height as Height, mi.Statistics_LastWriteTime as LastWriteTime, mi.Statistics_SampleAspectRatio as SampleAspectRatio, + // mi.Statistics_VideoCodec as VideoCodec, mi.Statistics_VideoScanType as VideoScanType, mi.Statistics_Width as Width, + // tem.TelevisionEpisodeId, tem.Id, tem.Season, tem.Episode, tem.Plot, tem.Aired, tem.Source, tem.LastWriteTime, tem.Title, tem.SortTitle + // from TelevisionEpisode tmi + // inner join MediaItem mi on tmi.Id = mi.Id + // inner join TelevisionEpisodeMetadata tem on tem.TelevisionEpisodeId = tmi.Id + // inner join TelevisionSeason tsn on tsn.Id = tmi.SeasonId + // where tsn.Id = @SeasonId", + // (episode, statistics, metadata) => + // { + // episode.Statistics = statistics; + // episode.Metadata = metadata; + // return episode; + // }, + // parameters, + // splitOn: "AudioCodec,TelevisionEpisodeId").Map(result => result.ToList()); + private async Task> AddSeason( + Show show, string path, int seasonNumber) { try { - var season = new TelevisionSeason + var season = new Season { - TelevisionShowId = show.Id, Path = path, Number = seasonNumber, - Episodes = new List() + ShowId = show.Id, Path = path, SeasonNumber = seasonNumber, + Episodes = new List() }; - await _dbContext.TelevisionSeasons.AddAsync(season); + await _dbContext.Seasons.AddAsync(season); await _dbContext.SaveChangesAsync(); return season; } @@ -325,20 +293,20 @@ where tsn.Id = @SeasonId", } } - private async Task> AddEpisode( - TelevisionSeason season, + private async Task> AddEpisode( + Season season, int mediaSourceId, string path) { try { - var episode = new TelevisionEpisodeMediaItem + var episode = new Episode { LibraryPathId = mediaSourceId, SeasonId = season.Id, Path = path }; - await _dbContext.TelevisionEpisodeMediaItems.AddAsync(episode); + await _dbContext.Episodes.AddAsync(episode); await _dbContext.SaveChangesAsync(); return episode; } diff --git a/ErsatzTV.Infrastructure/Data/TvContext.cs b/ErsatzTV.Infrastructure/Data/TvContext.cs index f105488aa..f9661c8e8 100644 --- a/ErsatzTV.Infrastructure/Data/TvContext.cs +++ b/ErsatzTV.Infrastructure/Data/TvContext.cs @@ -23,22 +23,17 @@ namespace ErsatzTV.Infrastructure.Data public DbSet Movies { get; set; } public DbSet MovieMetadata { get; set; } public DbSet Shows { get; set; } + public DbSet ShowMetadata { get; set; } public DbSet Seasons { get; set; } public DbSet Episodes { get; set; } public DbSet PlexMovieMediaItems { get; set; } - public DbSet TelevisionEpisodeMediaItems { get; set; } - public DbSet MediaCollections { get; set; } - public DbSet SimpleMediaCollections { get; set; } + public DbSet Collections { get; set; } public DbSet ProgramSchedules { get; set; } public DbSet Playouts { get; set; } public DbSet PlayoutItems { get; set; } public DbSet PlayoutProgramScheduleItemAnchors { get; set; } public DbSet FFmpegProfiles { get; set; } public DbSet Resolutions { get; set; } - public DbSet TelevisionShows { get; set; } - public DbSet LocalTelevisionShowSources { get; set; } - public DbSet TelevisionShowMetadata { get; set; } - public DbSet TelevisionSeasons { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseLoggerFactory(_loggerFactory); diff --git a/ErsatzTV/Controllers/Api/MediaCollectionsController.cs b/ErsatzTV/Controllers/Api/MediaCollectionsController.cs index 5c2e6c1c1..a45f5f95b 100644 --- a/ErsatzTV/Controllers/Api/MediaCollectionsController.cs +++ b/ErsatzTV/Controllers/Api/MediaCollectionsController.cs @@ -25,24 +25,24 @@ namespace ErsatzTV.Controllers.Api [ProducesResponseType(400)] public Task Add( [Required] [FromBody] - CreateSimpleMediaCollection createCollection) => + CreateCollection createCollection) => _mediator.Send(createCollection).ToActionResult(); [HttpGet] [ProducesResponseType(typeof(IEnumerable), 200)] public Task GetAll() => - _mediator.Send(new GetAllMediaCollections()).ToActionResult(); + _mediator.Send(new GetAllCollections()).ToActionResult(); [HttpGet("{id}")] [ProducesResponseType(typeof(MediaCollectionViewModel), 200)] [ProducesResponseType(404)] public Task Get(int id) => - _mediator.Send(new GetSimpleMediaCollectionById(id)).ToActionResult(); + _mediator.Send(new GetCollectionById(id)).ToActionResult(); [HttpGet("{id}/items")] [ProducesResponseType(typeof(IEnumerable), 200)] [ProducesResponseType(404)] public Task GetItems(int id) => - _mediator.Send(new GetSimpleMediaCollectionItems(id)).ToActionResult(); + _mediator.Send(new GetCollectionItems(id)).ToActionResult(); } } diff --git a/ErsatzTV/Pages/MediaCollectionEditor.razor b/ErsatzTV/Pages/MediaCollectionEditor.razor index ca417b1bd..fa08b7227 100644 --- a/ErsatzTV/Pages/MediaCollectionEditor.razor +++ b/ErsatzTV/Pages/MediaCollectionEditor.razor @@ -39,7 +39,7 @@ { if (IsEdit) { - Option maybeCollection = await Mediator.Send(new GetSimpleMediaCollectionById(Id)); + Option maybeCollection = await Mediator.Send(new GetCollectionById(Id)); maybeCollection.IfSome(collection => { _model.Id = collection.Id; @@ -66,8 +66,8 @@ if (_editContext.Validate()) { Seq errorMessage = IsEdit ? - (await Mediator.Send(new UpdateSimpleMediaCollection(Id, _model.Name))).LeftToSeq() : - (await Mediator.Send(new CreateSimpleMediaCollection(_model.Name))).LeftToSeq(); + (await Mediator.Send(new UpdateCollection(Id, _model.Name))).LeftToSeq() : + (await Mediator.Send(new CreateCollection(_model.Name))).LeftToSeq(); errorMessage.HeadOrNone().Match( error => diff --git a/ErsatzTV/Pages/MediaCollectionItems.razor b/ErsatzTV/Pages/MediaCollectionItems.razor index a5f5569ab..c4a3e3c71 100644 --- a/ErsatzTV/Pages/MediaCollectionItems.razor +++ b/ErsatzTV/Pages/MediaCollectionItems.razor @@ -82,14 +82,14 @@ [Parameter] public int Id { get; set; } - private SimpleMediaCollectionCardResultsViewModel _data; + private CollectionCardResultsViewModel _data; protected override async Task OnParametersSetAsync() => await RefreshData(); private async Task RefreshData() { - Either maybeResult = - await Mediator.Send(new GetSimpleMediaCollectionCards(Id)); + Either maybeResult = + await Mediator.Send(new GetCollectionCards(Id)); maybeResult.Match( result => _data = result, @@ -100,9 +100,9 @@ { if (vm is MovieCardViewModel movie) { - var request = new RemoveItemsFromSimpleMediaCollection(Id) + var request = new RemoveItemsFromCollection(Id) { - MovieIds = new List { movie.MovieId } + MediaItemIds = new List { movie.MovieId } }; await RemoveItemsWithConfirmation("movie", $"{movie.Title} ({movie.Subtitle})", request); @@ -113,9 +113,9 @@ { if (vm is TelevisionShowCardViewModel show) { - var request = new RemoveItemsFromSimpleMediaCollection(Id) + var request = new RemoveItemsFromCollection(Id) { - TelevisionShowIds = new List { show.TelevisionShowId } + MediaItemIds = new List { show.TelevisionShowId } }; await RemoveItemsWithConfirmation("show", $"{show.Title} ({show.Subtitle})", request); @@ -126,9 +126,9 @@ { if (vm is TelevisionSeasonCardViewModel season) { - var request = new RemoveItemsFromSimpleMediaCollection(Id) + var request = new RemoveItemsFromCollection(Id) { - TelevisionSeasonIds = new List { season.TelevisionSeasonId } + MediaItemIds = new List { season.TelevisionSeasonId } }; await RemoveItemsWithConfirmation("season", $"{season.ShowTitle} - {season.Title}", request); @@ -139,9 +139,9 @@ { if (vm is TelevisionEpisodeCardViewModel episode) { - var request = new RemoveItemsFromSimpleMediaCollection(Id) + var request = new RemoveItemsFromCollection(Id) { - TelevisionEpisodeIds = new List { episode.EpisodeId } + MediaItemIds = new List { episode.EpisodeId } }; await RemoveItemsWithConfirmation("episode", $"{episode.ShowTitle} - {episode.Title}", request); @@ -151,7 +151,7 @@ private async Task RemoveItemsWithConfirmation( string entityType, string entityName, - RemoveItemsFromSimpleMediaCollection request) + RemoveItemsFromCollection request) { var parameters = new DialogParameters { { "EntityType", entityType }, { "EntityName", entityName } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; diff --git a/ErsatzTV/Pages/MediaCollections.razor b/ErsatzTV/Pages/MediaCollections.razor index c1c43bfb3..6510f815d 100644 --- a/ErsatzTV/Pages/MediaCollections.razor +++ b/ErsatzTV/Pages/MediaCollections.razor @@ -29,7 +29,7 @@ protected override Task OnParametersSetAsync() => RefreshData(); private async Task RefreshData() => - _data = await Mediator.Send(new GetAllMediaCollections()); + _data = await Mediator.Send(new GetAllCollections()); private async Task DeleteMediaCollection(MediaCardViewModel vm) { @@ -42,7 +42,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled) { - await Mediator.Send(new DeleteSimpleMediaCollection(collection.Id)); + await Mediator.Send(new DeleteCollection(collection.Id)); await RefreshData(); } } diff --git a/ErsatzTV/Pages/Movie.razor b/ErsatzTV/Pages/Movie.razor index 3004229c3..77c58be69 100644 --- a/ErsatzTV/Pages/Movie.razor +++ b/ErsatzTV/Pages/Movie.razor @@ -68,7 +68,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) { - await Mediator.Send(new AddMovieToSimpleMediaCollection(collection.Id, MovieId)); + await Mediator.Send(new AddMovieToCollection(collection.Id, MovieId)); NavigationManager.NavigateTo($"/media/collections/{collection.Id}"); } } diff --git a/ErsatzTV/Pages/ScheduleItemsEditor.razor b/ErsatzTV/Pages/ScheduleItemsEditor.razor index ceb6319e2..6bb7cd389 100644 --- a/ErsatzTV/Pages/ScheduleItemsEditor.razor +++ b/ErsatzTV/Pages/ScheduleItemsEditor.razor @@ -105,7 +105,7 @@ } @@ -160,7 +160,7 @@ private async Task LoadScheduleItems() { - _mediaCollections = await Mediator.Send(new GetAllMediaCollections()); + _mediaCollections = await Mediator.Send(new GetAllCollections()); _televisionShows = await Mediator.Send(new GetAllTelevisionShows()); _televisionSeasons = await Mediator.Send(new GetAllTelevisionSeasons()); @@ -186,7 +186,7 @@ StartTime = item.StartTime, PlayoutMode = item.PlayoutMode, CollectionType = item.CollectionType, - MediaCollection = item.MediaCollection, + Collection = item.Collection, TelevisionShow = item.TelevisionShow, TelevisionSeason = item.TelevisionSeason }; @@ -254,28 +254,28 @@ private async Task SaveChanges() { - var items = _schedule.Items.Map(item => new ReplaceProgramScheduleItem( - item.Index, - item.StartType, - item.StartTime, - item.PlayoutMode, - item.CollectionType, - item.MediaCollection?.Id, - item.TelevisionShow?.Id, - item.TelevisionSeason?.Id, - item.MultipleCount, - item.PlayoutDuration, - item.PlayoutMode == PlayoutMode.Duration ? item.OfflineTail.IfNone(false) : null)).ToList(); - - Seq errorMessages = await Mediator.Send(new ReplaceProgramScheduleItems(Id, items)).Map(e => e.LeftToSeq()); - - errorMessages.HeadOrNone().Match( - error => - { - Snackbar.Add($"Unexpected error saving schedule: {error.Value}", Severity.Error); - Logger.LogError("Unexpected error saving schedule: {Error}", error.Value); - }, - () => NavigationManager.NavigateTo("/schedules")); + // TODO: fix this + // var items = _schedule.Items.Map(item => new ReplaceProgramScheduleItem( + // item.Index, + // item.StartType, + // item.StartTime, + // item.PlayoutMode, + // item.CollectionType, + // item.Collection?.Id, + // item.MediaItem?.Id, + // item.MultipleCount, + // item.PlayoutDuration, + // item.PlayoutMode == PlayoutMode.Duration ? item.OfflineTail.IfNone(false) : null)).ToList(); + // + // Seq errorMessages = await Mediator.Send(new ReplaceProgramScheduleItems(Id, items)).Map(e => e.LeftToSeq()); + // + // errorMessages.HeadOrNone().Match( + // error => + // { + // Snackbar.Add($"Unexpected error saving schedule: {error.Value}", Severity.Error); + // Logger.LogError("Unexpected error saving schedule: {Error}", error.Value); + // }, + // () => NavigationManager.NavigateTo("/schedules")); } } \ No newline at end of file diff --git a/ErsatzTV/Pages/TelevisionEpisode.razor b/ErsatzTV/Pages/TelevisionEpisode.razor index fbf3af3a2..5ad2d52d4 100644 --- a/ErsatzTV/Pages/TelevisionEpisode.razor +++ b/ErsatzTV/Pages/TelevisionEpisode.razor @@ -74,7 +74,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) { - await Mediator.Send(new AddTelevisionEpisodeToSimpleMediaCollection(collection.Id, EpisodeId)); + await Mediator.Send(new AddEpisodeToCollection(collection.Id, EpisodeId)); NavigationManager.NavigateTo($"/media/collections/{collection.Id}"); } } diff --git a/ErsatzTV/Pages/TelevisionEpisodeList.razor b/ErsatzTV/Pages/TelevisionEpisodeList.razor index 6425e0a89..293b0400b 100644 --- a/ErsatzTV/Pages/TelevisionEpisodeList.razor +++ b/ErsatzTV/Pages/TelevisionEpisodeList.razor @@ -99,7 +99,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) { - await Mediator.Send(new AddTelevisionSeasonToSimpleMediaCollection(collection.Id, SeasonId)); + await Mediator.Send(new AddSeasonToCollection(collection.Id, SeasonId)); NavigationManager.NavigateTo($"/media/collections/{collection.Id}"); } } @@ -114,7 +114,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) { - await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, SeasonId, null, null, null)); + await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, SeasonId, null, null, null)); NavigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); } } diff --git a/ErsatzTV/Pages/TelevisionSeasonList.razor b/ErsatzTV/Pages/TelevisionSeasonList.razor index e7b11e38b..acf0e9c97 100644 --- a/ErsatzTV/Pages/TelevisionSeasonList.razor +++ b/ErsatzTV/Pages/TelevisionSeasonList.razor @@ -95,7 +95,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) { - await Mediator.Send(new AddTelevisionShowToSimpleMediaCollection(collection.Id, ShowId)); + await Mediator.Send(new AddShowToCollection(collection.Id, ShowId)); NavigationManager.NavigateTo($"/media/collections/{collection.Id}"); } } @@ -109,7 +109,7 @@ DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) { - await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, ShowId, null, null, null, null)); + await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, ShowId, null, null, null)); NavigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); } } diff --git a/ErsatzTV/Shared/AddToCollectionDialog.razor b/ErsatzTV/Shared/AddToCollectionDialog.razor index b76f9d3e9..042fea0f3 100644 --- a/ErsatzTV/Shared/AddToCollectionDialog.razor +++ b/ErsatzTV/Shared/AddToCollectionDialog.razor @@ -47,7 +47,7 @@ private MediaCollectionViewModel _selectedCollection; protected override async Task OnParametersSetAsync() => - _collections = await Mediator.Send(new GetAllSimpleMediaCollections()); + _collections = await Mediator.Send(new GetAllCollections()); private string FormatText() => $"Select the collection to add the {EntityType} {EntityName}"; diff --git a/ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs b/ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs index df6763558..016955798 100644 --- a/ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs +++ b/ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs @@ -42,28 +42,28 @@ namespace ErsatzTV.ViewModels TelevisionSeason = null; break; case ProgramScheduleItemCollectionType.TelevisionShow: - MediaCollection = null; + Collection = null; TelevisionSeason = null; break; case ProgramScheduleItemCollectionType.TelevisionSeason: - MediaCollection = null; + Collection = null; TelevisionShow = null; break; } - OnPropertyChanged(nameof(MediaCollection)); + OnPropertyChanged(nameof(Collection)); OnPropertyChanged(nameof(TelevisionShow)); OnPropertyChanged(nameof(TelevisionSeason)); } } - public MediaCollectionViewModel MediaCollection { get; set; } + public MediaCollectionViewModel Collection { get; set; } public TelevisionShowViewModel TelevisionShow { get; set; } public TelevisionSeasonViewModel TelevisionSeason { get; set; } public string CollectionName => CollectionType switch { - ProgramScheduleItemCollectionType.Collection => MediaCollection?.Name, + ProgramScheduleItemCollectionType.Collection => Collection?.Name, ProgramScheduleItemCollectionType.TelevisionShow => $"{TelevisionShow?.Title} ({TelevisionShow?.Year})", ProgramScheduleItemCollectionType.TelevisionSeason => $"{TelevisionSeason?.Title} ({TelevisionSeason?.Plot})",