Browse Source

television and movie views are working again

pull/26/head
Jason Dove 6 years ago
parent
commit
7fc0f47e35
  1. 34
      ErsatzTV.Application/MediaCards/Mapper.cs
  2. 4
      ErsatzTV.Application/MediaCards/MediaCardViewModel.cs
  3. 6
      ErsatzTV.Application/MediaCards/MovieCardResultsViewModel.cs
  4. 11
      ErsatzTV.Application/MediaCards/MovieCardViewModel.cs
  5. 6
      ErsatzTV.Application/MediaCards/Queries/GetMovieCards.cs
  6. 35
      ErsatzTV.Application/MediaCards/Queries/GetMovieCardsHandler.cs
  7. 7
      ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs
  8. 34
      ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs
  9. 6
      ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCards.cs
  10. 33
      ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCardsHandler.cs
  11. 11
      ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs
  12. 6
      ErsatzTV.Application/MediaCards/TelevisionSeasonCardResultsViewModel.cs
  13. 11
      ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs
  14. 6
      ErsatzTV.Application/MediaCards/TelevisionShowCardResultsViewModel.cs
  15. 11
      ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs
  16. 4
      ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItems.cs
  17. 37
      ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItemsHandler.cs
  18. 10
      ErsatzTV.Core/AggregateModels/AggregateMediaItemType.cs
  19. 4
      ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs
  20. 5
      ErsatzTV.Core/Interfaces/Repositories/IMovieRepository.cs
  21. 8
      ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs
  22. 37
      ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs
  23. 16
      ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs
  24. 39
      ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs
  25. 8
      ErsatzTV/Pages/MediaMovieItems.razor
  26. 8
      ErsatzTV/Pages/MediaTvItems.razor
  27. 17
      ErsatzTV/Pages/Movies.razor
  28. 28
      ErsatzTV/Pages/TelevisionSeasons.razor
  29. 52
      ErsatzTV/Pages/TelevisionShows.razor
  30. 4
      ErsatzTV/Shared/MainLayout.razor
  31. 35
      ErsatzTV/Shared/MediaCard.razor
  32. 2
      ErsatzTV/wwwroot/css/site.css

34
ErsatzTV.Application/MediaCards/Mapper.cs

@ -0,0 +1,34 @@ @@ -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}";
}
}

4
ErsatzTV.Application/MediaCards/MediaCardViewModel.cs

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
namespace ErsatzTV.Application.MediaCards
{
public record MediaCardViewModel(string Title, string Subtitle, string SortTitle, string Poster);
}

6
ErsatzTV.Application/MediaCards/MovieCardResultsViewModel.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using System.Collections.Generic;
namespace ErsatzTV.Application.MediaCards
{
public record MovieCardResultsViewModel(int Count, List<MovieCardViewModel> Cards);
}

11
ErsatzTV.Application/MediaCards/MovieCardViewModel.cs

@ -0,0 +1,11 @@ @@ -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)
{
}
}

6
ErsatzTV.Application/MediaCards/Queries/GetMovieCards.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using MediatR;
namespace ErsatzTV.Application.MediaCards.Queries
{
public record GetMovieCards(int PageNumber, int PageSize) : IRequest<MovieCardResultsViewModel>;
}

35
ErsatzTV.Application/MediaCards/Queries/GetMovieCardsHandler.cs

@ -0,0 +1,35 @@ @@ -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<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);
}
}
}

7
ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCards.cs

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
using MediatR;
namespace ErsatzTV.Application.MediaCards.Queries
{
public record GetTelevisionSeasonCards
(int TelevisionShowId, int PageNumber, int PageSize) : IRequest<TelevisionSeasonCardResultsViewModel>;
}

34
ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs

@ -0,0 +1,34 @@ @@ -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);
}
}
}

6
ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCards.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using MediatR;
namespace ErsatzTV.Application.MediaCards.Queries
{
public record GetTelevisionShowCards(int PageNumber, int PageSize) : IRequest<TelevisionShowCardResultsViewModel>;
}

33
ErsatzTV.Application/MediaCards/Queries/GetTelevisionShowCardsHandler.cs

@ -0,0 +1,33 @@ @@ -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);
}
}
}

11
ErsatzTV.Application/MediaCards/TelevisionEpisodeCardViewModel.cs

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
namespace ErsatzTV.Application.MediaCards
{
public record TelevisionEpisodeCardViewModel
(string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel(
Title,
Subtitle,
SortTitle,
Poster)
{
}
}

6
ErsatzTV.Application/MediaCards/TelevisionSeasonCardResultsViewModel.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using System.Collections.Generic;
namespace ErsatzTV.Application.MediaCards
{
public record TelevisionSeasonCardResultsViewModel(int Count, List<TelevisionSeasonCardViewModel> Cards);
}

11
ErsatzTV.Application/MediaCards/TelevisionSeasonCardViewModel.cs

@ -0,0 +1,11 @@ @@ -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)
{
}
}

6
ErsatzTV.Application/MediaCards/TelevisionShowCardResultsViewModel.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using System.Collections.Generic;
namespace ErsatzTV.Application.MediaCards
{
public record TelevisionShowCardResultsViewModel(int Count, List<TelevisionShowCardViewModel> Cards);
}

11
ErsatzTV.Application/MediaCards/TelevisionShowCardViewModel.cs

@ -0,0 +1,11 @@ @@ -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)
{
}
}

4
ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItems.cs

@ -1,8 +1,8 @@ @@ -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<AggregateMediaItemResults>;
(AggregateMediaItemType ItemType, int PageNumber, int PageSize) : IRequest<AggregateMediaItemResults>;
}

37
ErsatzTV.Application/MediaItems/Queries/GetAggregateMediaItemsHandler.cs

@ -20,24 +20,25 @@ namespace ErsatzTV.Application.MediaItems.Queries @@ -20,24 +20,25 @@ namespace ErsatzTV.Application.MediaItems.Queries
GetAggregateMediaItems request,
CancellationToken cancellationToken)
{
int count = await _mediaItemRepository.GetCountByType(request.MediaType);
IEnumerable<MediaItemSummary> 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<AggregateMediaItemViewModel>());
// int count = await _mediaItemRepository.GetCountByType(request.ItemType);
//
// IEnumerable<MediaItemSummary> 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);
}
}
}

10
ErsatzTV.Core/AggregateModels/AggregateMediaItemType.cs

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
namespace ErsatzTV.Core.AggregateModels
{
public enum AggregateMediaItemType
{
TelevisionShows,
TelevisionSeasons,
TelevisionEpisodes,
Movies
}
}

4
ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs

@ -12,8 +12,8 @@ namespace ErsatzTV.Core.Interfaces.Repositories @@ -12,8 +12,8 @@ namespace ErsatzTV.Core.Interfaces.Repositories
public Task<Option<MediaItem>> Get(int id);
public Task<List<MediaItem>> GetAll();
public Task<List<MediaItem>> Search(string searchString);
public Task<List<MediaItemSummary>> GetPageByType(MediaType mediaType, int pageNumber, int pageSize);
public Task<int> GetCountByType(MediaType mediaType);
// public Task<List<MediaItemSummary>> GetPageByType(AggregateMediaItemType itemType, int pageNumber, int pageSize);
// public Task<int> GetCountByType(AggregateMediaItemType itemType);
public Task<List<MediaItem>> GetAllByMediaSourceId(int mediaSourceId);
public Task<bool> Update(MediaItem mediaItem);
public Task<Unit> Delete(int mediaItemId);

5
ErsatzTV.Core/Interfaces/Repositories/IMovieRepository.cs

@ -1,4 +1,5 @@ @@ -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 @@ -8,5 +9,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories
{
public Task<Either<BaseError, MovieMediaItem>> GetOrAdd(int mediaSourceId, string path);
public Task<bool> Update(MovieMediaItem movie);
public Task<int> GetMovieCount();
public Task<List<MovieMediaItem>> GetPagedMovies(int pageNumber, int pageSize);
}
}

8
ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs

@ -10,15 +10,17 @@ namespace ErsatzTV.Core.Interfaces.Repositories @@ -10,15 +10,17 @@ namespace ErsatzTV.Core.Interfaces.Repositories
public Task<Unit> Add(TelevisionShow show);
public Task<List<TelevisionShow>> GetAllByMediaSourceId(int mediaSourceId);
public Task<bool> Update(TelevisionShow show);
public Task<bool> Update(TelevisionSeason season);
public Task<bool> Update(TelevisionEpisodeMediaItem episode);
public Task<int> GetShowCount();
public Task<List<TelevisionShow>> GetPagedShows(int pageNumber, int pageSize);
public Task<int> GetSeasonCount(int televisionShowId);
public Task<List<TelevisionSeason>> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize);
public Task<Either<BaseError, TelevisionShow>> GetOrAddShow(int mediaSourceId, string path);
public Task<Either<BaseError, TelevisionSeason>> GetOrAddSeason(
TelevisionShow show,
string path,
int seasonNumber);
public Task<Either<BaseError, TelevisionEpisodeMediaItem>> GetOrAddEpisode(
TelevisionSeason season,
int mediaSourceId,

37
ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs

@ -74,7 +74,8 @@ namespace ErsatzTV.Core.Metadata @@ -74,7 +74,8 @@ namespace ErsatzTV.Core.Metadata
async seasonNumber =>
{
Either<BaseError, TelevisionSeason> 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 @@ -192,6 +193,29 @@ namespace ErsatzTV.Core.Metadata
return BaseError.New(ex.Message);
}
}
private async Task<Either<BaseError, TelevisionSeason>> 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<Either<BaseError, TelevisionEpisodeMediaItem>> UpdateThumbnail(
TelevisionEpisodeMediaItem episode)
@ -227,11 +251,20 @@ namespace ErsatzTV.Core.Metadata @@ -227,11 +251,20 @@ namespace ErsatzTV.Core.Metadata
private Option<string> 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<string> 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<string> LocateThumbnail(TelevisionEpisodeMediaItem episode)
{
string folder = Path.GetDirectoryName(episode.Path) ?? string.Empty;

16
ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs

@ -1,4 +1,6 @@ @@ -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 @@ -31,6 +33,20 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
_dbContext.MovieMediaItems.Update(movie);
return await _dbContext.SaveChangesAsync() > 0;
}
public Task<int> GetMovieCount() =>
_dbContext.MovieMediaItems
.AsNoTracking()
.CountAsync();
public Task<List<MovieMediaItem>> 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<Either<BaseError, MovieMediaItem>> AddMovie(int mediaSourceId, string path)
{

39
ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs

@ -1,5 +1,6 @@ @@ -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 @@ -34,12 +35,50 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
return await _dbContext.SaveChangesAsync() > 0;
}
public async Task<bool> Update(TelevisionSeason season)
{
_dbContext.TelevisionSeasons.Update(season);
return await _dbContext.SaveChangesAsync() > 0;
}
public async Task<bool> Update(TelevisionEpisodeMediaItem episode)
{
_dbContext.TelevisionEpisodeMediaItems.Update(episode);
return await _dbContext.SaveChangesAsync() > 0;
}
// TODO: test with split folders (same show in different sources)
public Task<int> 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<List<TelevisionShow>> 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<int> GetSeasonCount(int televisionShowId) =>
_dbContext.TelevisionSeasons
.AsNoTracking()
.Where(s => s.TelevisionShowId == televisionShowId)
.CountAsync();
public Task<List<TelevisionSeason>> 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<Either<BaseError, TelevisionShow>> GetOrAddShow(int mediaSourceId, string path)
{
Option<TelevisionShow> maybeExisting = await _dbContext.TelevisionShows

8
ErsatzTV/Pages/MediaMovieItems.razor

@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
@page "/media/movies/items"
@inject IMediator Mediator
<MediaItemsGrid MediaType="@MediaType.Movie"/>
@code {
}

8
ErsatzTV/Pages/MediaTvItems.razor

@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
@page "/media/tv/items"
@inject IMediator Mediator
<MediaItemsGrid MediaType="@MediaType.TvShow"/>
@code {
}

17
ErsatzTV/Shared/MediaItemsGrid.razor → ErsatzTV/Pages/Movies.razor

@ -1,5 +1,6 @@ @@ -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
<MudContainer MaxWidth="MaxWidth.Small" Class="mb-6" Style="max-width: 300px">
@ -19,26 +20,22 @@ @@ -19,26 +20,22 @@
</MudContainer>
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
@foreach (AggregateMediaItemViewModel item in _data.DataPage)
@foreach (MovieCardViewModel card in _data.Cards)
{
<MediaCard Data="@item" DataRefreshed="@(() => RefreshData())"/>
<MediaCard Data="@card" DataRefreshed="@(() => RefreshData())"/>
}
</MudContainer>
@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()
{

28
ErsatzTV/Pages/TelevisionSeasons.razor

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
@page "/media/tv/shows/{ShowId:int}"
@using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCards.Queries
@inject IMediator Mediator
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
@foreach (TelevisionSeasonCardViewModel card in _data.Cards)
{
<MediaCard Data="@card" Link="@($"/media/tv/shows/{ShowId}/seasons/{card.TelevisionSeasonId}")" DataRefreshed="@(() => RefreshData())"/>
}
</MudContainer>
@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));
}

52
ErsatzTV/Pages/TelevisionShows.razor

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
@page "/media/tv/shows"
@using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCards.Queries
@inject IMediator Mediator
<MudContainer MaxWidth="MaxWidth.Small" Class="mb-6" Style="max-width: 300px">
<MudPaper Style="align-items: center; display: flex; justify-content: center;">
<MudIconButton Icon="@Icons.Material.Outlined.ChevronLeft"
OnClick="@(() => PrevPage())"
Disabled="@(_pageNumber <= 1)">
</MudIconButton>
<MudText Style="flex-grow: 1"
Align="Align.Center">
@Math.Min((_pageNumber - 1) * PageSize + 1, _data.Count)-@Math.Min(_data.Count, _pageNumber * PageSize) of @_data.Count
</MudText>
<MudIconButton Icon="@Icons.Material.Outlined.ChevronRight"
OnClick="@(() => NextPage())" Disabled="@(_pageNumber * PageSize >= _data.Count)">
</MudIconButton>
</MudPaper>
</MudContainer>
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
@foreach (TelevisionShowCardViewModel card in _data.Cards)
{
<MediaCard Data="@card" Link="@($"/media/tv/shows/{card.TelevisionShowId}")" DataRefreshed="@(() => RefreshData())"/>
}
</MudContainer>
@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();
}
}

4
ErsatzTV/Shared/MainLayout.razor

@ -28,8 +28,8 @@ @@ -28,8 +28,8 @@
<MudNavLink Href="/ffmpeg">FFmpeg</MudNavLink>
<MudNavGroup Title="Media" Expanded="true">
<MudNavLink Href="/media/sources">Media Sources</MudNavLink>
<MudNavLink Href="/media/tv/items">TV Shows</MudNavLink>
<MudNavLink Href="/media/movies/items">Movies</MudNavLink>
<MudNavLink Href="/media/tv/shows">TV Shows</MudNavLink>
<MudNavLink Href="/media/movies">Movies</MudNavLink>
<MudNavLink Href="/media/collections">Media Collections</MudNavLink>
</MudNavGroup>
<MudNavLink Href="/schedules">Schedules</MudNavLink>

35
ErsatzTV/Shared/MediaCard.razor

@ -1,16 +1,34 @@ @@ -1,16 +1,34 @@
@using ErsatzTV.Application.MediaItems
@using Unit = LanguageExt.Unit
@using ErsatzTV.Application.MediaCards
@inject IMediator Mediator
<div class="media-card-container mx-3 pb-3">
<MudPaper Class="media-card" Style="@PosterForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster))
<div>
@if (!string.IsNullOrWhiteSpace(Link))
{
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled">
@Placeholder(Data.SortTitle)
</MudText>
<MudButton Link="@Link" Class="media-card" Style="@PosterForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster))
{
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled">
@Placeholder(Data.SortTitle)
</MudText>
}
</MudButton>
}
</MudPaper>
else
{
<MudPaper Class="media-card" Style="@PosterForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster))
{
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled">
@Placeholder(Data.SortTitle)
</MudText>
}
</MudPaper>
}
<div style="background: rgba(0, 0, 0, 0.5)"></div>
</div>
<MudText Align="Align.Center" Class="media-card-title" UserAttributes="@(new Dictionary<string, object> { { "title", Data.Title } })">
@Data.Title
</MudText>
@ -22,7 +40,10 @@ @@ -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<Unit> DataRefreshed { get; set; }

2
ErsatzTV/wwwroot/css/site.css

@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
width: 152px;
}
.media-card:hover { filter: brightness(80%); }
.media-card:hover { filter: brightness(75%); }
.media-card-title {
overflow: hidden;

Loading…
Cancel
Save