rework media layout (#22)
* replace media items tables with card grids * style cleanup * add basic paging * sort and page in the db * optimize sql for movies * support movie posters * resize movie posters and store in cache with channel logos * fix bug preventing folders with more than 50 chars as local media sources * support tv posters
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ErsatzTV.Application.MediaItems
|
||||
{
|
||||
public record AggregateMediaItemResults(int Count, List<AggregateMediaItemViewModel> DataPage);
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace ErsatzTV.Application.MediaItems
|
||||
{
|
||||
public record AggregateMediaItemViewModel(string Source, string Title, int Count, string Duration);
|
||||
public record AggregateMediaItemViewModel(
|
||||
string Title,
|
||||
string Subtitle,
|
||||
string SortTitle,
|
||||
string Poster);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace ErsatzTV.Application.MediaItems.Commands
|
||||
{
|
||||
private readonly IConfigElementRepository _configElementRepository;
|
||||
private readonly ILocalMetadataProvider _localMetadataProvider;
|
||||
private readonly ILocalPosterProvider _localPosterProvider;
|
||||
private readonly ILocalStatisticsProvider _localStatisticsProvider;
|
||||
private readonly IMediaItemRepository _mediaItemRepository;
|
||||
private readonly IMediaSourceRepository _mediaSourceRepository;
|
||||
@@ -27,7 +28,8 @@ namespace ErsatzTV.Application.MediaItems.Commands
|
||||
IConfigElementRepository configElementRepository,
|
||||
ISmartCollectionBuilder smartCollectionBuilder,
|
||||
ILocalMetadataProvider localMetadataProvider,
|
||||
ILocalStatisticsProvider localStatisticsProvider)
|
||||
ILocalStatisticsProvider localStatisticsProvider,
|
||||
ILocalPosterProvider localPosterProvider)
|
||||
{
|
||||
_mediaItemRepository = mediaItemRepository;
|
||||
_mediaSourceRepository = mediaSourceRepository;
|
||||
@@ -35,6 +37,7 @@ namespace ErsatzTV.Application.MediaItems.Commands
|
||||
_smartCollectionBuilder = smartCollectionBuilder;
|
||||
_localMetadataProvider = localMetadataProvider;
|
||||
_localStatisticsProvider = localStatisticsProvider;
|
||||
_localPosterProvider = localPosterProvider;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, MediaItemViewModel>> Handle(
|
||||
@@ -50,6 +53,7 @@ namespace ErsatzTV.Application.MediaItems.Commands
|
||||
|
||||
await _localStatisticsProvider.RefreshStatistics(parameters.FFprobePath, parameters.MediaItem);
|
||||
await _localMetadataProvider.RefreshMetadata(parameters.MediaItem);
|
||||
await _localPosterProvider.RefreshPoster(parameters.MediaItem);
|
||||
await _smartCollectionBuilder.RefreshSmartCollections(parameters.MediaItem);
|
||||
|
||||
return ProjectToViewModel(parameters.MediaItem);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace ErsatzTV.Application.MediaItems.Commands
|
||||
{
|
||||
public record RefreshMediaItemPoster : RefreshMediaItem
|
||||
{
|
||||
public RefreshMediaItemPoster(int mediaItemId) : base(mediaItemId)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaItems.Queries
|
||||
{
|
||||
public record GetAggregateMediaItems
|
||||
(MediaType MediaType, string SearchString) : IRequest<List<AggregateMediaItemViewModel>>;
|
||||
(MediaType MediaType, int PageNumber, int PageSize) : IRequest<AggregateMediaItemResults>;
|
||||
}
|
||||
|
||||
@@ -1,46 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.AggregateModels;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaItems.Queries
|
||||
{
|
||||
public class
|
||||
GetAggregateMediaItemsHandler : IRequestHandler<GetAggregateMediaItems, List<AggregateMediaItemViewModel>>
|
||||
GetAggregateMediaItemsHandler : IRequestHandler<GetAggregateMediaItems, AggregateMediaItemResults>
|
||||
{
|
||||
private readonly IMediaItemRepository _mediaItemRepository;
|
||||
|
||||
public GetAggregateMediaItemsHandler(IMediaItemRepository mediaItemRepository) =>
|
||||
_mediaItemRepository = mediaItemRepository;
|
||||
|
||||
public async Task<List<AggregateMediaItemViewModel>> Handle(
|
||||
public async Task<AggregateMediaItemResults> Handle(
|
||||
GetAggregateMediaItems request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
IEnumerable<MediaItem> allItems = await _mediaItemRepository.GetAll(request.MediaType);
|
||||
int count = await _mediaItemRepository.GetCountByType(request.MediaType);
|
||||
|
||||
if (!string.IsNullOrEmpty(request.SearchString))
|
||||
{
|
||||
allItems = allItems.Filter(
|
||||
i => i.Metadata?.Title.Contains(request.SearchString, StringComparison.OrdinalIgnoreCase) ==
|
||||
true);
|
||||
}
|
||||
IEnumerable<MediaItemSummary> allItems = await _mediaItemRepository.GetPageByType(
|
||||
request.MediaType,
|
||||
request.PageNumber,
|
||||
request.PageSize);
|
||||
|
||||
return allItems.GroupBy(c => new { c.Source.Name, c.Metadata.Title }).Map(
|
||||
group => new AggregateMediaItemViewModel(
|
||||
group.Key.Name,
|
||||
group.Key.Title,
|
||||
group.Count(),
|
||||
group.Count() == 1 ? DisplayDuration(group.Head()) : string.Empty))
|
||||
var results = allItems
|
||||
.Map(
|
||||
s => new AggregateMediaItemViewModel(
|
||||
s.Title,
|
||||
s.Subtitle,
|
||||
s.SortTitle,
|
||||
s.Poster))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static string DisplayDuration(MediaItem mediaItem) => string.Format(
|
||||
mediaItem.Metadata?.Duration.TotalHours >= 1 ? @"{0:h\:mm\:ss}" : @"{0:mm\:ss}",
|
||||
mediaItem.Metadata?.Duration);
|
||||
return new AggregateMediaItemResults(count, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user