Metadata Downloading (#3525)
This commit is contained in:
parent
eb66763078
commit
f4fd7230ea
108 changed files with 6296 additions and 484 deletions
|
@ -4,10 +4,12 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Constants;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.SignalR;
|
||||
using EasyCaching.Core;
|
||||
using Flurl;
|
||||
using Flurl.Http;
|
||||
|
@ -25,6 +27,8 @@ public interface ICoverDbService
|
|||
Task<string> DownloadFaviconAsync(string url, EncodeFormat encodeFormat);
|
||||
Task<string> DownloadPublisherImageAsync(string publisherName, EncodeFormat encodeFormat);
|
||||
Task<string?> DownloadPersonImageAsync(Person person, EncodeFormat encodeFormat);
|
||||
Task<string?> DownloadPersonImageAsync(Person person, EncodeFormat encodeFormat, string url);
|
||||
Task SetPersonCoverImage(Person person, string url, bool fromBase64 = true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,6 +38,9 @@ public class CoverDbService : ICoverDbService
|
|||
private readonly IDirectoryService _directoryService;
|
||||
private readonly IEasyCachingProviderFactory _cacheFactory;
|
||||
private readonly IHostEnvironment _env;
|
||||
private readonly IImageService _imageService;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IEventHub _eventHub;
|
||||
|
||||
private const string NewHost = "https://www.kavitareader.com/CoversDB/";
|
||||
|
||||
|
@ -57,12 +64,16 @@ public class CoverDbService : ICoverDbService
|
|||
private static readonly TimeSpan CacheDuration = TimeSpan.FromDays(1);
|
||||
|
||||
public CoverDbService(ILogger<CoverDbService> logger, IDirectoryService directoryService,
|
||||
IEasyCachingProviderFactory cacheFactory, IHostEnvironment env)
|
||||
IEasyCachingProviderFactory cacheFactory, IHostEnvironment env, IImageService imageService,
|
||||
IUnitOfWork unitOfWork, IEventHub eventHub)
|
||||
{
|
||||
_logger = logger;
|
||||
_directoryService = directoryService;
|
||||
_cacheFactory = cacheFactory;
|
||||
_env = env;
|
||||
_imageService = imageService;
|
||||
_unitOfWork = unitOfWork;
|
||||
_eventHub = eventHub;
|
||||
}
|
||||
|
||||
public async Task<string> DownloadFaviconAsync(string url, EncodeFormat encodeFormat)
|
||||
|
@ -225,36 +236,37 @@ public class CoverDbService : ICoverDbService
|
|||
{
|
||||
throw new KavitaException($"Could not grab person image for {person.Name}");
|
||||
}
|
||||
return await DownloadPersonImageAsync(person, encodeFormat, personImageLink);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error downloading image for {PersonName}", person.Name);
|
||||
}
|
||||
|
||||
// Create the destination file path
|
||||
var filename = ImageService.GetPersonFormat(person.Id) + encodeFormat.GetExtension();
|
||||
var targetFile = Path.Combine(_directoryService.CoverImageDirectory, filename);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure if file exists, we delete to overwrite
|
||||
|
||||
|
||||
_logger.LogTrace("Fetching publisher image from {Url}", personImageLink.Sanitize());
|
||||
// Download the file using Flurl
|
||||
var personStream = await personImageLink
|
||||
.AllowHttpStatus("2xx,304")
|
||||
.GetStreamAsync();
|
||||
|
||||
using var image = Image.NewFromStream(personStream);
|
||||
switch (encodeFormat)
|
||||
/// <summary>
|
||||
/// Attempts to download the Person cover image from a Url
|
||||
/// </summary>
|
||||
/// <param name="person"></param>
|
||||
/// <param name="encodeFormat"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="KavitaException"></exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public async Task<string?> DownloadPersonImageAsync(Person person, EncodeFormat encodeFormat, string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
var personImageLink = await GetCoverPersonImagePath(person);
|
||||
if (string.IsNullOrEmpty(personImageLink))
|
||||
{
|
||||
case EncodeFormat.PNG:
|
||||
image.Pngsave(targetFile);
|
||||
break;
|
||||
case EncodeFormat.WEBP:
|
||||
image.Webpsave(targetFile);
|
||||
break;
|
||||
case EncodeFormat.AVIF:
|
||||
image.Heifsave(targetFile);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(encodeFormat), encodeFormat, null);
|
||||
throw new KavitaException($"Could not grab person image for {person.Name}");
|
||||
}
|
||||
|
||||
|
||||
var filename = await DownloadImageFromUrl(ImageService.GetPersonFormat(person.Id), encodeFormat, personImageLink);
|
||||
|
||||
_logger.LogDebug("Person image for {PersonName} downloaded and saved successfully", person.Name);
|
||||
|
||||
return filename;
|
||||
|
@ -266,6 +278,39 @@ public class CoverDbService : ICoverDbService
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<string> DownloadImageFromUrl(string filenameWithoutExtension, EncodeFormat encodeFormat, string url)
|
||||
{
|
||||
// Create the destination file path
|
||||
var filename = filenameWithoutExtension + encodeFormat.GetExtension();
|
||||
var targetFile = Path.Combine(_directoryService.CoverImageDirectory, filename);
|
||||
|
||||
// Ensure if file exists, we delete to overwrite
|
||||
|
||||
_logger.LogTrace("Fetching person image from {Url}", url.Sanitize());
|
||||
// Download the file using Flurl
|
||||
var personStream = await url
|
||||
.AllowHttpStatus("2xx,304")
|
||||
.GetStreamAsync();
|
||||
|
||||
using var image = Image.NewFromStream(personStream);
|
||||
switch (encodeFormat)
|
||||
{
|
||||
case EncodeFormat.PNG:
|
||||
image.Pngsave(targetFile);
|
||||
break;
|
||||
case EncodeFormat.WEBP:
|
||||
image.Webpsave(targetFile);
|
||||
break;
|
||||
case EncodeFormat.AVIF:
|
||||
image.Heifsave(targetFile);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(encodeFormat), encodeFormat, null);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
private async Task<string> GetCoverPersonImagePath(Person person)
|
||||
{
|
||||
var tempFile = Path.Join(_directoryService.LongTermCacheDirectory, "people.yml");
|
||||
|
@ -414,4 +459,49 @@ public class CoverDbService : ICoverDbService
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task SetPersonCoverImage(Person person, string url, bool fromBase64 = true)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
var filePath = await CreateThumbnail(url, $"{ImageService.GetPersonFormat(person.Id)}", fromBase64);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
person.CoverImage = filePath;
|
||||
person.CoverImageLocked = true;
|
||||
_imageService.UpdateColorScape(person);
|
||||
_unitOfWork.PersonRepository.Update(person);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
person.CoverImage = string.Empty;
|
||||
person.CoverImageLocked = false;
|
||||
_imageService.UpdateColorScape(person);
|
||||
_unitOfWork.PersonRepository.Update(person);
|
||||
}
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
|
||||
MessageFactory.CoverUpdateEvent(person.Id, MessageFactoryEntityTypes.Person), false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> CreateThumbnail(string url, string filename, bool fromBase64 = true)
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var encodeFormat = settings.EncodeMediaAs;
|
||||
var coverImageSize = settings.CoverImageSize;
|
||||
|
||||
if (fromBase64)
|
||||
{
|
||||
return _imageService.CreateThumbnailFromBase64(url,
|
||||
filename, encodeFormat, coverImageSize.GetDimensions().Width);
|
||||
}
|
||||
|
||||
return await DownloadImageFromUrl(filename, encodeFormat, url);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue