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:
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ErsatzTV.Core.Domain;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
internal static class Mapper
|
||||
{
|
||||
internal static TelevisionShowCardViewModel ProjectToViewModel(TelevisionShow televisionShow) =>
|
||||
new(
|
||||
televisionShow.Id,
|
||||
televisionShow.Metadata?.Title,
|
||||
televisionShow.Metadata?.Year.ToString(),
|
||||
televisionShow.Metadata?.SortTitle,
|
||||
televisionShow.Poster);
|
||||
|
||||
internal static TelevisionSeasonCardViewModel ProjectToViewModel(TelevisionSeason televisionSeason) =>
|
||||
new(
|
||||
televisionSeason.TelevisionShow.Metadata?.Title,
|
||||
televisionSeason.Id,
|
||||
televisionSeason.Number,
|
||||
GetSeasonName(televisionSeason.Number),
|
||||
string.Empty,
|
||||
GetSeasonName(televisionSeason.Number),
|
||||
televisionSeason.Poster,
|
||||
televisionSeason.Number == 0 ? "S" : televisionSeason.Number.ToString());
|
||||
|
||||
internal static TelevisionEpisodeCardViewModel ProjectToViewModel(
|
||||
TelevisionEpisodeMediaItem televisionEpisode) =>
|
||||
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());
|
||||
|
||||
internal static MovieCardViewModel ProjectToViewModel(MovieMediaItem movie) =>
|
||||
new(
|
||||
movie.Id,
|
||||
movie.Metadata?.Title,
|
||||
movie.Metadata?.Year?.ToString(),
|
||||
movie.Metadata?.SortTitle,
|
||||
movie.Poster);
|
||||
|
||||
internal static SimpleMediaCollectionCardResultsViewModel
|
||||
ProjectToViewModel(SimpleMediaCollection collection) =>
|
||||
new(
|
||||
collection.Name,
|
||||
collection.Movies.Map(ProjectToViewModel).ToList(),
|
||||
collection.TelevisionShows.Map(ProjectToViewModel).ToList(),
|
||||
collection.TelevisionSeasons.Map(ProjectToViewModel).ToList(),
|
||||
collection.TelevisionEpisodes.Map(ProjectToViewModel).ToList());
|
||||
|
||||
private static string GetSeasonName(int number) =>
|
||||
number == 0 ? "Specials" : $"Season {number}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record MediaCardViewModel(string Title, string Subtitle, string SortTitle, string Poster);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record MovieCardResultsViewModel(int Count, List<MovieCardViewModel> Cards);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record MovieCardViewModel
|
||||
(int MovieId, string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel(
|
||||
Title,
|
||||
Subtitle,
|
||||
SortTitle,
|
||||
Poster)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public record GetMovieCards(int PageNumber, int PageSize) : IRequest<MovieCardResultsViewModel>;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
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.MediaCards.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public class
|
||||
GetMovieCardsHandler : IRequestHandler<GetMovieCards, MovieCardResultsViewModel>
|
||||
{
|
||||
private readonly IMovieRepository _movieRepository;
|
||||
|
||||
public GetMovieCardsHandler(IMovieRepository movieRepository) => _movieRepository = movieRepository;
|
||||
|
||||
public async Task<MovieCardResultsViewModel> Handle(
|
||||
GetMovieCards request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int count = await _movieRepository.GetMovieCount();
|
||||
|
||||
List<MovieCardViewModel> results = await _movieRepository
|
||||
.GetPagedMovies(request.PageNumber, request.PageSize)
|
||||
.Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
|
||||
return new MovieCardResultsViewModel(count, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public record GetSimpleMediaCollectionCards
|
||||
(int Id) : IRequest<Either<BaseError, SimpleMediaCollectionCardResultsViewModel>>;
|
||||
}
|
||||
@@ -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 GetSimpleMediaCollectionCardsHandler : IRequestHandler<GetSimpleMediaCollectionCards,
|
||||
Either<BaseError, SimpleMediaCollectionCardResultsViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetSimpleMediaCollectionCardsHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public async Task<Either<BaseError, SimpleMediaCollectionCardResultsViewModel>> Handle(
|
||||
GetSimpleMediaCollectionCards request,
|
||||
CancellationToken cancellationToken) =>
|
||||
(await _mediaCollectionRepository.GetSimpleMediaCollectionWithItemsUntracked(request.Id))
|
||||
.ToEither(BaseError.New("Unable to load collection"))
|
||||
.Map(ProjectToViewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public record GetTelevisionEpisodeCards
|
||||
(int TelevisionSeasonId, int PageNumber, int PageSize) : IRequest<TelevisionEpisodeCardResultsViewModel>;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
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.MediaCards.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public class
|
||||
GetTelevisionEpisodeCardsHandler : IRequestHandler<GetTelevisionEpisodeCards,
|
||||
TelevisionEpisodeCardResultsViewModel>
|
||||
{
|
||||
private readonly ITelevisionRepository _televisionRepository;
|
||||
|
||||
public GetTelevisionEpisodeCardsHandler(ITelevisionRepository televisionRepository) =>
|
||||
_televisionRepository = televisionRepository;
|
||||
|
||||
public async Task<TelevisionEpisodeCardResultsViewModel> Handle(
|
||||
GetTelevisionEpisodeCards request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int count = await _televisionRepository.GetEpisodeCount(request.TelevisionSeasonId);
|
||||
|
||||
List<TelevisionEpisodeCardViewModel> results = await _televisionRepository
|
||||
.GetPagedEpisodes(request.TelevisionSeasonId, request.PageNumber, request.PageSize)
|
||||
.Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
|
||||
return new TelevisionEpisodeCardResultsViewModel(count, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public record GetTelevisionSeasonCards
|
||||
(int TelevisionShowId, int PageNumber, int PageSize) : IRequest<TelevisionSeasonCardResultsViewModel>;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
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.MediaCards.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public class
|
||||
GetTelevisionSeasonCardsHandler : IRequestHandler<GetTelevisionSeasonCards, TelevisionSeasonCardResultsViewModel
|
||||
>
|
||||
{
|
||||
private readonly ITelevisionRepository _televisionRepository;
|
||||
|
||||
public GetTelevisionSeasonCardsHandler(ITelevisionRepository televisionRepository) =>
|
||||
_televisionRepository = televisionRepository;
|
||||
|
||||
public async Task<TelevisionSeasonCardResultsViewModel> Handle(
|
||||
GetTelevisionSeasonCards request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int count = await _televisionRepository.GetSeasonCount(request.TelevisionShowId);
|
||||
|
||||
List<TelevisionSeasonCardViewModel> results = await _televisionRepository
|
||||
.GetPagedSeasons(request.TelevisionShowId, request.PageNumber, request.PageSize)
|
||||
.Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
|
||||
return new TelevisionSeasonCardResultsViewModel(count, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public record GetTelevisionShowCards(int PageNumber, int PageSize) : IRequest<TelevisionShowCardResultsViewModel>;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
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.MediaCards.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards.Queries
|
||||
{
|
||||
public class
|
||||
GetTelevisionShowCardsHandler : IRequestHandler<GetTelevisionShowCards, TelevisionShowCardResultsViewModel>
|
||||
{
|
||||
private readonly ITelevisionRepository _televisionRepository;
|
||||
|
||||
public GetTelevisionShowCardsHandler(ITelevisionRepository televisionRepository) =>
|
||||
_televisionRepository = televisionRepository;
|
||||
|
||||
public async Task<TelevisionShowCardResultsViewModel> Handle(
|
||||
GetTelevisionShowCards request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int count = await _televisionRepository.GetShowCount();
|
||||
|
||||
List<TelevisionShowCardViewModel> results = await _televisionRepository
|
||||
.GetPagedShows(request.PageNumber, request.PageSize)
|
||||
.Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
|
||||
return new TelevisionShowCardResultsViewModel(count, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record SimpleMediaCollectionCardResultsViewModel(
|
||||
string Name,
|
||||
List<MovieCardViewModel> MovieCards,
|
||||
List<TelevisionShowCardViewModel> ShowCards,
|
||||
List<TelevisionSeasonCardViewModel> SeasonCards,
|
||||
List<TelevisionEpisodeCardViewModel> EpisodeCards);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record TelevisionEpisodeCardResultsViewModel(int Count, List<TelevisionEpisodeCardViewModel> Cards);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record TelevisionEpisodeCardViewModel
|
||||
(
|
||||
int EpisodeId,
|
||||
DateTime Aired,
|
||||
string ShowTitle,
|
||||
string Title,
|
||||
string Subtitle,
|
||||
string SortTitle,
|
||||
string Poster,
|
||||
string Placeholder) : MediaCardViewModel(
|
||||
Title,
|
||||
Subtitle,
|
||||
SortTitle,
|
||||
Poster)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record TelevisionSeasonCardResultsViewModel(int Count, List<TelevisionSeasonCardViewModel> Cards);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record TelevisionSeasonCardViewModel
|
||||
(
|
||||
string ShowTitle,
|
||||
int TelevisionSeasonId,
|
||||
int TelevisionSeasonNumber,
|
||||
string Title,
|
||||
string Subtitle,
|
||||
string SortTitle,
|
||||
string Poster,
|
||||
string Placeholder) : MediaCardViewModel(
|
||||
Title,
|
||||
Subtitle,
|
||||
SortTitle,
|
||||
Poster)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record TelevisionShowCardResultsViewModel(int Count, List<TelevisionShowCardViewModel> Cards);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace ErsatzTV.Application.MediaCards
|
||||
{
|
||||
public record TelevisionShowCardViewModel
|
||||
(int TelevisionShowId, string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel(
|
||||
Title,
|
||||
Subtitle,
|
||||
SortTitle,
|
||||
Poster)
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user