using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace JellyfinPlugin { public static class CropHelper { public static async Task DetectCropAsync(string filePath, double limit) { string limitStr = limit.ToString(System.Globalization.CultureInfo.InvariantCulture); var startInfo = new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-skip_frame nokey -i \"{filePath}\" -vf \"cropdetect=limit={limitStr}:round=16:reset=0\" -f null -", RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using var process = new Process { StartInfo = startInfo }; process.Start(); string output = await process.StandardError.ReadToEndAsync(); await process.WaitForExitAsync(); var regex = new Regex(@"crop=([0-9]+):([0-9]+):([0-9]+):([0-9]+)"); var matches = regex.Matches(output); var crops = new ConcurrentDictionary(); int totalFrames = 0; foreach (Match match in matches) { string cropStr = match.Value.Replace("crop=", ""); crops.AddOrUpdate(cropStr, 1, (_, count) => count + 1); totalFrames++; } if (totalFrames == 0) return string.Empty; var bestCrop = crops.OrderByDescending(kvp => kvp.Value).FirstOrDefault().Key; return bestCrop ?? string.Empty; } } }