diff --git a/ErsatzTV.Application/MediaCards/Mapper.cs b/ErsatzTV.Application/MediaCards/Mapper.cs new file mode 100644 index 000000000..ac5dd247b --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Mapper.cs @@ -0,0 +1,34 @@ +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.Id, + GetSeasonName(televisionSeason.Number), + string.Empty, + GetSeasonName(televisionSeason.Number), + televisionSeason.Poster); + + internal static MovieCardViewModel ProjectToViewModel(MovieMediaItem movie) => + new( + movie.Id, + movie.Metadata.Title, + movie.Metadata.Year.ToString(), + movie.Metadata.SortTitle, + movie.Poster); + + private static string GetSeasonName(int number) => + number == 0 ? "Specials" : $"Season {number}"; + } +} diff --git a/ErsatzTV.Application/MediaCards/MediaCardViewModel.cs b/ErsatzTV.Application/MediaCards/MediaCardViewModel.cs new file mode 100644 index 000000000..eeb87c6a2 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/MediaCardViewModel.cs @@ -0,0 +1,4 @@ +namespace ErsatzTV.Application.MediaCards +{ + public record MediaCardViewModel(string Title, string Subtitle, string SortTitle, string Poster); +} diff --git a/ErsatzTV.Application/MediaCards/MovieCardResultsViewModel.cs b/ErsatzTV.Application/MediaCards/MovieCardResultsViewModel.cs new file mode 100644 index 000000000..f4062bbac --- /dev/null +++ b/ErsatzTV.Application/MediaCards/MovieCardResultsViewModel.cs @@ -0,0 +1,6 @@ +using System.Collections.Generic; + +namespace ErsatzTV.Application.MediaCards +{ + public record MovieCardResultsViewModel(int Count, List Cards); +} diff --git a/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs b/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs new file mode 100644 index 000000000..a1e97a8d4 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/MovieCardViewModel.cs @@ -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) + { + } +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetMovieCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetMovieCards.cs new file mode 100644 index 000000000..67efe3c92 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetMovieCards.cs @@ -0,0 +1,6 @@ +using MediatR; + +namespace ErsatzTV.Application.MediaCards.Queries +{ + public record GetMovieCards(int PageNumber, int PageSize) : IRequest; +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetMovieCardsHandler.cs b/ErsatzTV.Application/MediaCards/Queries/GetMovieCardsHandler.cs new file mode 100644 index 000000000..c745f5d4e --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetMovieCardsHandler.cs @@ -0,0 +1,35 @@ +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 + { + private readonly IMovieRepository _movieRepository; + + public GetMovieCardsHandler(IMovieRepository movieRepository) + { + _movieRepository = movieRepository; + } + + public async Task Handle( + GetMovieCards request, + CancellationToken cancellationToken) + { + int count = await _movieRepository.GetMovieCount(); + + List results = await _movieRepository + .GetPagedMovies(request.PageNumber, request.PageSize) + .Map(list => list.Map(ProjectToViewModel).ToList()); + + return new MovieCardResultsViewModel(count, results); + } + } +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs new file mode 100644 index 000000000..85f7546fb --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs @@ -0,0 +1,7 @@ +using MediatR; + +namespace ErsatzTV.Application.MediaCards.Queries +{ + public record GetTelevisionSeasonCards + (int TelevisionShowId, int PageNumber, int PageSize) : IRequest; +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs new file mode 100644 index 000000000..1a339a96e --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs @@ -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 + { + private readonly ITelevisionRepository _televisionRepository; + + public GetTelevisionSeasonCardsHandler(ITelevisionRepository televisionRepository) => + _televisionRepository = televisionRepository; + + public async Task Handle( + GetTelevisionSeasonCards request, + CancellationToken cancellationToken) + { + int count = await _televisionRepository.GetSeasonCount(request.TelevisionShowId); + + List results = await _televisionRepository + .GetPagedSeasons(request.TelevisionShowId, request.PageNumber, request.PageSize) + .Map(list => list.Map(ProjectToViewModel).ToList()); + + return new TelevisionSeasonCardResultsViewModel(count, results); + } + } +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCards.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCards.cs new file mode 100644 index 000000000..1e7903240 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCards.cs @@ -0,0 +1,6 @@ +using MediatR; + +namespace ErsatzTV.Application.MediaCards.Queries +{ + public record GetTelevisionShowCards(int PageNumber, int PageSize) : IRequest; +} diff --git a/ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCardsHandler.cs b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCardsHandler.cs new file mode 100644 index 000000000..ca8465d3f --- /dev/null +++ b/ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCardsHandler.cs @@ -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 + { + private readonly ITelevisionRepository _televisionRepository; + + public GetTelevisionShowCardsHandler(ITelevisionRepository televisionRepository) => + _televisionRepository = televisionRepository; + + public async Task Handle( + GetTelevisionShowCards request, + CancellationToken cancellationToken) + { + int count = await _televisionRepository.GetShowCount(); + + List results = await _televisionRepository + .GetPagedShows(request.PageNumber, request.PageSize) + .Map(list => list.Map(ProjectToViewModel).ToList()); + + return new TelevisionShowCardResultsViewModel(count, results); + } + } +} diff --git a/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs new file mode 100644 index 000000000..1c8ed8348 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs @@ -0,0 +1,11 @@ +namespace ErsatzTV.Application.MediaCards +{ + public record TelevisionEpisodeCardViewModel + (string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel( + Title, + Subtitle, + SortTitle, + Poster) + { + } +} diff --git a/ErsatzTV.Application/MediaCards/TelevisionSeasonCardResultsViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionSeasonCardResultsViewModel.cs new file mode 100644 index 000000000..9df90f1a2 --- /dev/null +++ b/ErsatzTV.Application/MediaCards/TelevisionSeasonCardResultsViewModel.cs @@ -0,0 +1,6 @@ +using System.Collections.Generic; + +namespace ErsatzTV.Application.MediaCards +{ + public record TelevisionSeasonCardResultsViewModel(int Count, List Cards); +} diff --git a/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs new file mode 100644 index 000000000..0f70bb97d --- /dev/null +++ b/ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs @@ -0,0 +1,11 @@ +namespace ErsatzTV.Application.MediaCards +{ + public record TelevisionSeasonCardViewModel + (int TelevisionSeasonId, string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel( + Title, + Subtitle, + SortTitle, + Poster) + { + } +} diff --git a/ErsatzTV.Application/MediaCards/TelevisionShowCardResultsViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionShowCardResultsViewModel.cs new file mode 100644 index 000000000..228085f1a --- /dev/null +++ b/ErsatzTV.Application/MediaCards/TelevisionShowCardResultsViewModel.cs @@ -0,0 +1,6 @@ +using System.Collections.Generic; + +namespace ErsatzTV.Application.MediaCards +{ + public record TelevisionShowCardResultsViewModel(int Count, List Cards); +} diff --git a/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs b/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs new file mode 100644 index 000000000..975781c2e --- /dev/null +++ b/ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs @@ -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) + { + } +} diff --git a/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItems.cs b/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItems.cs index c552bf0cd..8143ac6c6 100644 --- a/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItems.cs +++ b/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItems.cs @@ -1,8 +1,8 @@ -using ErsatzTV.Core.Domain; +using ErsatzTV.Core.AggregateModels; using MediatR; namespace ErsatzTV.Application.MediaItems.Queries { public record GetAggregateMediaItems - (MediaType MediaType, int PageNumber, int PageSize) : IRequest; + (AggregateMediaItemType ItemType, int PageNumber, int PageSize) : IRequest; } diff --git a/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItemsHandler.cs b/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItemsHandler.cs index 67dcfd792..9d766691c 100644 --- a/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItemsHandler.cs +++ b/ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItemsHandler.cs @@ -20,24 +20,25 @@ namespace ErsatzTV.Application.MediaItems.Queries GetAggregateMediaItems request, CancellationToken cancellationToken) { - int count = await _mediaItemRepository.GetCountByType(request.MediaType); - - IEnumerable allItems = await _mediaItemRepository.GetPageByType( - request.MediaType, - request.PageNumber, - request.PageSize); - - var results = allItems - .Map( - s => new AggregateMediaItemViewModel( - s.MediaItemId, - s.Title, - s.Subtitle, - s.SortTitle, - s.Poster)) - .ToList(); - - return new AggregateMediaItemResults(count, results); + return new AggregateMediaItemResults(0, new List()); + // int count = await _mediaItemRepository.GetCountByType(request.ItemType); + // + // IEnumerable allItems = await _mediaItemRepository.GetPageByType( + // request.ItemType, + // request.PageNumber, + // request.PageSize); + // + // var results = allItems + // .Map( + // s => new AggregateMediaItemViewModel( + // s.MediaItemId, + // s.Title, + // s.Subtitle, + // s.SortTitle, + // s.Poster)) + // .ToList(); + // + // return new AggregateMediaItemResults(count, results); } } } diff --git a/ErsatzTV.Core/AggregateModels/AggregateMediaItemType.cs b/ErsatzTV.Core/AggregateModels/AggregateMediaItemType.cs new file mode 100644 index 000000000..dd156d9ad --- /dev/null +++ b/ErsatzTV.Core/AggregateModels/AggregateMediaItemType.cs @@ -0,0 +1,10 @@ +namespace ErsatzTV.Core.AggregateModels +{ + public enum AggregateMediaItemType + { + TelevisionShows, + TelevisionSeasons, + TelevisionEpisodes, + Movies + } +} diff --git a/ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs index a3a913983..aa5966938 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs @@ -12,8 +12,8 @@ namespace ErsatzTV.Core.Interfaces.Repositories public Task> Get(int id); public Task> GetAll(); public Task> Search(string searchString); - public Task> GetPageByType(MediaType mediaType, int pageNumber, int pageSize); - public Task GetCountByType(MediaType mediaType); + // public Task> GetPageByType(AggregateMediaItemType itemType, int pageNumber, int pageSize); + // public Task GetCountByType(AggregateMediaItemType itemType); public Task> GetAllByMediaSourceId(int mediaSourceId); public Task Update(MediaItem mediaItem); public Task Delete(int mediaItemId); diff --git a/ErsatzTV.Core/Interfaces/Repositories/IMovieRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IMovieRepository.cs index db9de1af4..4fec7e047 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IMovieRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IMovieRepository.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using ErsatzTV.Core.Domain; using LanguageExt; @@ -8,5 +9,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories { public Task> GetOrAdd(int mediaSourceId, string path); public Task Update(MovieMediaItem movie); + public Task GetMovieCount(); + public Task> GetPagedMovies(int pageNumber, int pageSize); } } diff --git a/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs index 43a03cf35..d48e998a6 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs @@ -10,15 +10,17 @@ namespace ErsatzTV.Core.Interfaces.Repositories public Task Add(TelevisionShow show); public Task> GetAllByMediaSourceId(int mediaSourceId); public Task Update(TelevisionShow show); + public Task Update(TelevisionSeason season); public Task Update(TelevisionEpisodeMediaItem episode); - + public Task GetShowCount(); + public Task> GetPagedShows(int pageNumber, int pageSize); + public Task GetSeasonCount(int televisionShowId); + public Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize); public Task> GetOrAddShow(int mediaSourceId, string path); - public Task> GetOrAddSeason( TelevisionShow show, string path, int seasonNumber); - public Task> GetOrAddEpisode( TelevisionSeason season, int mediaSourceId, diff --git a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs index b5ecce1a4..d881a6980 100644 --- a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs +++ b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs @@ -74,7 +74,8 @@ namespace ErsatzTV.Core.Metadata async seasonNumber => { Either maybeSeason = await _televisionRepository - .GetOrAddSeason(show, seasonFolder, seasonNumber); + .GetOrAddSeason(show, seasonFolder, seasonNumber) + .BindT(UpdatePoster); await maybeSeason.Match( season => ScanEpisodes(localMediaSource, ffprobePath, season), @@ -192,6 +193,29 @@ namespace ErsatzTV.Core.Metadata return BaseError.New(ex.Message); } } + + private async Task> UpdatePoster(TelevisionSeason season) + { + try + { + await LocatePoster(season).IfSomeAsync( + async posterFile => + { + if (string.IsNullOrWhiteSpace(season.Poster) || + season.PosterLastWriteTime < _localFileSystem.GetLastWriteTime(posterFile)) + { + _logger.LogDebug("Refreshing {Attribute} from {Path}", "Poster", posterFile); + await SavePosterToDisk(season, posterFile, _televisionRepository.Update); + } + }); + + return season; + } + catch (Exception ex) + { + return BaseError.New(ex.Message); + } + } private async Task> UpdateThumbnail( TelevisionEpisodeMediaItem episode) @@ -227,11 +251,20 @@ namespace ErsatzTV.Core.Metadata private Option LocatePoster(TelevisionShow show) => ImageFileExtensions - .Collect(ext => new[] { $"poster.{ext}" }) + .Map(ext => $"poster.{ext}") .Map(f => Path.Combine(show.Path, f)) .Filter(s => _localFileSystem.FileExists(s)) .HeadOrNone(); + private Option LocatePoster(TelevisionSeason season) + { + string folder = Path.GetDirectoryName(season.Path) ?? string.Empty; + return ImageFileExtensions + .Map(ext => Path.Combine(folder, $"season{season.Number:00}-poster.{ext}")) + .Filter(s => _localFileSystem.FileExists(s)) + .HeadOrNone(); + } + private Option LocateThumbnail(TelevisionEpisodeMediaItem episode) { string folder = Path.GetDirectoryName(episode.Path) ?? string.Empty; diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs index 7c88a4116..5bbe16d49 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using ErsatzTV.Core; using ErsatzTV.Core.Domain; @@ -31,6 +33,20 @@ namespace ErsatzTV.Infrastructure.Data.Repositories _dbContext.MovieMediaItems.Update(movie); return await _dbContext.SaveChangesAsync() > 0; } + + public Task GetMovieCount() => + _dbContext.MovieMediaItems + .AsNoTracking() + .CountAsync(); + + public Task> GetPagedMovies(int pageNumber, int pageSize) => + _dbContext.MovieMediaItems + .Include(s => s.Metadata) + .OrderBy(s => s.Metadata.SortTitle) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .AsNoTracking() + .ToListAsync(); private async Task> AddMovie(int mediaSourceId, string path) { diff --git a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs index eb8e0ab6b..980674cb0 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using ErsatzTV.Core; using ErsatzTV.Core.Domain; @@ -34,12 +35,50 @@ namespace ErsatzTV.Infrastructure.Data.Repositories return await _dbContext.SaveChangesAsync() > 0; } + public async Task Update(TelevisionSeason season) + { + _dbContext.TelevisionSeasons.Update(season); + return await _dbContext.SaveChangesAsync() > 0; + } + public async Task Update(TelevisionEpisodeMediaItem episode) { _dbContext.TelevisionEpisodeMediaItems.Update(episode); return await _dbContext.SaveChangesAsync() > 0; } + // TODO: test with split folders (same show in different sources) + public Task GetShowCount() => + _dbContext.TelevisionShows + .AsNoTracking() + // .GroupBy(s => new { s.Metadata.Title, s.Metadata.Year }) + .CountAsync(); + + // TODO: test with split folders (same show in different sources) + public Task> GetPagedShows(int pageNumber, int pageSize) => + _dbContext.TelevisionShows + .Include(s => s.Metadata) + .OrderBy(s => s.Metadata.SortTitle) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .AsNoTracking() + .ToListAsync(); + + public Task GetSeasonCount(int televisionShowId) => + _dbContext.TelevisionSeasons + .AsNoTracking() + .Where(s => s.TelevisionShowId == televisionShowId) + .CountAsync(); + + public Task> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize) => + _dbContext.TelevisionSeasons + .Where(s => s.TelevisionShowId == televisionShowId) + .OrderBy(s => s.Number) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .AsNoTracking() + .ToListAsync(); + public async Task> GetOrAddShow(int mediaSourceId, string path) { Option maybeExisting = await _dbContext.TelevisionShows diff --git a/ErsatzTV/Pages/MediaMovieItems.razor b/ErsatzTV/Pages/MediaMovieItems.razor deleted file mode 100644 index 185814ec3..000000000 --- a/ErsatzTV/Pages/MediaMovieItems.razor +++ /dev/null @@ -1,8 +0,0 @@ -@page "/media/movies/items" -@inject IMediator Mediator - - - -@code { - -} \ No newline at end of file diff --git a/ErsatzTV/Pages/MediaTvItems.razor b/ErsatzTV/Pages/MediaTvItems.razor deleted file mode 100644 index 69703faf8..000000000 --- a/ErsatzTV/Pages/MediaTvItems.razor +++ /dev/null @@ -1,8 +0,0 @@ -@page "/media/tv/items" -@inject IMediator Mediator - - - -@code { - -} \ No newline at end of file diff --git a/ErsatzTV/Shared/MediaItemsGrid.razor b/ErsatzTV/Pages/Movies.razor similarity index 75% rename from ErsatzTV/Shared/MediaItemsGrid.razor rename to ErsatzTV/Pages/Movies.razor index 84a4ca52f..8bfcc7a26 100644 --- a/ErsatzTV/Shared/MediaItemsGrid.razor +++ b/ErsatzTV/Pages/Movies.razor @@ -1,5 +1,6 @@ -@using ErsatzTV.Application.MediaItems -@using ErsatzTV.Application.MediaItems.Queries +@page "/media/movies" +@using ErsatzTV.Application.MediaCards +@using ErsatzTV.Application.MediaCards.Queries @inject IMediator Mediator @@ -19,26 +20,22 @@ - @foreach (AggregateMediaItemViewModel item in _data.DataPage) + @foreach (MovieCardViewModel card in _data.Cards) { - + } @code { - - [Parameter] - public MediaType MediaType { get; set; } - private int PageSize => 100; private int _pageNumber = 1; - private AggregateMediaItemResults _data; + private MovieCardResultsViewModel _data; protected override Task OnParametersSetAsync() => RefreshData(); private async Task RefreshData() => - _data = await Mediator.Send(new GetAggregateMediaItems(MediaType, _pageNumber, PageSize)); + _data = await Mediator.Send(new GetMovieCards(_pageNumber, PageSize)); private async Task PrevPage() { diff --git a/ErsatzTV/Pages/TelevisionSeasons.razor b/ErsatzTV/Pages/TelevisionSeasons.razor new file mode 100644 index 000000000..f9659778b --- /dev/null +++ b/ErsatzTV/Pages/TelevisionSeasons.razor @@ -0,0 +1,28 @@ +@page "/media/tv/shows/{ShowId:int}" +@using ErsatzTV.Application.MediaCards +@using ErsatzTV.Application.MediaCards.Queries +@inject IMediator Mediator + + + @foreach (TelevisionSeasonCardViewModel card in _data.Cards) + { + + } + + +@code { + + [Parameter] + public int ShowId { get; set; } + + private int PageSize => 100; + private int _pageNumber = 1; + + private TelevisionSeasonCardResultsViewModel _data; + + protected override Task OnParametersSetAsync() => RefreshData(); + + private async Task RefreshData() => + _data = await Mediator.Send(new GetTelevisionSeasonCards(ShowId, _pageNumber, PageSize)); + +} \ No newline at end of file diff --git a/ErsatzTV/Pages/TelevisionShows.razor b/ErsatzTV/Pages/TelevisionShows.razor new file mode 100644 index 000000000..f0626ba74 --- /dev/null +++ b/ErsatzTV/Pages/TelevisionShows.razor @@ -0,0 +1,52 @@ +@page "/media/tv/shows" +@using ErsatzTV.Application.MediaCards +@using ErsatzTV.Application.MediaCards.Queries +@inject IMediator Mediator + + + + + + + @Math.Min((_pageNumber - 1) * PageSize + 1, _data.Count)-@Math.Min(_data.Count, _pageNumber * PageSize) of @_data.Count + + + + + + + + @foreach (TelevisionShowCardViewModel card in _data.Cards) + { + + } + + +@code { + private int PageSize => 100; + private int _pageNumber = 1; + + private TelevisionShowCardResultsViewModel _data; + + protected override Task OnParametersSetAsync() => RefreshData(); + + private async Task RefreshData() => + _data = await Mediator.Send(new GetTelevisionShowCards(_pageNumber, PageSize)); + + private async Task PrevPage() + { + _pageNumber -= 1; + await RefreshData(); + } + + private async Task NextPage() + { + _pageNumber += 1; + await RefreshData(); + } + +} \ No newline at end of file diff --git a/ErsatzTV/Shared/MainLayout.razor b/ErsatzTV/Shared/MainLayout.razor index 9f5e86798..8cf5190f7 100644 --- a/ErsatzTV/Shared/MainLayout.razor +++ b/ErsatzTV/Shared/MainLayout.razor @@ -28,8 +28,8 @@ FFmpeg Media Sources - TV Shows - Movies + TV Shows + Movies Media Collections Schedules diff --git a/ErsatzTV/Shared/MediaCard.razor b/ErsatzTV/Shared/MediaCard.razor index 8ef46e897..37f9cd082 100644 --- a/ErsatzTV/Shared/MediaCard.razor +++ b/ErsatzTV/Shared/MediaCard.razor @@ -1,16 +1,34 @@ @using ErsatzTV.Application.MediaItems @using Unit = LanguageExt.Unit +@using ErsatzTV.Application.MediaCards @inject IMediator Mediator
- - @if (string.IsNullOrWhiteSpace(Data.Poster)) +
+ @if (!string.IsNullOrWhiteSpace(Link)) { - - @Placeholder(Data.SortTitle) - + + @if (string.IsNullOrWhiteSpace(Data.Poster)) + { + + @Placeholder(Data.SortTitle) + + } + } - + else + { + + @if (string.IsNullOrWhiteSpace(Data.Poster)) + { + + @Placeholder(Data.SortTitle) + + } + + } +
+
@Data.Title @@ -22,7 +40,10 @@ @code { [Parameter] - public AggregateMediaItemViewModel Data { get; set; } + public MediaCardViewModel Data { get; set; } + + [Parameter] + public string Link { get; set; } [Parameter] public EventCallback DataRefreshed { get; set; } diff --git a/ErsatzTV/wwwroot/css/site.css b/ErsatzTV/wwwroot/css/site.css index d3f31315d..d643912f5 100644 --- a/ErsatzTV/wwwroot/css/site.css +++ b/ErsatzTV/wwwroot/css/site.css @@ -16,7 +16,7 @@ width: 152px; } -.media-card:hover { filter: brightness(80%); } +.media-card:hover { filter: brightness(75%); } .media-card-title { overflow: hidden;