* spike new scanner * add existing items to new scanner * add collection refresh actions * add tv show metadata and posters * update metadata and posters when nfo/poster files are updated * add "remove" action, test for all supported file extensions * update statistics when primary video file is updated * reflect that collections are "sourced" from nfo * implement most scanning actions * cleanup * fix startup * cross-platform scanner tests
94 lines
3.4 KiB
C#
94 lines
3.4 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Interfaces.Images;
|
|
using ErsatzTV.Core.Interfaces.Metadata;
|
|
using ErsatzTV.Core.Interfaces.Repositories;
|
|
using LanguageExt;
|
|
using Microsoft.Extensions.Logging;
|
|
using static LanguageExt.Prelude;
|
|
|
|
namespace ErsatzTV.Core.Metadata
|
|
{
|
|
public class LocalPosterProvider : ILocalPosterProvider
|
|
{
|
|
private static readonly string[] SupportedExtensions = { "jpg", "jpeg", "png", "gif", "tbn" };
|
|
|
|
private readonly IImageCache _imageCache;
|
|
private readonly ILogger<LocalPosterProvider> _logger;
|
|
private readonly IMediaItemRepository _mediaItemRepository;
|
|
|
|
public LocalPosterProvider(
|
|
IMediaItemRepository mediaItemRepository,
|
|
IImageCache imageCache,
|
|
ILogger<LocalPosterProvider> logger)
|
|
{
|
|
_mediaItemRepository = mediaItemRepository;
|
|
_imageCache = imageCache;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task RefreshPoster(MediaItem mediaItem)
|
|
{
|
|
Option<string> maybePosterPath = mediaItem.Metadata.MediaType switch
|
|
{
|
|
MediaType.Movie => RefreshMoviePoster(mediaItem),
|
|
MediaType.TvShow => RefreshTelevisionPoster(mediaItem),
|
|
_ => None
|
|
};
|
|
|
|
await maybePosterPath.Match(
|
|
path => SavePosterToDisk(mediaItem, path),
|
|
Task.CompletedTask);
|
|
}
|
|
|
|
private static Option<string> RefreshMoviePoster(MediaItem mediaItem)
|
|
{
|
|
string folder = Path.GetDirectoryName(mediaItem.Path);
|
|
if (folder != null)
|
|
{
|
|
IEnumerable<string> possiblePaths = SupportedExtensions.Collect(
|
|
e => new[] { $"poster.{e}", Path.GetFileNameWithoutExtension(mediaItem.Path) + $"-poster.{e}" });
|
|
Option<string> maybePoster =
|
|
possiblePaths.Map(p => Path.Combine(folder, p)).FirstOrDefault(File.Exists);
|
|
return maybePoster;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
private Option<string> RefreshTelevisionPoster(MediaItem mediaItem)
|
|
{
|
|
string folder = Directory.GetParent(Path.GetDirectoryName(mediaItem.Path) ?? string.Empty)?.FullName;
|
|
if (folder != null)
|
|
{
|
|
IEnumerable<string> possiblePaths = SupportedExtensions.Collect(e => new[] { $"poster.{e}" });
|
|
Option<string> maybePoster =
|
|
possiblePaths.Map(p => Path.Combine(folder, p)).FirstOrDefault(File.Exists);
|
|
return maybePoster;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
public async Task SavePosterToDisk(MediaItem mediaItem, string posterPath)
|
|
{
|
|
byte[] originalBytes = await File.ReadAllBytesAsync(posterPath);
|
|
Either<BaseError, string> maybeHash = await _imageCache.ResizeAndSaveImage(originalBytes, 220, null);
|
|
await maybeHash.Match(
|
|
hash =>
|
|
{
|
|
mediaItem.Poster = hash;
|
|
return _mediaItemRepository.Update(mediaItem);
|
|
},
|
|
error =>
|
|
{
|
|
_logger.LogWarning("Unable to save poster to disk from {Path}: {Error}", posterPath, error.Value);
|
|
return Task.CompletedTask;
|
|
});
|
|
}
|
|
}
|
|
}
|