namespace ConfusedPolarBear.Plugin.IntroSkipper; using System; using System.Threading; using System.Text.Json; using System.Text.Json.Serialization; /// <summary> /// Detailed statistics about the last analysis operation performed. All times are represented as milliseconds. /// </summary> public class AnalysisStatistics { /// <summary> /// Gets the number of episodes that have been analyzed so far. /// </summary> public ThreadSafeInteger TotalAnalyzedEpisodes { get; } = new ThreadSafeInteger(); /// <summary> /// Gets or sets the number of episodes that need to be analyzed. /// </summary> public int TotalQueuedEpisodes { get; set; } /// <summary> /// Gets the number of times an index search successfully located a pair of introductions. /// </summary> public ThreadSafeInteger IndexSearches { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the number of times a quick scan successfully located a pair of introductions. /// </summary> public ThreadSafeInteger QuickScans { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the number of times a full scan successfully located a pair of introductions. /// </summary> public ThreadSafeInteger FullScans { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the total CPU time spent waiting for audio fingerprints to be generated. /// </summary> public ThreadSafeInteger FingerprintCPUTime { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the total CPU time spent analyzing fingerprints in the initial pass. /// </summary> public ThreadSafeInteger FirstPassCPUTime { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the total CPU time spent analyzing fingerprints in the second pass. /// </summary> public ThreadSafeInteger SecondPassCPUTime { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the total task runtime across all threads. /// </summary> public ThreadSafeInteger TotalCPUTime { get; } = new ThreadSafeInteger(); /// <summary> /// Gets the total task runtime as measured by a clock. /// </summary> public ThreadSafeInteger TotalTaskTime { get; } = new ThreadSafeInteger(); } /// <summary> /// Convenience wrapper around a thread safe integer. /// </summary> [JsonConverter(typeof(ThreadSafeIntegerJsonConverter))] public class ThreadSafeInteger { private int value = 0; /// <summary> /// Gets the current value stored by this integer. /// </summary> public int Value { get { return value; } } /// <summary> /// Increment the value of this integer by 1. /// </summary> public void Increment() { Add(1); } /// <summary> /// Adds the total milliseconds elapsed since a start time. /// </summary> /// <param name="start">Start time.</param> public void AddDuration(DateTime start) { if (start == DateTime.MinValue) { return; } var elapsed = DateTime.Now.Subtract(start); Add((int)elapsed.TotalMilliseconds); } /// <summary> /// Adds the provided amount to this integer. /// </summary> /// <param name="amount">Amount to add.</param> public void Add(int amount) { Interlocked.Add(ref value, amount); } } /// <summary> /// Serialize thread safe integers to a regular integer (instead of an object with a Value property). /// </summary> public class ThreadSafeIntegerJsonConverter : JsonConverter<ThreadSafeInteger> { /// <summary> /// Deserialization of TSIs is not supported and will always throw a NotSupportedException. /// </summary> /// <param name="reader">Reader.</param> /// <param name="typeToConvert">Type.</param> /// <param name="options">Options.</param> /// <returns>Never returns.</returns> public override ThreadSafeInteger? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotSupportedException(); } /// <summary> /// Serialize the provided TSI. /// </summary> /// <param name="writer">Writer.</param> /// <param name="value">TSI.</param> /// <param name="options">Options.</param> public override void Write(Utf8JsonWriter writer, ThreadSafeInteger value, JsonSerializerOptions options) { writer.WriteNumberValue(value.Value); } }