diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs index 6311298..46d3652 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs @@ -62,17 +62,6 @@ public class PluginConfiguration : BasePluginConfiguration /// public int MinimumIntroDuration { get; set; } = 15; - /// - /// Gets or sets the maximum amount of noise (in dB) that is considered silent. - /// Lowering this number will increase the filter's sensitivity to noise. - /// - public int SilenceDetectionMaximumNoise { get; set; } = -50; - - /// - /// Gets or sets the minimum duration of audio (in seconds) that is considered silent. - /// - public double SilenceDetectionMinimumDuration { get; set; } = 0.50; - // ===== Playback settings ===== /// @@ -93,5 +82,34 @@ public class PluginConfiguration : BasePluginConfiguration /// /// Gets or sets the amount of intro to play (in seconds). /// - public int SecondsOfIntroToPlay { get; set; } = 2; + public int SecondsOfIntroToPlay { get; set; } = 3; + + // ===== Internal algorithm settings ===== + + /// + /// Gets or sets the maximum number of bits (out of 32 total) that can be different between two Chromaprint points before they are considered dissimilar. + /// Defaults to 6 (81% similar). + /// + public int MaximumFingerprintPointDifferences { get; set; } = 6; + + /// + /// Gets or sets the maximum number of seconds that can pass between two similar fingerprint points before a new time range is started. + /// + public double MaximumTimeSkip { get; set; } = 3.5; + + /// + /// Gets or sets the amount to shift inverted indexes by. + /// + public int InvertedIndexShift { get; set; } = 2; + + /// + /// Gets or sets the maximum amount of noise (in dB) that is considered silent. + /// Lowering this number will increase the filter's sensitivity to noise. + /// + public int SilenceDetectionMaximumNoise { get; set; } = -50; + + /// + /// Gets or sets the minimum duration of audio (in seconds) that is considered silent. + /// + public double SilenceDetectionMinimumDuration { get; set; } = 0.33; } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html index 377eb03..99981cf 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html @@ -154,6 +154,32 @@ Increasing either of these settings will cause episode analysis to take much longer.

+ +
+ Silence detection options + +
+ + +
+ Noise tolerance in negative decibels. +
+
+ +
+ + +
+ Minimum silence duration in seconds before adjusting introduction end time. +
+
+
@@ -190,6 +216,16 @@ Seconds after the introduction starts to hide the skip prompt at. + +
+ + +
+ Seconds of introduction that should be played. Defaults to 2. +
+
@@ -201,12 +237,6 @@ - -

- Erasing introduction timestamps is only necessary after upgrading the plugin if specifically - requested to do so in the plugin's changelog. After the timestamps are erased, run the - Analyze episodes scheduled task to re-analyze all media on the server. -

@@ -337,14 +367,20 @@ // all plugin configuration fields that can be get or set with .value (i.e. strings or numbers). var configurationFields = [ + // analysis "MaxParallelism", "SelectedLibraries", "AnalysisPercent", "AnalysisLengthLimit", "MinimumIntroDuration", "EdlAction", + // playback "ShowPromptAdjustment", - "HidePromptAdjustment" + "HidePromptAdjustment", + "SecondsOfIntroToPlay", + // internals + "SilenceDetectionMaximumNoise", + "SilenceDetectionMinimumDuration", ] // visualizer elements diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs index 5edc7a9..fcd3e89 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs @@ -15,22 +15,6 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper; ///
public class AnalyzeEpisodesTask : IScheduledTask { - /// - /// Maximum number of bits (out of 32 total) that can be different between segments before they are considered dissimilar. - /// 6 bits means the audio must be at least 81% similar (1 - 6 / 32). - /// - private const double MaximumDifferences = 6; - - /// - /// Maximum time (in seconds) permitted between timestamps before they are considered non-contiguous. - /// - private const double MaximumDistance = 3.5; - - /// - /// Amount to shift inverted index offsets by. - /// - private const int InvertedIndexShift = 2; - /// /// Seconds of audio in one fingerprint point. This value is defined by the Chromaprint library and should not be changed. /// @@ -57,6 +41,14 @@ public class AnalyzeEpisodesTask : IScheduledTask /// private static int minimumIntroDuration = 15; + private static int maximumDifferences = 6; + + private static int invertedIndexShift = 2; + + private static double maximumTimeSkip = 3.5; + + private static double silenceDetectionMinimumDuration = 0.33; + /// /// Initializes a new instance of the class. /// @@ -124,6 +116,13 @@ public class AnalyzeEpisodesTask : IScheduledTask "No episodes to analyze. If you are limiting the list of libraries to analyze, check that all library names have been spelled correctly."); } + // Load analysis settings from configuration + var config = Plugin.Instance?.Configuration ?? new Configuration.PluginConfiguration(); + maximumDifferences = config.MaximumFingerprintPointDifferences; + invertedIndexShift = config.InvertedIndexShift; + maximumTimeSkip = config.MaximumTimeSkip; + silenceDetectionMinimumDuration = config.SilenceDetectionMinimumDuration; + // Log EDL settings EdlManager.LogConfiguration(); @@ -448,7 +447,7 @@ public class AnalyzeEpisodesTask : IScheduledTask { var originalPoint = kvp.Key; - for (var i = -1 * InvertedIndexShift; i <= InvertedIndexShift; i++) + for (var i = -1 * invertedIndexShift; i <= invertedIndexShift; i++) { var modifiedPoint = (uint)(originalPoint + i); @@ -542,7 +541,7 @@ public class AnalyzeEpisodesTask : IScheduledTask var diff = lhs[lhsPosition] ^ rhs[rhsPosition]; // If the difference between the samples is small, flag both times as similar. - if (CountBits(diff) > MaximumDifferences) + if (CountBits(diff) > maximumDifferences) { continue; } @@ -559,25 +558,25 @@ public class AnalyzeEpisodesTask : IScheduledTask rhsTimes.Add(double.MaxValue); // Now that both fingerprints have been compared at this shift, see if there's a contiguous time range. - var lContiguous = TimeRangeHelpers.FindContiguous(lhsTimes.ToArray(), MaximumDistance); + var lContiguous = TimeRangeHelpers.FindContiguous(lhsTimes.ToArray(), maximumTimeSkip); if (lContiguous is null || lContiguous.Duration < minimumIntroDuration) { return (new TimeRange(), new TimeRange()); } // Since LHS had a contiguous time range, RHS must have one also. - var rContiguous = TimeRangeHelpers.FindContiguous(rhsTimes.ToArray(), MaximumDistance)!; + var rContiguous = TimeRangeHelpers.FindContiguous(rhsTimes.ToArray(), maximumTimeSkip)!; // Tweak the end timestamps just a bit to ensure as little content as possible is skipped over. if (lContiguous.Duration >= 90) { - lContiguous.End -= 2 * MaximumDistance; - rContiguous.End -= 2 * MaximumDistance; + lContiguous.End -= 2 * maximumTimeSkip; + rContiguous.End -= 2 * maximumTimeSkip; } else if (lContiguous.Duration >= 30) { - lContiguous.End -= MaximumDistance; - rContiguous.End -= MaximumDistance; + lContiguous.End -= maximumTimeSkip; + rContiguous.End -= maximumTimeSkip; } return (lContiguous, rContiguous); @@ -612,9 +611,8 @@ public class AnalyzeEpisodesTask : IScheduledTask continue; } - // Since we only want to adjust the end timestamp of the intro, create a new TimeRange - // that covers the last few seconds. - var originalIntroEnd = new TimeRange(originalIntro.IntroEnd - 10, originalIntro.IntroEnd); + // Only adjust the end timestamp of the intro + var originalIntroEnd = new TimeRange(originalIntro.IntroEnd - 15, originalIntro.IntroEnd); _logger.LogTrace( "{Name} original intro: {Start} - {End}", @@ -636,8 +634,10 @@ public class AnalyzeEpisodesTask : IScheduledTask // Ignore any silence that: // * doesn't intersect the ending of the intro, or - // * is less than half a second long - if (!originalIntroEnd.Intersects(currentRange) || currentRange.Duration < 0.5) + // * is shorter than the user defined minimum duration + if ( + !originalIntroEnd.Intersects(currentRange) || + currentRange.Duration < silenceDetectionMinimumDuration) { continue; }