using System.Globalization; using System.IO; namespace AmiReel.Services; internal sealed class MediaProbe { private readonly ProcessRunner _runner; private readonly Action? _log; public MediaProbe(ProcessRunner runner, Action? log) { _runner = runner; _log = log; } public async Task ProbeDurationAsync(ToolPaths tools, string input, CancellationToken token) { using FfmpegLibraryProbe? libraryProbe = CreateLibraryProbe(tools); if (libraryProbe is not null) return libraryProbe.ProbeDuration(input); string output = await _runner.RunAsync(tools.Ffprobe, ["-v", "error", "-show_entries", "format=duration", "-of", "default=nk=1:nw=1", input], null, null, token); return double.Parse(output.Trim(), CultureInfo.InvariantCulture); } public async Task HasAudioAsync(ToolPaths tools, string input, CancellationToken token) { using FfmpegLibraryProbe? libraryProbe = CreateLibraryProbe(tools); if (libraryProbe is not null) return libraryProbe.HasAudio(input); string output = await _runner.RunAsync(tools.Ffprobe, ["-v", "error", "-select_streams", "a", "-show_entries", "stream=index", "-of", "csv=p=0", input], null, null, token); return !string.IsNullOrWhiteSpace(output); } private FfmpegLibraryProbe? CreateLibraryProbe(ToolPaths tools) { if (!FfmpegLibraryProbe.TryCreate(tools.Ffmpeg, out FfmpegLibraryProbe? probe)) return null; _log?.Invoke($"Using FFmpeg shared libraries for media probing from '{Path.GetDirectoryName(tools.Ffmpeg)}'."); return probe; } }