diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs index 11dfd6c4..e3454fc1 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs @@ -29,7 +29,7 @@ namespace Kyoo.Abstractions.Models public interface IThumbnails { /// - /// A poster is a 9/16 format image with the cover of the resource. + /// A poster is a 2/3 format image with the cover of the resource. /// public Image? Poster { get; set; } @@ -82,6 +82,12 @@ namespace Kyoo.Abstractions.Models return base.ConvertFrom(context, culture, value)!; return new Image(source); } + + /// + public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) + { + return false; + } } } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs index 6d33283e..8e421c7c 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs @@ -341,8 +341,15 @@ namespace Kyoo.Core.Controllers if (obj == null) throw new ArgumentNullException(nameof(obj)); await Validate(obj); - // if (obj is IThumbnails thumbs) - // await _thumbnailsManager.DownloadImages(thumbs); + if (obj is IThumbnails thumbs) + { + if (thumbs.Poster != null) + Database.Entry(thumbs).Reference(x => x.Poster).TargetEntry.State = EntityState.Added; + if (thumbs.Thumbnail != null) + Database.Entry(thumbs).Reference(x => x.Thumbnail).TargetEntry.State = EntityState.Added; + if (thumbs.Logo != null) + Database.Entry(thumbs).Reference(x => x.Logo).TargetEntry.State = EntityState.Added; + } return obj; } @@ -427,6 +434,13 @@ namespace Kyoo.Core.Controllers /// A representing the asynchronous operation. protected virtual Task EditRelations(T resource, T changed, bool resetOld) { + if (resource is IThumbnails thumbs) + { + // FIXME: I think this throws if poster is set to null. + Database.Entry(thumbs).Reference(x => x.Poster).TargetEntry.State = EntityState.Modified; + Database.Entry(thumbs).Reference(x => x.Thumbnail).TargetEntry.State = EntityState.Modified; + Database.Entry(thumbs).Reference(x => x.Logo).TargetEntry.State = EntityState.Modified; + } return Validate(resource); } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs index 89c00fdd..bf6f3e5e 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs @@ -66,6 +66,8 @@ namespace Kyoo.Core.Controllers { await base.Create(obj); _database.Entry(obj).State = EntityState.Added; + if (obj.Logo != null) + _database.Entry(obj).Reference(x => x.Logo).TargetEntry.State = EntityState.Added; await _database.SaveChangesAsync(() => Get(obj.Slug)); OnResourceCreated(obj); return obj; diff --git a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs index b566c195..d11fd898 100644 --- a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs +++ b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs @@ -20,7 +20,7 @@ using System; using System.IO; using System.Net.Http; using System.Threading.Tasks; -using BlurHashSharp.SkiaSharp; +using Blurhash.SkiaSharp; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Microsoft.Extensions.Logging; @@ -62,28 +62,33 @@ namespace Kyoo.Core.Controllers await reader.CopyToAsync(file); } - private async Task _DownloadImage(string? url, string localPath, string what) + private async Task _DownloadImage(Image? image, string localPath, string what) { - if (url == null) + if (image == null) return; try { _logger.LogInformation("Downloading image {What}", what); HttpClient client = _clientFactory.CreateClient(); - HttpResponseMessage response = await client.GetAsync(url); + HttpResponseMessage response = await client.GetAsync(image.Source); response.EnsureSuccessStatusCode(); await using Stream reader = await response.Content.ReadAsStreamAsync(); - SKBitmap bitmap = SKBitmap.Decode(reader); + using SKCodec codec = SKCodec.Create(reader); + SKImageInfo info = codec.Info; + info.ColorType = SKColorType.Rgba8888; + SKBitmap bitmap = SKBitmap.Decode(codec, info); bitmap.Resize(new SKSizeI(bitmap.Width, bitmap.Height), SKFilterQuality.High); await _WriteTo(bitmap, $"{localPath}.{ImageQuality.High.ToString().ToLowerInvariant()}.jpg"); - bitmap.Resize(new SKSizeI(bitmap.Width, bitmap.Height), SKFilterQuality.Medium); + bitmap.Resize(new SKSizeI((int)(bitmap.Width / 1.5), (int)(bitmap.Height / 1.5)), SKFilterQuality.Medium); await _WriteTo(bitmap, $"{localPath}.{ImageQuality.Medium.ToString().ToLowerInvariant()}.jpg"); - bitmap.Resize(new SKSizeI(bitmap.Width, bitmap.Height), SKFilterQuality.Low); + bitmap.Resize(new SKSizeI(bitmap.Width / 2, bitmap.Height / 2), SKFilterQuality.Low); await _WriteTo(bitmap, $"{localPath}.{ImageQuality.Low.ToString().ToLowerInvariant()}.jpg"); + + image.Blurhash = Blurhasher.Encode(bitmap, 4, 3); } catch (Exception ex) { @@ -99,9 +104,9 @@ namespace Kyoo.Core.Controllers throw new ArgumentNullException(nameof(item)); string name = item is IResource res ? res.Slug : "???"; - await _DownloadImage(item.Poster?.Source, _GetBaseImagePath(item, "poster"), $"The poster of {name}"); - await _DownloadImage(item.Thumbnail?.Source, _GetBaseImagePath(item, "thumbnail"), $"The poster of {name}"); - await _DownloadImage(item.Logo?.Source, _GetBaseImagePath(item, "logo"), $"The poster of {name}"); + await _DownloadImage(item.Poster, _GetBaseImagePath(item, "poster"), $"The poster of {name}"); + await _DownloadImage(item.Thumbnail, _GetBaseImagePath(item, "thumbnail"), $"The poster of {name}"); + await _DownloadImage(item.Logo, _GetBaseImagePath(item, "logo"), $"The poster of {name}"); } private static string _GetBaseImagePath(T item, string image) diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj index 332e4b6a..b4061a1c 100644 --- a/back/src/Kyoo.Core/Kyoo.Core.csproj +++ b/back/src/Kyoo.Core/Kyoo.Core.csproj @@ -6,7 +6,7 @@ - + diff --git a/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs b/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs index 9e6c95f5..d02cb624 100644 --- a/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs +++ b/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs @@ -135,10 +135,8 @@ namespace Kyoo.Core.Api /// public override async Task> Create([FromBody] T resource) { - // TODO: Remove this method and use a websocket API to do that. - ActionResult ret = await base.Create(resource); - await _thumbs.DownloadImages(ret.Value); - return ret; + await _thumbs.DownloadImages(resource); + return await base.Create(resource); } } } diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/ImageConvertor.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/ImageConvertor.cs deleted file mode 100644 index 52674995..00000000 --- a/back/src/Kyoo.Core/Views/Helper/Serializers/ImageConvertor.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.Collections.Generic; -using Kyoo.Abstractions.Models; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Kyoo.Core.Api -{ - public class ImageConverter : JsonConverter - { - /// - public override void WriteJson(JsonWriter writer, Image value, JsonSerializer serializer) - { - JObject obj = JObject.FromObject(value, serializer); - obj.WriteTo(writer); - } - - /// - public override Image ReadJson(JsonReader reader, - Type objectType, - Image existingValue, - bool hasExistingValue, - JsonSerializer serializer) - { - throw new NotImplementedException(); - } - } -} diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs index 98429630..e8cacb82 100644 --- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs +++ b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs @@ -78,29 +78,28 @@ namespace Kyoo.Core.Api protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { IList properties = base.CreateProperties(type, memberSerialization); - if (!type.IsAssignableTo(typeof(Image))) - return properties; + // if (!type.IsAssignableTo(typeof(Image))) + // return properties; // foreach ((int id, string image) in Images.ImageName) // { - // properties.Add(new JsonProperty - // { - // DeclaringType = type, - // PropertyName = image.ToLower(), - // UnderlyingName = image, - // PropertyType = typeof(string), - // Readable = true, - // Writable = false, - // ItemIsReference = false, - // TypeNameHandling = TypeNameHandling.None, - // ShouldSerialize = x => - // { - // IThumbnails thumb = (IThumbnails)x; - // return thumb?.Images?.ContainsKey(id) == true; - // }, - // ValueProvider = new ThumbnailProvider(id) - // }); + // properties.Add(new JsonProperty + // { + // DeclaringType = type, + // PropertyName = image.ToLower(), + // UnderlyingName = image, + // PropertyType = typeof(string), + // Readable = true, + // Writable = false, + // ItemIsReference = false, + // TypeNameHandling = TypeNameHandling.None, + // ShouldSerialize = x => + // { + // IThumbnails thumb = (IThumbnails)x; + // return thumb?.Images?.ContainsKey(id) == true; + // }, + // ValueProvider = new ThumbnailProvider(id) + // }); // } - return properties; }