namespace Splitter_UI.Services; public sealed class AutoDecisionService(IThumbnailService _thumbnails, IFileProbeService _fileProbe, ILogger _log) : IAutoDecisionService { public void ApplyAutoDecisions(JobViewModel job, CancellationToken token) { Task.Run(() => Detect(job, token)); } private async Task Detect(JobViewModel job, CancellationToken token) { try { job.GravitateTo = new(0.5f, 0.5f); job.OverrideTargetDuration = 58.0; job.Mask = "[NAME]_seg[NN].[EXT]"; job.OutputFolder = Path.Combine(Path.GetDirectoryName(job.InputFile)!, "splitter"); job.Probe = await _fileProbe.ProbeAsync(job.InputFile, token); job.Thumbnail = await _thumbnails.CreateThumbnailAsync(job.InputFile, job.Probe, rotateDegree: job.Rotate); if (job.Probe.Width > job.Probe.Height) { job.Detect = "body"; job.Rotate = 0; CalculateCrop(job); } //else //{ // var sampler = new VideoRotationSampler(null); // job.Rotate = await sampler.DetectRotationAsync(job.InputFile, job.Probe.Duration, token); // job.Detect = job.Rotate == 0 ? null : "body"; //} _log.LogInfo(job.ToString()); } catch (Exception ex) { _log.LogError($"Error creating thumbnail for {Path.GetFileName(job.InputFile)}: {ex.Message}"); } } private static void CalculateCrop(JobViewModel job) { var targetAR = (float)CommandLine.DefaultW / CommandLine.DefaultH; var pixelAspect = job.Probe!.Sar.X / job.Probe.Sar.Y; var srcW = job.Probe.Width * pixelAspect; float srcH = job.Probe.Height; var srcAR = srcW / srcH; var cropH = srcH; var cropW = cropH * targetAR; if (cropW > srcW) { cropW = srcW; cropH = cropW / targetAR; } var x = (srcW - cropW) * 0.5f; var y = (srcH - cropH) * 0.5f; var invPixelAspect = 1f / pixelAspect; var cropW_px = cropW * invPixelAspect; var cropH_px = cropH; var x_px = x * invPixelAspect; var y_px = y; job.CropText = $"{(int)MathF.Round(cropW_px)},{(int)MathF.Round(cropH_px)}"; } }