rework television media (#26)
* rework television media * refactor poster saving * television and movie views are working again * remove dead code * use paper styling for all cards * add show poster, plot to seasons page * remove missing shows; cleanup interfaces * fix split show display (same show in different folders/sources) * add placeholder "add to schedule" button * no more duplicate television shows, even with the same show split across sources * stop releasing CLI for now * use season number as season placeholder * add television shows to collections * add television seasons to collections * add television episodes to collections * add movies to collections * remove movies, shows, seasons, episodes from collections * fix page width and menus * fix buffer size defaults * fix chronological episode ordering * allow deleting media collections * don't get stuck building a playout with an empty collection * schedule editing and playouts work again * minor cleanup * remove dead code * fix bugs with viewing movies as they are loading * add scanner tests; support nested movie folders * update collections docs * rearrange order of schedule items * add show and season to schedule * delete schedules that use legacy collections, reset all posters * move cleanup to new migration * load fallback metadata when nfo fails; don't require metadata in ui * update readme and screenshots
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record AddItemsToSimpleMediaCollection
|
||||
(int MediaCollectionId, List<int> ItemIds) : MediatR.IRequest<Either<BaseError, Unit>>;
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using static LanguageExt.Prelude;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public class
|
||||
AddItemsToSimpleMediaCollectionHandler : MediatR.IRequestHandler<AddItemsToSimpleMediaCollection,
|
||||
Either<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly IMediaItemRepository _mediaItemRepository;
|
||||
|
||||
public AddItemsToSimpleMediaCollectionHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
IMediaItemRepository mediaItemRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_mediaItemRepository = mediaItemRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
AddItemsToSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(ApplyAddItemsRequest)
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<Unit> ApplyAddItemsRequest(RequestParameters parameters)
|
||||
{
|
||||
foreach (MediaItem item in parameters.ItemsToAdd.Where(
|
||||
item => parameters.Collection.Items.All(i => i.Id != item.Id)))
|
||||
{
|
||||
parameters.Collection.Items.Add(item);
|
||||
}
|
||||
|
||||
await _mediaCollectionRepository.Update(parameters.Collection);
|
||||
|
||||
return Unit.Default;
|
||||
}
|
||||
|
||||
private async Task<Validation<BaseError, RequestParameters>>
|
||||
Validate(AddItemsToSimpleMediaCollection request) =>
|
||||
(await SimpleMediaCollectionMustExist(request), await ValidateItems(request))
|
||||
.Apply(
|
||||
(simpleMediaCollectionToUpdate, itemsToAdd) =>
|
||||
new RequestParameters(simpleMediaCollectionToUpdate, itemsToAdd));
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
AddItemsToSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollection(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
|
||||
private Task<Validation<BaseError, List<MediaItem>>> ValidateItems(
|
||||
AddItemsToSimpleMediaCollection request) =>
|
||||
LoadAllMediaItems(request)
|
||||
.Map(v => v.ToValidation<BaseError>("MediaItem does not exist"));
|
||||
|
||||
private async Task<Option<List<MediaItem>>> LoadAllMediaItems(AddItemsToSimpleMediaCollection request)
|
||||
{
|
||||
var items = (await request.ItemIds.Map(async id => await _mediaItemRepository.Get(id)).Sequence())
|
||||
.ToList();
|
||||
if (items.Any(i => i.IsNone))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
return items.Somes().ToList();
|
||||
}
|
||||
|
||||
private record RequestParameters(SimpleMediaCollection Collection, List<MediaItem> ItemsToAdd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record AddMovieToSimpleMediaCollection
|
||||
(int MediaCollectionId, int MovieId) : MediatR.IRequest<Either<BaseError, Unit>>;
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
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
|
||||
AddMovieToSimpleMediaCollectionHandler : MediatR.IRequestHandler<AddMovieToSimpleMediaCollection,
|
||||
Either<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly IMovieRepository _movieRepository;
|
||||
|
||||
public AddMovieToSimpleMediaCollectionHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
IMovieRepository movieRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_movieRepository = movieRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
AddMovieToSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(ApplyAddMoviesRequest)
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<Unit> ApplyAddMoviesRequest(RequestParameters parameters)
|
||||
{
|
||||
parameters.Collection.Movies.Add(parameters.MovieToAdd);
|
||||
await _mediaCollectionRepository.Update(parameters.Collection);
|
||||
|
||||
return Unit.Default;
|
||||
}
|
||||
|
||||
private async Task<Validation<BaseError, RequestParameters>>
|
||||
Validate(AddMovieToSimpleMediaCollection request) =>
|
||||
(await SimpleMediaCollectionMustExist(request), await ValidateMovies(request))
|
||||
.Apply(
|
||||
(simpleMediaCollectionToUpdate, movieToAdd) =>
|
||||
new RequestParameters(simpleMediaCollectionToUpdate, movieToAdd));
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
AddMovieToSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
|
||||
private Task<Validation<BaseError, MovieMediaItem>> ValidateMovies(
|
||||
AddMovieToSimpleMediaCollection request) =>
|
||||
LoadMovie(request)
|
||||
.Map(v => v.ToValidation<BaseError>("MovieMediaItem does not exist"));
|
||||
|
||||
private Task<Option<MovieMediaItem>> LoadMovie(AddMovieToSimpleMediaCollection request) =>
|
||||
_movieRepository.GetMovie(request.MovieId);
|
||||
|
||||
private record RequestParameters(SimpleMediaCollection Collection, MovieMediaItem MovieToAdd);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record AddTelevisionEpisodeToSimpleMediaCollection
|
||||
(int MediaCollectionId, int TelevisionEpisodeId) : MediatR.IRequest<Either<BaseError, Unit>>;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
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<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly ITelevisionRepository _televisionRepository;
|
||||
|
||||
public AddTelevisionEpisodeToSimpleMediaCollectionHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
ITelevisionRepository televisionRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_televisionRepository = televisionRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
AddTelevisionEpisodeToSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(ApplyAddTelevisionEpisodeRequest)
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<Unit> 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<Validation<BaseError, RequestParameters>>
|
||||
Validate(AddTelevisionEpisodeToSimpleMediaCollection request) =>
|
||||
(await SimpleMediaCollectionMustExist(request), await ValidateEpisode(request))
|
||||
.Apply(
|
||||
(simpleMediaCollectionToUpdate, episode) =>
|
||||
new RequestParameters(simpleMediaCollectionToUpdate, episode));
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
AddTelevisionEpisodeToSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
|
||||
private Task<Validation<BaseError, TelevisionEpisodeMediaItem>> ValidateEpisode(
|
||||
AddTelevisionEpisodeToSimpleMediaCollection request) =>
|
||||
LoadTelevisionEpisode(request)
|
||||
.Map(v => v.ToValidation<BaseError>("TelevisionEpisode does not exist"));
|
||||
|
||||
private Task<Option<TelevisionEpisodeMediaItem>> LoadTelevisionEpisode(
|
||||
AddTelevisionEpisodeToSimpleMediaCollection request) =>
|
||||
_televisionRepository.GetEpisode(request.TelevisionEpisodeId);
|
||||
|
||||
private record RequestParameters(SimpleMediaCollection Collection, TelevisionEpisodeMediaItem EpisodeToAdd);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record AddTelevisionSeasonToSimpleMediaCollection
|
||||
(int MediaCollectionId, int TelevisionSeasonId) : MediatR.IRequest<Either<BaseError, Unit>>;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
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<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly ITelevisionRepository _televisionRepository;
|
||||
|
||||
public AddTelevisionSeasonToSimpleMediaCollectionHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
ITelevisionRepository televisionRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_televisionRepository = televisionRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
AddTelevisionSeasonToSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(ApplyAddTelevisionSeasonRequest)
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<Unit> 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<Validation<BaseError, RequestParameters>>
|
||||
Validate(AddTelevisionSeasonToSimpleMediaCollection request) =>
|
||||
(await SimpleMediaCollectionMustExist(request), await ValidateSeason(request))
|
||||
.Apply(
|
||||
(simpleMediaCollectionToUpdate, season) =>
|
||||
new RequestParameters(simpleMediaCollectionToUpdate, season));
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
AddTelevisionSeasonToSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
|
||||
private Task<Validation<BaseError, TelevisionSeason>> ValidateSeason(
|
||||
AddTelevisionSeasonToSimpleMediaCollection request) =>
|
||||
LoadTelevisionSeason(request)
|
||||
.Map(v => v.ToValidation<BaseError>("TelevisionSeason does not exist"));
|
||||
|
||||
private Task<Option<TelevisionSeason>> LoadTelevisionSeason(
|
||||
AddTelevisionSeasonToSimpleMediaCollection request) =>
|
||||
_televisionRepository.GetSeason(request.TelevisionSeasonId);
|
||||
|
||||
private record RequestParameters(SimpleMediaCollection Collection, TelevisionSeason SeasonToAdd);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record AddTelevisionShowToSimpleMediaCollection
|
||||
(int MediaCollectionId, int TelevisionShowId) : MediatR.IRequest<Either<BaseError, Unit>>;
|
||||
}
|
||||
+67
@@ -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
|
||||
AddTelevisionShowToSimpleMediaCollectionHandler : MediatR.IRequestHandler<
|
||||
AddTelevisionShowToSimpleMediaCollection,
|
||||
Either<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly ITelevisionRepository _televisionRepository;
|
||||
|
||||
public AddTelevisionShowToSimpleMediaCollectionHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
ITelevisionRepository televisionRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_televisionRepository = televisionRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
AddTelevisionShowToSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(ApplyAddTelevisionShowRequest)
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<Unit> 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<Validation<BaseError, RequestParameters>>
|
||||
Validate(AddTelevisionShowToSimpleMediaCollection request) =>
|
||||
(await SimpleMediaCollectionMustExist(request), await ValidateShow(request))
|
||||
.Apply(
|
||||
(simpleMediaCollectionToUpdate, show) =>
|
||||
new RequestParameters(simpleMediaCollectionToUpdate, show));
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
AddTelevisionShowToSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
|
||||
private Task<Validation<BaseError, TelevisionShow>> ValidateShow(
|
||||
AddTelevisionShowToSimpleMediaCollection request) =>
|
||||
LoadTelevisionShow(request)
|
||||
.Map(v => v.ToValidation<BaseError>("TelevisionShow does not exist"));
|
||||
|
||||
private Task<Option<TelevisionShow>> LoadTelevisionShow(AddTelevisionShowToSimpleMediaCollection request) =>
|
||||
_televisionRepository.GetShow(request.TelevisionShowId);
|
||||
|
||||
private record RequestParameters(SimpleMediaCollection Collection, TelevisionShow ShowToAdd);
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -29,7 +29,15 @@ namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
_mediaCollectionRepository.Add(c).Map(ProjectToViewModel);
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> Validate(CreateSimpleMediaCollection request) =>
|
||||
ValidateName(request).MapT(name => new SimpleMediaCollection { Name = name });
|
||||
ValidateName(request).MapT(
|
||||
name => new SimpleMediaCollection
|
||||
{
|
||||
Name = name,
|
||||
Movies = new List<MovieMediaItem>(),
|
||||
TelevisionShows = new List<TelevisionShow>(),
|
||||
TelevisionEpisodes = new List<TelevisionEpisodeMediaItem>(),
|
||||
TelevisionSeasons = new List<TelevisionSeason>()
|
||||
});
|
||||
|
||||
private async Task<Validation<BaseError, string>> ValidateName(CreateSimpleMediaCollection createCollection)
|
||||
{
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record RemoveItemsFromSimpleMediaCollection
|
||||
(int MediaCollectionId) : MediatR.IRequest<Either<BaseError, Unit>>
|
||||
{
|
||||
public List<int> MovieIds { get; set; } = new();
|
||||
public List<int> TelevisionShowIds { get; set; } = new();
|
||||
public List<int> TelevisionSeasonIds { get; set; } = new();
|
||||
public List<int> TelevisionEpisodeIds { get; set; } = new();
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
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<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public RemoveItemsFromSimpleMediaCollectionHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
RemoveItemsFromSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(collection => ApplyAddTelevisionEpisodeRequest(request, collection))
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private Task<Unit> 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<Validation<BaseError, SimpleMediaCollection>> Validate(
|
||||
RemoveItemsFromSimpleMediaCollection request) =>
|
||||
SimpleMediaCollectionMustExist(request);
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
RemoveItemsFromSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollectionWithItems(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record ReplaceSimpleMediaCollectionItems
|
||||
(int MediaCollectionId, List<int> MediaItemIds) : IRequest<Either<BaseError, List<MediaItemViewModel>>>;
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using LanguageExt.UnsafeValueAccess;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public class ReplaceSimpleMediaCollectionItemsHandler : IRequestHandler<ReplaceSimpleMediaCollectionItems,
|
||||
Either<BaseError, List<MediaItemViewModel>>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly IMediaItemRepository _mediaItemRepository;
|
||||
|
||||
public ReplaceSimpleMediaCollectionItemsHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
IMediaItemRepository mediaItemRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_mediaItemRepository = mediaItemRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, List<MediaItemViewModel>>> Handle(
|
||||
ReplaceSimpleMediaCollectionItems request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(mediaItems => PersistItems(request, mediaItems))
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<List<MediaItemViewModel>> PersistItems(
|
||||
ReplaceSimpleMediaCollectionItems request,
|
||||
List<MediaItem> mediaItems)
|
||||
{
|
||||
await _mediaCollectionRepository.ReplaceItems(request.MediaCollectionId, mediaItems);
|
||||
return mediaItems.Map(MediaItems.Mapper.ProjectToViewModel).ToList();
|
||||
}
|
||||
|
||||
private Task<Validation<BaseError, List<MediaItem>>> Validate(ReplaceSimpleMediaCollectionItems request) =>
|
||||
MediaCollectionMustExist(request).BindT(_ => MediaItemsMustExist(request));
|
||||
|
||||
private async Task<Validation<BaseError, SimpleMediaCollection>> MediaCollectionMustExist(
|
||||
ReplaceSimpleMediaCollectionItems request) =>
|
||||
(await _mediaCollectionRepository.GetSimpleMediaCollection(request.MediaCollectionId))
|
||||
.ToValidation<BaseError>("[MediaCollectionId] does not exist.");
|
||||
|
||||
private async Task<Validation<BaseError, List<MediaItem>>> MediaItemsMustExist(
|
||||
ReplaceSimpleMediaCollectionItems replaceItems)
|
||||
{
|
||||
var allMediaItems = (await replaceItems.MediaItemIds.Map(i => _mediaItemRepository.Get(i)).Sequence())
|
||||
.ToList();
|
||||
if (allMediaItems.Any(x => x.IsNone))
|
||||
{
|
||||
return BaseError.New("[MediaItemId] does not exist");
|
||||
}
|
||||
|
||||
return allMediaItems.Sequence().ValueUnsafe().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using ErsatzTV.Core.AggregateModels;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Domain;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections
|
||||
{
|
||||
@@ -7,13 +6,5 @@ namespace ErsatzTV.Application.MediaCollections
|
||||
{
|
||||
internal static MediaCollectionViewModel ProjectToViewModel(MediaCollection mediaCollection) =>
|
||||
new(mediaCollection.Id, mediaCollection.Name);
|
||||
|
||||
internal static MediaCollectionSummaryViewModel ProjectToViewModel(
|
||||
MediaCollectionSummary mediaCollectionSummary) =>
|
||||
new(
|
||||
mediaCollectionSummary.Id,
|
||||
mediaCollectionSummary.Name,
|
||||
mediaCollectionSummary.ItemCount,
|
||||
mediaCollectionSummary.IsSimple);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
namespace ErsatzTV.Application.MediaCollections
|
||||
using ErsatzTV.Application.MediaCards;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections
|
||||
{
|
||||
public record MediaCollectionViewModel(int Id, string Name);
|
||||
public record MediaCollectionViewModel(int Id, string Name) : MediaCardViewModel(
|
||||
Name,
|
||||
string.Empty,
|
||||
Name,
|
||||
string.Empty);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetMediaCollectionSummaries(string SearchString) : IRequest<List<MediaCollectionSummaryViewModel>>;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
using static ErsatzTV.Application.MediaCollections.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class
|
||||
GetMediaCollectionSummariesHandler : IRequestHandler<GetMediaCollectionSummaries,
|
||||
List<MediaCollectionSummaryViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetMediaCollectionSummariesHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<List<MediaCollectionSummaryViewModel>> Handle(
|
||||
GetMediaCollectionSummaries request,
|
||||
CancellationToken cancellationToken) =>
|
||||
_mediaCollectionRepository.GetSummaries(request.SearchString)
|
||||
.Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetSimpleMediaCollectionWithItemsById
|
||||
(int Id) : IRequest<Option<Tuple<MediaCollectionViewModel, List<MediaItemSearchResultViewModel>>>>;
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
using static LanguageExt.Prelude;
|
||||
using static ErsatzTV.Application.MediaCollections.Mapper;
|
||||
using static ErsatzTV.Application.MediaItems.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class GetSimpleMediaCollectionWithItemsByIdHandler : IRequestHandler<GetSimpleMediaCollectionWithItemsById,
|
||||
Option<Tuple<MediaCollectionViewModel, List<MediaItemSearchResultViewModel>>>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetSimpleMediaCollectionWithItemsByIdHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public async Task<Option<Tuple<MediaCollectionViewModel, List<MediaItemSearchResultViewModel>>>> Handle(
|
||||
GetSimpleMediaCollectionWithItemsById request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Option<SimpleMediaCollection> maybeCollection =
|
||||
await _mediaCollectionRepository.GetSimpleMediaCollectionWithItems(request.Id);
|
||||
|
||||
return maybeCollection.Match<Option<Tuple<MediaCollectionViewModel, List<MediaItemSearchResultViewModel>>>>(
|
||||
c => Tuple(ProjectToViewModel(c), c.Items.Map(ProjectToSearchViewModel).ToList()),
|
||||
None);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user