Browse Source

fix television artwork

pull/31/head
Jason Dove 6 years ago
parent
commit
e6c0b5b05d
  1. 18
      ErsatzTV.Application/Television/Mapper.cs
  2. 5
      ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs
  3. 4
      ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs
  4. 2
      ErsatzTV.Core/Metadata/LocalFolderScanner.cs
  5. 25
      ErsatzTV.Core/Metadata/LocalMetadataProvider.cs
  6. 23
      ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs
  7. 14
      ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs
  8. 59
      ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs
  9. 14
      ErsatzTV/Controllers/ArtworkController.cs
  10. 2
      ErsatzTV/Pages/Movie.razor
  11. 2
      ErsatzTV/Pages/TelevisionEpisode.razor
  12. 5
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  13. 2
      ErsatzTV/Pages/TelevisionSeasonList.razor
  14. 17
      ErsatzTV/Shared/MediaCard.razor

18
ErsatzTV.Application/Television/Mapper.cs

@ -1,4 +1,6 @@
using ErsatzTV.Core.Domain; using System.Linq;
using ErsatzTV.Core.Domain;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Television namespace ErsatzTV.Application.Television
{ {
@ -10,7 +12,7 @@ namespace ErsatzTV.Application.Television
show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty),
show.ShowMetadata.HeadOrNone().Map(m => m.ReleaseDate?.Year.ToString()).IfNone(string.Empty), show.ShowMetadata.HeadOrNone().Map(m => m.ReleaseDate?.Year.ToString()).IfNone(string.Empty),
show.ShowMetadata.HeadOrNone().Map(m => m.Plot).IfNone(string.Empty), show.ShowMetadata.HeadOrNone().Map(m => m.Plot).IfNone(string.Empty),
null); // TODO: artwork show.ShowMetadata.HeadOrNone().Map(GetPoster).IfNone(string.Empty));
internal static TelevisionSeasonViewModel ProjectToViewModel(Season season) => internal static TelevisionSeasonViewModel ProjectToViewModel(Season season) =>
new( new(
@ -19,7 +21,7 @@ namespace ErsatzTV.Application.Television
season.Show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), season.Show.ShowMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty),
season.Show.ShowMetadata.HeadOrNone().Map(m => m.ReleaseDate?.Year.ToString()).IfNone(string.Empty), season.Show.ShowMetadata.HeadOrNone().Map(m => m.ReleaseDate?.Year.ToString()).IfNone(string.Empty),
season.SeasonNumber == 0 ? "Specials" : $"Season {season.SeasonNumber}", season.SeasonNumber == 0 ? "Specials" : $"Season {season.SeasonNumber}",
null); // TODO: artwork season.SeasonMetadata.HeadOrNone().Map(GetPoster).IfNone(string.Empty));
internal static TelevisionEpisodeViewModel ProjectToViewModel(Episode episode) => internal static TelevisionEpisodeViewModel ProjectToViewModel(Episode episode) =>
new( new(
@ -28,6 +30,14 @@ namespace ErsatzTV.Application.Television
episode.EpisodeNumber, episode.EpisodeNumber,
episode.EpisodeMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty), episode.EpisodeMetadata.HeadOrNone().Map(m => m.Title).IfNone(string.Empty),
episode.EpisodeMetadata.HeadOrNone().Map(m => m.Plot).IfNone(string.Empty), episode.EpisodeMetadata.HeadOrNone().Map(m => m.Plot).IfNone(string.Empty),
null); // TODO: artwork episode.EpisodeMetadata.HeadOrNone().Map(GetThumbnail).IfNone(string.Empty));
private static string GetPoster(Metadata metadata) =>
Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Poster))
.Match(a => a.Path, string.Empty);
private static string GetThumbnail(Metadata metadata) =>
Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Thumbnail))
.Match(a => a.Path, string.Empty);
} }
} }

5
ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs

@ -44,10 +44,11 @@ namespace ErsatzTV.Core.Tests.Fakes
public Task<List<EpisodeMetadata>> GetPagedEpisodes(int seasonId, int pageNumber, int pageSize) => public Task<List<EpisodeMetadata>> GetPagedEpisodes(int seasonId, int pageNumber, int pageSize) =>
throw new NotSupportedException(); throw new NotSupportedException();
public Task<Option<Show>> GetShowByMetadata(ShowMetadata metadata) => throw new NotSupportedException(); public Task<Option<Show>> GetShowByMetadata(int libraryPathId, ShowMetadata metadata) =>
throw new NotSupportedException();
public Task<Either<BaseError, Show>> public Task<Either<BaseError, Show>>
AddShow(int localMediaSourceId, string showFolder, ShowMetadata metadata) => AddShow(int libraryPathId, string showFolder, ShowMetadata metadata) =>
throw new NotSupportedException(); throw new NotSupportedException();
public Task<Either<BaseError, Season>> GetOrAddSeason(Show show, string path, int seasonNumber) => public Task<Either<BaseError, Season>> GetOrAddSeason(Show show, string path, int seasonNumber) =>

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

@ -23,10 +23,10 @@ namespace ErsatzTV.Core.Interfaces.Repositories
Task<Option<Episode>> GetEpisode(int televisionEpisodeId); Task<Option<Episode>> GetEpisode(int televisionEpisodeId);
Task<int> GetEpisodeCount(int televisionSeasonId); Task<int> GetEpisodeCount(int televisionSeasonId);
Task<List<EpisodeMetadata>> GetPagedEpisodes(int seasonId, int pageNumber, int pageSize); Task<List<EpisodeMetadata>> GetPagedEpisodes(int seasonId, int pageNumber, int pageSize);
Task<Option<Show>> GetShowByMetadata(ShowMetadata metadata); Task<Option<Show>> GetShowByMetadata(int libraryPathId, ShowMetadata metadata);
Task<Either<BaseError, Show>> AddShow( Task<Either<BaseError, Show>> AddShow(
int localMediaSourceId, int libraryPathId,
string showFolder, string showFolder,
ShowMetadata metadata); ShowMetadata metadata);

2
ErsatzTV.Core/Metadata/LocalFolderScanner.cs

@ -88,6 +88,8 @@ namespace ErsatzTV.Core.Metadata
{ {
DateTime lastWriteTime = _localFileSystem.GetLastWriteTime(artworkFile); DateTime lastWriteTime = _localFileSystem.GetLastWriteTime(artworkFile);
metadata.Artwork ??= new List<Artwork>();
Option<Artwork> maybePoster = Option<Artwork> maybePoster =
metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == artworkKind); metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == artworkKind);

25
ErsatzTV.Core/Metadata/LocalMetadataProvider.cs

@ -38,19 +38,22 @@ namespace ErsatzTV.Core.Metadata
_logger = logger; _logger = logger;
} }
public Task<ShowMetadata> GetMetadataForShow(string showFolder) public async Task<ShowMetadata> GetMetadataForShow(string showFolder)
{ {
string nfoFileName = Path.Combine(showFolder, "tvshow.nfo"); string nfoFileName = Path.Combine(showFolder, "tvshow.nfo");
return Optional(_localFileSystem.FileExists(nfoFileName)) Option<ShowMetadata> maybeMetadata = None;
.Filter(identity).AsTask() if (_localFileSystem.FileExists(nfoFileName))
.Bind(_ => LoadTelevisionShowMetadata(nfoFileName)) {
.IfNoneAsync(() => _fallbackMetadataProvider.GetFallbackMetadataForShow(showFolder).AsTask()) maybeMetadata = await LoadTelevisionShowMetadata(nfoFileName);
.Map( }
m =>
{ return maybeMetadata.IfNone(
m.SortTitle = GetSortTitle(m.Title); () =>
return m; {
}); ShowMetadata metadata = _fallbackMetadataProvider.GetFallbackMetadataForShow(showFolder);
metadata.SortTitle = GetSortTitle(metadata.Title);
return metadata;
});
} }
public Task<Unit> RefreshSidecarMetadata(MediaItem mediaItem, string path) => public Task<Unit> RefreshSidecarMetadata(MediaItem mediaItem, string path) =>

23
ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs

@ -76,7 +76,7 @@ namespace ErsatzTV.Core.Metadata
string showFolder) string showFolder)
{ {
ShowMetadata metadata = await _localMetadataProvider.GetMetadataForShow(showFolder); ShowMetadata metadata = await _localMetadataProvider.GetMetadataForShow(showFolder);
Option<Show> maybeShow = await _televisionRepository.GetShowByMetadata(metadata); Option<Show> maybeShow = await _televisionRepository.GetShowByMetadata(libraryPathId, metadata);
return await maybeShow.Match( return await maybeShow.Match(
show => Right<BaseError, Show>(show).AsTask(), show => Right<BaseError, Show>(show).AsTask(),
async () => await _televisionRepository.AddShow(libraryPathId, showFolder, metadata)); async () => await _televisionRepository.AddShow(libraryPathId, showFolder, metadata));
@ -86,9 +86,9 @@ namespace ErsatzTV.Core.Metadata
LibraryPath libraryPath, LibraryPath libraryPath,
string ffprobePath, string ffprobePath,
Show show, Show show,
string showPath) string showFolder)
{ {
foreach (string seasonFolder in _localFileSystem.ListSubdirectories(showPath).Filter(ShouldIncludeFolder) foreach (string seasonFolder in _localFileSystem.ListSubdirectories(showFolder).Filter(ShouldIncludeFolder)
.OrderBy(identity)) .OrderBy(identity))
{ {
Option<int> maybeSeasonNumber = SeasonNumberForFolder(seasonFolder); Option<int> maybeSeasonNumber = SeasonNumberForFolder(seasonFolder);
@ -97,10 +97,10 @@ namespace ErsatzTV.Core.Metadata
{ {
Either<BaseError, Season> maybeSeason = await _televisionRepository Either<BaseError, Season> maybeSeason = await _televisionRepository
.GetOrAddSeason(show, seasonFolder, seasonNumber) .GetOrAddSeason(show, seasonFolder, seasonNumber)
.BindT(UpdatePoster); .BindT(season => UpdatePoster(season, seasonFolder));
await maybeSeason.Match( await maybeSeason.Match(
season => ScanEpisodes(libraryPath, ffprobePath, season), season => ScanEpisodes(libraryPath, ffprobePath, season, seasonFolder),
_ => Task.FromResult(Unit.Default)); _ => Task.FromResult(Unit.Default));
}); });
} }
@ -111,9 +111,10 @@ namespace ErsatzTV.Core.Metadata
private async Task<Unit> ScanEpisodes( private async Task<Unit> ScanEpisodes(
LibraryPath libraryPath, LibraryPath libraryPath,
string ffprobePath, string ffprobePath,
Season season) Season season,
string seasonPath)
{ {
foreach (string file in _localFileSystem.ListFiles(season.Path) foreach (string file in _localFileSystem.ListFiles(seasonPath)
.Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f))).OrderBy(identity)) .Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f))).OrderBy(identity))
{ {
// TODO: figure out how to rebuild playlists // TODO: figure out how to rebuild playlists
@ -227,11 +228,11 @@ namespace ErsatzTV.Core.Metadata
} }
} }
private async Task<Either<BaseError, Season>> UpdatePoster(Season season) private async Task<Either<BaseError, Season>> UpdatePoster(Season season, string seasonFolder)
{ {
try try
{ {
await LocatePoster(season).IfSomeAsync( await LocatePoster(season, seasonFolder).IfSomeAsync(
async posterFile => async posterFile =>
{ {
season.SeasonMetadata ??= new List<SeasonMetadata>(); season.SeasonMetadata ??= new List<SeasonMetadata>();
@ -293,9 +294,9 @@ namespace ErsatzTV.Core.Metadata
.Filter(s => _localFileSystem.FileExists(s)) .Filter(s => _localFileSystem.FileExists(s))
.HeadOrNone(); .HeadOrNone();
private Option<string> LocatePoster(Season season) private Option<string> LocatePoster(Season season, string seasonFolder)
{ {
string folder = Path.GetDirectoryName(season.Path) ?? string.Empty; string folder = Path.GetDirectoryName(seasonFolder) ?? string.Empty;
return ImageFileExtensions return ImageFileExtensions
.Map(ext => Path.Combine(folder, $"season{season.SeasonNumber:00}-poster.{ext}")) .Map(ext => Path.Combine(folder, $"season{season.SeasonNumber:00}-poster.{ext}"))
.Filter(s => _localFileSystem.FileExists(s)) .Filter(s => _localFileSystem.FileExists(s))

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

@ -17,19 +17,27 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
{ {
private readonly IDbConnection _dbConnection; private readonly IDbConnection _dbConnection;
private readonly TvContext _dbContext; private readonly TvContext _dbContext;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MovieRepository(TvContext dbContext, IDbConnection dbConnection) public MovieRepository(
TvContext dbContext,
IDbContextFactory<TvContext> dbContextFactory,
IDbConnection dbConnection)
{ {
_dbContext = dbContext; _dbContext = dbContext;
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection; _dbConnection = dbConnection;
} }
public Task<Option<Movie>> GetMovie(int movieId) => public async Task<Option<Movie>> GetMovie(int movieId)
_dbContext.Movies {
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
return await dbContext.Movies
.Include(m => m.MovieMetadata) .Include(m => m.MovieMetadata)
.ThenInclude(m => m.Artwork) .ThenInclude(m => m.Artwork)
.SingleOrDefaultAsync(m => m.Id == movieId) .SingleOrDefaultAsync(m => m.Id == movieId)
.Map(Optional); .Map(Optional);
}
public async Task<Either<BaseError, Movie>> GetOrAdd(LibraryPath libraryPath, string path) public async Task<Either<BaseError, Movie>> GetOrAdd(LibraryPath libraryPath, string path)
{ {

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

@ -53,6 +53,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.AsNoTracking() .AsNoTracking()
.Filter(s => s.Id == televisionShowId) .Filter(s => s.Id == televisionShowId)
.Include(s => s.ShowMetadata) .Include(s => s.ShowMetadata)
.ThenInclude(sm => sm.Artwork)
.SingleOrDefaultAsync() .SingleOrDefaultAsync()
.Map(Optional); .Map(Optional);
@ -84,6 +85,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
public Task<Option<Season>> GetSeason(int televisionSeasonId) => public Task<Option<Season>> GetSeason(int televisionSeasonId) =>
_dbContext.Seasons _dbContext.Seasons
.AsNoTracking() .AsNoTracking()
.Include(s => s.SeasonMetadata)
.ThenInclude(sm => sm.Artwork)
.Include(s => s.Show) .Include(s => s.Show)
.ThenInclude(s => s.ShowMetadata) .ThenInclude(s => s.ShowMetadata)
.SingleOrDefaultAsync(s => s.Id == televisionSeasonId) .SingleOrDefaultAsync(s => s.Id == televisionSeasonId)
@ -123,6 +126,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.AsNoTracking() .AsNoTracking()
.Include(e => e.Season) .Include(e => e.Season)
.Include(e => e.EpisodeMetadata) .Include(e => e.EpisodeMetadata)
.ThenInclude(em => em.Artwork)
.SingleOrDefaultAsync(s => s.Id == televisionEpisodeId) .SingleOrDefaultAsync(s => s.Id == televisionEpisodeId)
.Map(Optional); .Map(Optional);
@ -146,13 +150,14 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.Take(pageSize) .Take(pageSize)
.ToListAsync(); .ToListAsync();
public async Task<Option<Show>> GetShowByMetadata(ShowMetadata metadata) public async Task<Option<Show>> GetShowByMetadata(int libraryPathId, ShowMetadata metadata)
{ {
Option<int> maybeId = await _dbContext.ShowMetadata Option<int> maybeId = await _dbContext.ShowMetadata
.Where(s => s.Title == metadata.Title && s.ReleaseDate == metadata.ReleaseDate) .Where(s => s.Title == metadata.Title && s.ReleaseDate == metadata.ReleaseDate)
.Where(s => s.Show.LibraryPathId == libraryPathId)
.SingleOrDefaultAsync() .SingleOrDefaultAsync()
.Map(sm => sm.ShowId) .Map(Optional)
.Map(Optional); .MapT(sm => sm.ShowId);
return await maybeId.Match( return await maybeId.Match(
id => id =>
@ -160,22 +165,20 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
return _dbContext.Shows return _dbContext.Shows
.Include(s => s.ShowMetadata) .Include(s => s.ShowMetadata)
.ThenInclude(sm => sm.Artwork) .ThenInclude(sm => sm.Artwork)
.Filter(s => s.Id == id) .OrderBy(s => s.Id)
.SingleOrDefaultAsync() .SingleOrDefaultAsync(s => s.Id == id)
.Map(Optional); .Map(Optional);
}, },
() => Option<Show>.None.AsTask()); () => Option<Show>.None.AsTask());
} }
public async Task<Either<BaseError, Show>> AddShow( public async Task<Either<BaseError, Show>> AddShow(int libraryPathId, string showFolder, ShowMetadata metadata)
int localMediaSourceId,
string showFolder,
ShowMetadata metadata)
{ {
try try
{ {
var show = new Show var show = new Show
{ {
LibraryPathId = libraryPathId,
ShowMetadata = new List<ShowMetadata> { metadata }, ShowMetadata = new List<ShowMetadata> { metadata },
Seasons = new List<Season>() Seasons = new List<Season>()
}; };
@ -191,27 +194,23 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
} }
} }
public async Task<Either<BaseError, Season>> GetOrAddSeason( public async Task<Either<BaseError, Season>> GetOrAddSeason(Show show, string path, int seasonNumber)
Show show,
string path,
int seasonNumber)
{ {
Option<Season> maybeExisting = await _dbContext.Seasons Option<Season> maybeExisting = await _dbContext.Seasons
.SingleOrDefaultAsync(i => i.Path == path); .Include(s => s.SeasonMetadata)
.ThenInclude(sm => sm.Artwork)
.SingleOrDefaultAsync(s => s.ShowId == show.Id && s.SeasonNumber == seasonNumber);
return await maybeExisting.Match( return await maybeExisting.Match(
season => Right<BaseError, Season>(season).AsTask(), season => Right<BaseError, Season>(season).AsTask(),
() => AddSeason(show, path, seasonNumber)); () => AddSeason(show, path, seasonNumber));
} }
// TODO: don't use mediaSourceId, use library path id public async Task<Either<BaseError, Episode>> GetOrAddEpisode(Season season, LibraryPath libraryPath, string path)
public async Task<Either<BaseError, Episode>> GetOrAddEpisode(
Season season,
LibraryPath libraryPath,
string path)
{ {
Option<Episode> maybeExisting = await _dbContext.Episodes Option<Episode> maybeExisting = await _dbContext.Episodes
.Include(i => i.EpisodeMetadata) .Include(i => i.EpisodeMetadata)
.ThenInclude(em => em.Artwork)
.Include(i => i.Statistics) .Include(i => i.Statistics)
.SingleOrDefaultAsync(i => i.Path == path); .SingleOrDefaultAsync(i => i.Path == path);
@ -253,17 +252,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.Filter(e => e.SeasonId == seasonId) .Filter(e => e.SeasonId == seasonId)
.ToListAsync(); .ToListAsync();
private async Task<Either<BaseError, Season>> AddSeason( private async Task<Either<BaseError, Season>> AddSeason(Show show, string path, int seasonNumber)
Show show,
string path,
int seasonNumber)
{ {
try try
{ {
var season = new Season var season = new Season
{ {
ShowId = show.Id, Path = path, SeasonNumber = seasonNumber, ShowId = show.Id,
Episodes = new List<Episode>() Path = path,
SeasonNumber = seasonNumber,
Episodes = new List<Episode>(),
SeasonMetadata = new List<SeasonMetadata>()
}; };
await _dbContext.Seasons.AddAsync(season); await _dbContext.Seasons.AddAsync(season);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
@ -275,18 +274,16 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
} }
} }
private async Task<Either<BaseError, Episode>> AddEpisode( private async Task<Either<BaseError, Episode>> AddEpisode(Season season, int libraryPathId, string path)
Season season,
int mediaSourceId,
string path)
{ {
try try
{ {
var episode = new Episode var episode = new Episode
{ {
LibraryPathId = mediaSourceId, LibraryPathId = libraryPathId,
SeasonId = season.Id, SeasonId = season.Id,
Path = path Path = path,
EpisodeMetadata = new List<EpisodeMetadata>()
}; };
await _dbContext.Episodes.AddAsync(episode); await _dbContext.Episodes.AddAsync(episode);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();

14
ErsatzTV/Controllers/PostersController.cs → ErsatzTV/Controllers/ArtworkController.cs

@ -17,8 +17,8 @@ namespace ErsatzTV.Controllers
public PostersController(IMediator mediator) => _mediator = mediator; public PostersController(IMediator mediator) => _mediator = mediator;
[HttpGet("/posters/{fileName}")] [HttpGet("/artwork/posters/{fileName}")]
public async Task<IActionResult> GetImage(string fileName) public async Task<IActionResult> GetPoster(string fileName)
{ {
Either<BaseError, ImageViewModel> imageContents = Either<BaseError, ImageViewModel> imageContents =
await _mediator.Send(new GetImageContents(fileName, ArtworkKind.Poster, 440)); await _mediator.Send(new GetImageContents(fileName, ArtworkKind.Poster, 440));
@ -26,5 +26,15 @@ namespace ErsatzTV.Controllers
Left: _ => new NotFoundResult(), Left: _ => new NotFoundResult(),
Right: r => new FileContentResult(r.Contents, r.MimeType)); Right: r => new FileContentResult(r.Contents, r.MimeType));
} }
[HttpGet("/artwork/thumbnails/{fileName}")]
public async Task<IActionResult> GetThumbnail(string fileName)
{
Either<BaseError, ImageViewModel> imageContents =
await _mediator.Send(new GetImageContents(fileName, ArtworkKind.Thumbnail, 220));
return imageContents.Match<IActionResult>(
Left: _ => new NotFoundResult(),
Right: r => new FileContentResult(r.Contents, r.MimeType));
}
} }
} }

2
ErsatzTV/Pages/Movie.razor

@ -14,7 +14,7 @@
@if (!string.IsNullOrWhiteSpace(_movie.Poster)) @if (!string.IsNullOrWhiteSpace(_movie.Poster))
{ {
<MudPaper Style="flex-shrink: 0;"> <MudPaper Style="flex-shrink: 0;">
<MudCardMedia Image="@($"/posters/{_movie.Poster}")" Style="height: 440px; width: 304px;"/> <MudCardMedia Image="@($"/artwork/posters/{_movie.Poster}")" Style="height: 440px; width: 304px;"/>
</MudPaper> </MudPaper>
} }
<MudCardContent Class="mx-3 my-3"> <MudCardContent Class="mx-3 my-3">

2
ErsatzTV/Pages/TelevisionEpisode.razor

@ -14,7 +14,7 @@
@if (!string.IsNullOrWhiteSpace(_episode.Poster)) @if (!string.IsNullOrWhiteSpace(_episode.Poster))
{ {
<MudPaper style="display: flex; flex-direction: column"> <MudPaper style="display: flex; flex-direction: column">
<MudCardMedia Image="@($"/posters/{_episode.Poster}")" Style="flex-grow: 1; height: 220px; width: 392px;"/> <MudCardMedia Image="@($"/artwork/thumbnails/{_episode.Poster}")" Style="flex-grow: 1; height: 220px; width: 392px;"/>
</MudPaper> </MudPaper>
} }
<MudCardContent Class="ml-3"> <MudCardContent Class="ml-3">

5
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -18,7 +18,7 @@
@if (!string.IsNullOrWhiteSpace(_season.Poster)) @if (!string.IsNullOrWhiteSpace(_season.Poster))
{ {
<MudPaper Style="flex-shrink: 0;"> <MudPaper Style="flex-shrink: 0;">
<MudCardMedia Image="@($"/posters/{_season.Poster}")" Style="height: 440px; width: 304px;"/> <MudCardMedia Image="@($"/artwork/posters/{_season.Poster}")" Style="height: 440px; width: 304px;"/>
</MudPaper> </MudPaper>
} }
<MudCardContent Class="mx-3 my-3"> <MudCardContent Class="mx-3 my-3">
@ -55,7 +55,8 @@
Link="@($"/media/tv/episodes/{card.EpisodeId}")" Link="@($"/media/tv/episodes/{card.EpisodeId}")"
DataRefreshed="@(() => RefreshData())" DataRefreshed="@(() => RefreshData())"
ContainerClass="media-card-episode-container mx-2" ContainerClass="media-card-episode-container mx-2"
CardClass="media-card-episode"/> CardClass="media-card-episode"
ArtworkKind="@ArtworkKind.Thumbnail"/>
} }
</MudContainer> </MudContainer>

2
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -18,7 +18,7 @@
@if (!string.IsNullOrWhiteSpace(_show.Poster)) @if (!string.IsNullOrWhiteSpace(_show.Poster))
{ {
<MudPaper Style="flex-shrink: 0;"> <MudPaper Style="flex-shrink: 0;">
<MudCardMedia Image="@($"/posters/{_show.Poster}")" Style="height: 440px; width: 304px;"/> <MudCardMedia Image="@($"/artwork/posters/{_show.Poster}")" Style="height: 440px; width: 304px;"/>
</MudPaper> </MudPaper>
} }
<MudCardContent Class="mx-3 my-3"> <MudCardContent Class="mx-3 my-3">

17
ErsatzTV/Shared/MediaCard.razor

@ -6,7 +6,7 @@
@if (!string.IsNullOrWhiteSpace(Link)) @if (!string.IsNullOrWhiteSpace(Link))
{ {
<div style="position: relative"> <div style="position: relative">
<MudPaper Class="@($"media-card {CardClass}")" Style="@PosterForItem()"> <MudPaper Class="@($"media-card {CardClass}")" Style="@ArtworkForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster)) @if (string.IsNullOrWhiteSpace(Data.Poster))
{ {
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled"> <MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled">
@ -29,7 +29,7 @@
} }
else else
{ {
<MudPaper Class="@($"media-card {CardClass}")" Style="@PosterForItem()"> <MudPaper Class="@($"media-card {CardClass}")" Style="@ArtworkForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster)) @if (string.IsNullOrWhiteSpace(Data.Poster))
{ {
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled"> <MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-disabled">
@ -72,6 +72,9 @@
[Parameter] [Parameter]
public string CardClass { get; set; } public string CardClass { get; set; }
[Parameter]
public ArtworkKind ArtworkKind { get; set; }
[Parameter] [Parameter]
public EventCallback<MediaCardViewModel> DeleteClicked { get; set; } public EventCallback<MediaCardViewModel> DeleteClicked { get; set; }
@ -86,8 +89,14 @@
return int.TryParse(first, out _) ? "#" : first; return int.TryParse(first, out _) ? "#" : first;
} }
private string PosterForItem() => string.IsNullOrWhiteSpace(Data.Poster) private string ArtworkForItem() => string.IsNullOrWhiteSpace(Data.Poster)
? "position: relative" ? "position: relative"
: $"position: relative; background-image: url(/posters/{Data.Poster}); background-size: cover"; : $"position: relative; background-image: url(/artwork/{PathForArtwork()}/{Data.Poster}); background-size: cover";
private string PathForArtwork() => ArtworkKind switch
{
ArtworkKind.Thumbnail => "thumbnails",
_ => "posters"
};
} }
Loading…
Cancel
Save