using System.Globalization; using Microsoft.Extensions.Logging; using Piwigo.Client.Contract; namespace Piwigo.Client; public class ImageApi : IImageApi { private const string DateFormat = "yyyy-MM-dd"; private const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; private readonly IPiwigoContext _context; private readonly ILogger _logger; public ImageApi(IPiwigoContext context, ILogger logger) { _context = context ?? throw new ArgumentNullException(nameof(context)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task AddCommentAsync(int imageId, string? author, string content, string key, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "image_id", imageId.ToString() }, { "content", content }, { "key", key } }; formParams.AddIfValueNotNull("author", author); var response = await _context.PostAsync>(_logger, "pwg.images.addComment", formParams, cancellationToken); return response.Result.Comment.Id; } public async Task AddChunkAsync(byte[] data, string originalSum, int position, CancellationToken cancellationToken = default) { var base64Data = Convert.ToBase64String(data); var formParams = new Dictionary { { "data", base64Data }, { "original_sum", originalSum }, // type = file is required for compatibility reasons. // There is no other value allowed { "type", "file" }, { "position", position.ToString() } }; await _context.PostAsync(_logger, "pwg.images.addChunk", formParams, cancellationToken); } public Task AddAsync(ImageUpload imageUpload, CancellationToken cancellationToken = default) { return AddOrUpdateAsync(null, imageUpload, cancellationToken); } public Task UpdateAsync(int imageId, ImageUpload imageUpload, CancellationToken cancellationToken = default) { return AddOrUpdateAsync(imageId, imageUpload, cancellationToken); } public async Task GetInfoAsync(int imageId, int? commentsPage, int? commentsPerPage, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "image_id", imageId.ToString() } }; formParams.AddIfValueNotNull("comments_page", commentsPage?.ToString()); formParams.AddIfValueNotNull("comments_per_page", commentsPerPage?.ToString()); var response = await _context.PostAsync>(_logger, "pwg.images.getInfo", formParams, cancellationToken); return response.Result; } public async Task ReadyForUploadAsync(CancellationToken cancellationToken = default) { var response = await _context.PostAsync>(_logger, "pwg.images.checkUpload", new Dictionary(), cancellationToken); return response.Result.IsReady; } public async Task CheckImageAsync(int imageId, string md5Sum, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "image_id", imageId.ToString() }, { "file_sum", md5Sum } }; var response = await _context.PostAsync>(_logger, "pwg.images.checkFiles", formParams, cancellationToken); return response.Result.ToImageCheckStatus(); } public async Task DeleteAsync(int imageId, string apiToken, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "image_id", imageId.ToString() }, { "pwg_token", apiToken } }; var response = await _context.PostAsync>(_logger, "pwg.images.delete", formParams, cancellationToken); return response.Result; } public async Task DeleteOrphansAsync(string apiToken, int? blockSize = null, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "pwg_token", apiToken } }; formParams.AddIfValueNotNull("block_size", blockSize?.ToString()); var response = await _context.PostAsync>(_logger, "pwg.images.deleteOrphans", formParams, cancellationToken); return response.Result; } public async Task> ExistsByMd5SumsAsync(IEnumerable md5Sums, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "md5sum_list", string.Join(",", md5Sums) } }; var response = await _context.PostAsync>>(_logger, "pwg.images.exist", formParams, cancellationToken); return response.Result; } public async Task RateAsync(int imageId, int rate, CancellationToken cancellationToken = default) { var formParams = new Dictionary { { "image_id", imageId.ToString() }, { "rate", rate.ToString() } }; var response = await _context.PostAsync>(_logger, "pwg.images.rate", formParams, cancellationToken); return response.Result; } public async Task SetInfoAsync(int imageId, ImageInfo imageInfo, ValueUpdateMode singleValueMode = ValueUpdateMode.Append, ValueUpdateMode multiValueMode = ValueUpdateMode.Append, CancellationToken cancellationToken = default) { var singleMode = singleValueMode switch { ValueUpdateMode.Append => "fill_if_empty", ValueUpdateMode.Replace => "replace", _ => throw new ArgumentOutOfRangeException(nameof(singleValueMode), singleValueMode, null) }; var multiMode = multiValueMode switch { ValueUpdateMode.Append => "append", ValueUpdateMode.Replace => "replace", _ => throw new ArgumentOutOfRangeException(nameof(singleValueMode), singleValueMode, null) }; var formParams = new Dictionary { { "image_id", imageId.ToString() }, { "single_value_mode", singleMode }, { "multiple_value_mode", multiMode } }; formParams.AddIfValueNotNull("file", imageInfo.FileName); AddImageInfoToForm(formParams, imageInfo); await _context.PostAsync(_logger, "pwg.images.setInfo", formParams, cancellationToken); } public async Task GetImagesAsync(int albumId, bool recursive, ImagePagingInfo page, ImageFilter filter, ImageOrder order = ImageOrder.Name, CancellationToken cancellationToken = default) { var orderValue = order switch { ImageOrder.Id => "id", ImageOrder.File => "file", ImageOrder.Name => "name", ImageOrder.Hit => "hit", ImageOrder.RatingScore => "rating_score", ImageOrder.DateCreation => "date_creation", ImageOrder.DateAvailable => "date_available", ImageOrder.Random => "random", _ => throw new ArgumentOutOfRangeException(nameof(order), order, null) }; var formParams = new Dictionary { { "cat_id", albumId.ToString() }, { "recursive", recursive.ToString() }, { "per_page", page.PageSize.ToString() }, { "page", page.Page.ToString() }, { "order", orderValue } }; formParams.AddIfValueNotNull("f_min_rate", filter.MinRate?.ToString(CultureInfo.InvariantCulture)); formParams.AddIfValueNotNull("f_max_rate", filter.MaxRate?.ToString(CultureInfo.InvariantCulture)); formParams.AddIfValueNotNull("f_min_hit", filter.MinHit?.ToString()); formParams.AddIfValueNotNull("f_max_hit", filter.MaxHit?.ToString()); formParams.AddIfValueNotNull("f_min_ratio", filter.MinRatio?.ToString(CultureInfo.InvariantCulture)); formParams.AddIfValueNotNull("f_max_ratio", filter.MaxRatio?.ToString(CultureInfo.InvariantCulture)); formParams.AddIfValueNotNull("f_max_level", filter.MaxLevel?.ToString()); formParams.AddIfValueNotNull("f_min_date_available", filter.MinDateAvailable?.ToString(DateFormat)); formParams.AddIfValueNotNull("f_max_date_available", filter.MaxDataAvailable?.ToString(DateFormat)); formParams.AddIfValueNotNull("f_min_date_created", filter.MinDateCreated?.ToString(DateFormat)); formParams.AddIfValueNotNull("f_max_date_created", filter.MaxDateCreated?.ToString(DateFormat)); var response = await _context.PostAsync>(_logger, "pwg.categories.getImages", formParams, cancellationToken); return response.Result; } private async Task AddOrUpdateAsync(int? imageId, ImageUpload imageUpload, CancellationToken cancellationToken) { var formParams = new Dictionary { { "original_sum", imageUpload.OriginalSum }, { "check_uniqueness", "true" } }; formParams.AddIfValueNotNull("original_filename", imageUpload.FileName); AddImageInfoToForm(formParams, imageUpload); formParams.AddIfValueNotNull("image_id", imageId?.ToString()); var response = await _context.PostAsync>(_logger, "pwg.images.add", formParams, cancellationToken); return response.Result; } private static void AddImageInfoToForm(IDictionary formParams, ImageInfo imageInfo) { formParams.AddIfValueNotNull("name", imageInfo.Name); formParams.AddIfValueNotNull("author", imageInfo.Author); formParams.AddIfValueNotNull("date_creation", imageInfo.CreatedAt?.ToString(DateTimeFormat)); formParams.AddIfValueNotNull("comment", imageInfo.Comment); formParams.AddIfValueNotNull("level", imageInfo.Level?.ToString()); var albums = imageInfo.Albums != null ? string.Join(";", imageInfo.Albums.Select(a => a.Rank.HasValue ? $"{a.AlbumId},{a.Rank}" : $"{a.AlbumId}")) : null; formParams.AddIfValueNotNull("categories", albums); var tags = imageInfo.TagIds != null ? string.Join(",", imageInfo.TagIds.Select(t => t.ToString())) : null; formParams.AddIfValueNotNull("tag_ids", tags); } }