Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Martin Rud 261 posts 1022 karma points c-trib
    Sep 12, 2024 @ 07:37
    Martin Rud
    0

    How to overwrite a media file with a locale, physical file so it works both with blob and non-blob storage

    I can't get Cogworks.Tinifier package working on Umbraco v13 (and have got no solutions here: https://www.facebook.com/groups/umbracowebdevs/posts/2091914831210397/). Therefore I have tried to make my own solution (see code below).

    It works a part of the way: When user uploads an image TinifyAPI optimizes it and saves the optimized image in a temporary location (like C:\Users\marti\AppData\Local\Temp\tmpsxjjxj.tmp).

    But the part of the code that should overwrite the uploaded, non-optimized image (which is my goal - I don't want the original non-optimized image since it consumes server disc space) does not work. I.e. this part:

    using (var fileStream = System.IO.File.OpenRead(tempFilePath))
    {
        byte[] fileBytesArray;
        using (var memoryStream = new MemoryStream())
        {
            await fileStream.CopyToAsync(memoryStream);
            fileBytesArray = memoryStream.ToArray();
        }
        var fileBytes = new ByteArrayContent(fileBytesArray);
        var uploadResponse = await httpClient.PutAsync(mediaUrl, fileBytes);
        if (!uploadResponse.IsSuccessStatusCode)
        {
            NotifyUser("Upload Error", $"Failed to upload optimized image.");
        }
    }
    

    No error, but also no file is overwritten.

    My full code:

    using Umbraco.Cms.Core.Events;
    using Umbraco.Cms.Core.Notifications;
    using Umbraco.Cms.Core.Services;
    using TinifyAPI;
    using Newtonsoft.Json.Linq;
    
    namespace MartinRud.Notifications
    {
        public class MediaNotificationHandler : INotificationHandler<MediaSavedNotification>
        {
            private readonly IMediaService _mediaService;
            private readonly IConfiguration _configuration; 
            private readonly ILogger<MediaNotificationHandler> _logger;
            private readonly IEventMessagesFactory _eventMessagesFactory;
            private readonly IHttpClientFactory _httpClientFactory;
            private readonly string _baseUrl;
    
            public MediaNotificationHandler(IMediaService mediaService, IConfiguration configuration, ILogger<MediaNotificationHandler> logger, IEventMessagesFactory eventMessagesFactory, IHttpClientFactory httpClientFactory)
            {
                _mediaService = mediaService;
                _configuration = configuration;
                _logger = logger;
                _eventMessagesFactory = eventMessagesFactory;
                _httpClientFactory = httpClientFactory;
                _baseUrl = configuration["MediaBaseUrl"] ?? "https://localhost:44378";
                Tinify.Key = _configuration["TinifierSettings:ApiKey"];
            }
    
    public async void Handle(MediaSavedNotification notification)
    {
        var httpClient = _httpClientFactory.CreateClient();
    
        foreach (var mediaItem in notification.SavedEntities)
        {
            if (mediaItem.ContentType.Alias.Equals("Image"))
            {
                var mediaJson = mediaItem.GetValue<string>("umbracoFile");
                var mediaUrl = ExtractUrlFromJson(mediaJson);
    
                if (!string.IsNullOrEmpty(mediaUrl))
                {
                    if (!Uri.IsWellFormedUriString(mediaUrl, UriKind.Absolute))
                    {
                        mediaUrl = new Uri(new Uri(_baseUrl), mediaUrl).ToString();
                    }
    
                    _logger.LogInformation($"Attempting to fetch URL: {mediaUrl}");
    
                    var tempFilePath = Path.GetTempFileName();
                    var jsonFilePath = Path.ChangeExtension(tempFilePath, "json");
    
                    try
                    {
                        var response = await GetWithRetryAsync(httpClient, mediaUrl);
    
                        if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
                        {
                            NotifyUser("URL Not Found", $"The URL '{mediaUrl}' was not found.");
                            continue;
                        }
    
                        using (var fileStream = System.IO.File.Create(tempFilePath))
                        {
                            await response.Content.CopyToAsync(fileStream);
                        }
    
                        if (System.IO.File.Exists(jsonFilePath))
                        {
                            NotifyUser("Image already compressed", "The image has already been optimized.");
                            continue;
                        }
    
                        NotifyUser("Starting image optimization", $"Starting optimization for image '{mediaItem.Name}'");
                        _logger.LogInformation("Calling CompressImage for: {TempFilePath}", tempFilePath);
    
                        await CompressImage(tempFilePath, jsonFilePath);
    
                        _logger.LogInformation("Finished calling CompressImage for: {TempFilePath}", tempFilePath);
    
                        // Upload the optimized image
                        using (var fileStream = System.IO.File.OpenRead(tempFilePath))
                        {
                            byte[] fileBytesArray;
                            using (var memoryStream = new MemoryStream())
                            {
                                await fileStream.CopyToAsync(memoryStream);
                                fileBytesArray = memoryStream.ToArray();
                            }
                            var fileBytes = new ByteArrayContent(fileBytesArray);
                            var uploadResponse = await httpClient.PutAsync(mediaUrl, fileBytes);
                            if (!uploadResponse.IsSuccessStatusCode)
                            {
                                NotifyUser("Upload Error", $"Failed to upload optimized image.");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error processing media item for: {MediaItemName}", mediaItem.Name);
                        NotifyUser("Error", $"Error processing media item: {ex.Message}");
                    }
                    finally
                    {
                        // Clean up temporary files
                        try
                        {
                            if (System.IO.File.Exists(tempFilePath))
                            {
                                //System.IO.File.Delete(tempFilePath);
                                _logger.LogInformation("Deleted temporary file: {TempFilePath}", tempFilePath);
                            }
                            if (System.IO.File.Exists(jsonFilePath))
                            {
                                //System.IO.File.Delete(jsonFilePath);
                                _logger.LogInformation("Deleted JSON file: {JsonFilePath}", jsonFilePath);
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Error deleting temporary files.");
                        }
                    }
                }
            }
        }
    }
    
    
    private string ExtractUrlFromJson(string json)
    {
        try
        {
            var jsonObject = JObject.Parse(json);
            var url = jsonObject["src"]?.ToString();
            return url ?? string.Empty;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error parsing JSON for media URL");
            return string.Empty;
        }
    }
    
    private async Task<HttpResponseMessage> GetWithRetryAsync(HttpClient httpClient, string url, int maxRetries = 3)
    {
        for (int retry = 0; retry < maxRetries; retry++)
        {
            try
            {
                var response = await httpClient.GetAsync(url);
                response.EnsureSuccessStatusCode(); // Throws if not success code.
                return response;
            }
            catch (HttpRequestException ex)
            {
                if (retry == maxRetries - 1) // Last retry
                {
                    _logger.LogError(ex, "Error fetching URL: {Url}", url);
                    throw;
                }
                await Task.Delay(1000); // Wait before retrying
            }
        }
        throw new Exception("Failed to fetch URL after multiple retries.");
    }
            private async Task CompressImage(string filePath, string jsonFilePath)
            {
                try
                {
                    var originalSize = new FileInfo(filePath).Length;
                    var source = Tinify.FromFile(filePath);
                    await source.ToFile(filePath);
    
                    var compressedSize = new FileInfo(filePath).Length;
                    var percentageReduction = (double)(originalSize - compressedSize) / originalSize * 100;
    
                    var compressionInfo = new
                    {
                        OriginalSize = originalSize,
                        CompressedSize = compressedSize,
                        PercentageReduction = Math.Round(percentageReduction, 2)
                    };
    
                    var json = JObject.FromObject(compressionInfo);
                    await System.IO.File.WriteAllTextAsync(jsonFilePath, json.ToString());
    
                    NotifyUser("Image optimization complete", $"Optimization for image completed successfully.");
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error compressing image");
                    NotifyUser("Image optimization error", $"Error optimizing image: {ex.Message}");
                }
            }
    
            private void NotifyUser(string title, string message)
            {
                var eventMessages = _eventMessagesFactory.Get();
                eventMessages.Add(new EventMessage(title, message, EventMessageType.Success)); // or .Error if needed
            }
        }
    }
    
  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies