using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using Microsoft.Extensions.Logging; namespace ConfusedPolarBear.Plugin.IntroSkipper; /// /// Wrapper for the fpcalc utility. /// public static class FPCalc { /// /// Logger. /// public static ILogger? Logger { get; set; } /// /// Check that the fpcalc utility is installed. /// public static bool CheckFPCalcInstalled() { try { var version = getOutput("-version", 2000); Logger?.LogDebug("fpcalc version: {Version}", version); return version.StartsWith("fpcalc version", StringComparison.OrdinalIgnoreCase); } catch { return false; } } /// /// Fingerprint a queued episode. /// /// Queued episode to fingerprint. public static ReadOnlyCollection Fingerprint(QueuedEpisode episode) { Logger?.LogDebug("Fingerprinting {Duration} seconds from {File}", episode.FingerprintDuration, episode.Path); // FIXME: revisit escaping var path = "\"" + episode.Path + "\""; var duration = episode.FingerprintDuration.ToString(CultureInfo.InvariantCulture); var args = " -raw -length " + duration + " " + path; /* Returns output similar to the following: * DURATION=123 * FINGERPRINT=123456789,987654321,123456789,987654321,123456789,987654321 */ var raw = getOutput(args); var lines = raw.Split("\n"); if (lines.Length < 2) { Logger?.LogTrace("fpcalc output is {Raw}", raw); throw new FingerprintException("fpcalc output was malformed"); } // Remove the "FINGERPRINT=" prefix and split into an array of numbers. var fingerprint = lines[1].Substring(12).Split(","); var results = new List(); foreach (var rawNumber in fingerprint) { results.Add(Convert.ToUInt32(rawNumber, CultureInfo.InvariantCulture)); } return results.AsReadOnly(); } private static string getOutput(string args, int timeout = 60 * 1000) { var info = new ProcessStartInfo("fpcalc", args); info.CreateNoWindow = true; info.RedirectStandardOutput = true; var fpcalc = new Process(); fpcalc.StartInfo = info; fpcalc.Start(); fpcalc.WaitForExit(timeout); return fpcalc.StandardOutput.ReadToEnd(); } }