forked from Kieran/void.cat
Convert all images to webp
This commit is contained in:
parent
dc0199a3d6
commit
e193127358
65
VoidCat/Services/Files/CompressContent.cs
Normal file
65
VoidCat/Services/Files/CompressContent.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using FFMpegCore;
|
||||||
|
|
||||||
|
namespace VoidCat.Services.Files;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Service which utilizes ffmpeg to strip metadata from media
|
||||||
|
/// and compress media to reduce storage costs
|
||||||
|
/// </summary>
|
||||||
|
public class CompressContent
|
||||||
|
{
|
||||||
|
private readonly ILogger<CompressContent> _logger;
|
||||||
|
|
||||||
|
public CompressContent(ILogger<CompressContent> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CompressResult> TryCompressMedia(string input, string output, CancellationToken cts)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string? outMime = null;
|
||||||
|
switch (Path.GetExtension(input))
|
||||||
|
{
|
||||||
|
case ".jpg":
|
||||||
|
case ".jpeg":
|
||||||
|
case ".gif":
|
||||||
|
case ".png":
|
||||||
|
case ".bmp":
|
||||||
|
case ".tiff":
|
||||||
|
{
|
||||||
|
output = Path.ChangeExtension(output, ".webp");
|
||||||
|
outMime = "image/webp";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ffmpeg = FFMpegArguments
|
||||||
|
.FromFileInput(input)
|
||||||
|
.OutputToFile(output, true, o =>
|
||||||
|
{
|
||||||
|
o.WithoutMetadata();
|
||||||
|
})
|
||||||
|
.CancellableThrough(cts);
|
||||||
|
|
||||||
|
_logger.LogInformation("Running: {command}", ffmpeg.Arguments);
|
||||||
|
var result = await ffmpeg.ProcessAsynchronously();
|
||||||
|
return new(result, output)
|
||||||
|
{
|
||||||
|
MimeType = outMime
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Could not strip metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(false, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CompressResult(bool Success, string OutPath)
|
||||||
|
{
|
||||||
|
public string? MimeType { get; init; }
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ public static class FileStorageStartup
|
|||||||
{
|
{
|
||||||
services.AddTransient<FileInfoManager>();
|
services.AddTransient<FileInfoManager>();
|
||||||
services.AddTransient<FileStoreFactory>();
|
services.AddTransient<FileStoreFactory>();
|
||||||
services.AddTransient<StripMetadata>();
|
services.AddTransient<CompressContent>();
|
||||||
|
|
||||||
if (settings.CloudStorage != default)
|
if (settings.CloudStorage != default)
|
||||||
{
|
{
|
||||||
|
@ -10,9 +10,9 @@ public class LocalDiskFileStore : StreamFileStore, IFileStore
|
|||||||
{
|
{
|
||||||
private const string FilesDir = "files-v1";
|
private const string FilesDir = "files-v1";
|
||||||
private readonly VoidSettings _settings;
|
private readonly VoidSettings _settings;
|
||||||
private readonly StripMetadata _stripMetadata;
|
private readonly CompressContent _stripMetadata;
|
||||||
|
|
||||||
public LocalDiskFileStore(VoidSettings settings, IAggregateStatsCollector stats, StripMetadata stripMetadata)
|
public LocalDiskFileStore(VoidSettings settings, IAggregateStatsCollector stats, CompressContent stripMetadata)
|
||||||
: base(stats)
|
: base(stats)
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
@ -58,9 +58,10 @@ public class LocalDiskFileStore : StreamFileStore, IFileStore
|
|||||||
File.Move(finalPath, srcPath);
|
File.Move(finalPath, srcPath);
|
||||||
|
|
||||||
var dstPath = $"{finalPath}_dst{ext}";
|
var dstPath = $"{finalPath}_dst{ext}";
|
||||||
if (await _stripMetadata.TryStripMediaMetadata(srcPath, dstPath, cts))
|
var res = await _stripMetadata.TryCompressMedia(srcPath, dstPath, cts);
|
||||||
|
if (res.Success)
|
||||||
{
|
{
|
||||||
File.Move(dstPath, finalPath);
|
File.Move(res.OutPath, finalPath);
|
||||||
File.Delete(srcPath);
|
File.Delete(srcPath);
|
||||||
|
|
||||||
// recompute metadata
|
// recompute metadata
|
||||||
@ -71,7 +72,8 @@ public class LocalDiskFileStore : StreamFileStore, IFileStore
|
|||||||
Metadata = vf.Metadata! with
|
Metadata = vf.Metadata! with
|
||||||
{
|
{
|
||||||
Size = (ulong)fInfo.Length,
|
Size = (ulong)fInfo.Length,
|
||||||
Digest = hash.ToHex()
|
Digest = hash.ToHex(),
|
||||||
|
MimeType = res.MimeType ?? vf.Metadata.MimeType
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
using FFMpegCore;
|
|
||||||
using FFMpegCore.Enums;
|
|
||||||
using FFMpegCore.Pipes;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace VoidCat.Services.Files;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Service which utilizes ffmpeg to strip metadata from media
|
|
||||||
/// </summary>
|
|
||||||
public class StripMetadata
|
|
||||||
{
|
|
||||||
private readonly ILogger<StripMetadata> _logger;
|
|
||||||
|
|
||||||
public StripMetadata(ILogger<StripMetadata> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> TryStripMediaMetadata(string input, string output, CancellationToken cts)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ffprobe = await FFProbe.AnalyseAsync(input, cancellationToken: cts);
|
|
||||||
if (ffprobe == default)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Could not determine media type with ffprobe");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("Stripping content from {type}", ffprobe.Format.FormatName);
|
|
||||||
|
|
||||||
var ffmpeg = FFMpegArguments
|
|
||||||
.FromFileInput(input)
|
|
||||||
.OutputToFile(output, true, o =>
|
|
||||||
{
|
|
||||||
o.WithoutMetadata();
|
|
||||||
})
|
|
||||||
.CancellableThrough(cts);
|
|
||||||
|
|
||||||
_logger.LogInformation("Running: {command}", ffmpeg.Arguments);
|
|
||||||
return await ffmpeg.ProcessAsynchronously();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Could not strip metadata");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user