Expose algorithm internal settings
This commit is contained in:
parent
6dc3a5fa41
commit
cf99dde0e2
@ -62,17 +62,6 @@ public class PluginConfiguration : BasePluginConfiguration
|
||||
/// </summary>
|
||||
public int MinimumIntroDuration { get; set; } = 15;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public int SilenceDetectionMaximumNoise { get; set; } = -50;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum duration of audio (in seconds) that is considered silent.
|
||||
/// </summary>
|
||||
public double SilenceDetectionMinimumDuration { get; set; } = 0.50;
|
||||
|
||||
// ===== Playback settings =====
|
||||
|
||||
/// <summary>
|
||||
@ -93,5 +82,34 @@ public class PluginConfiguration : BasePluginConfiguration
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of intro to play (in seconds).
|
||||
/// </summary>
|
||||
public int SecondsOfIntroToPlay { get; set; } = 2;
|
||||
public int SecondsOfIntroToPlay { get; set; } = 3;
|
||||
|
||||
// ===== Internal algorithm settings =====
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
public int MaximumFingerprintPointDifferences { get; set; } = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of seconds that can pass between two similar fingerprint points before a new time range is started.
|
||||
/// </summary>
|
||||
public double MaximumTimeSkip { get; set; } = 3.5;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount to shift inverted indexes by.
|
||||
/// </summary>
|
||||
public int InvertedIndexShift { get; set; } = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public int SilenceDetectionMaximumNoise { get; set; } = -50;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum duration of audio (in seconds) that is considered silent.
|
||||
/// </summary>
|
||||
public double SilenceDetectionMinimumDuration { get; set; } = 0.33;
|
||||
}
|
||||
|
@ -154,6 +154,32 @@
|
||||
Increasing either of these settings will cause episode analysis to take much longer.
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details id="silence">
|
||||
<summary>Silence detection options</summary>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SilenceDetectionMaximumNoise">
|
||||
Noise tolerance
|
||||
</label>
|
||||
<input id="SilenceDetectionMaximumNoise" type="number" is="emby-input" min="-90"
|
||||
max="0" />
|
||||
<div class="fieldDescription">
|
||||
Noise tolerance in negative decibels.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SilenceDetectionMinimumDuration">
|
||||
Minimum silence duration
|
||||
</label>
|
||||
<input id="SilenceDetectionMinimumDuration" type="number" is="emby-input" min="0"
|
||||
step="0.01" />
|
||||
<div class="fieldDescription">
|
||||
Minimum silence duration in seconds before adjusting introduction end time.
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="verticalSection-extrabottompadding">
|
||||
@ -190,6 +216,16 @@
|
||||
Seconds after the introduction starts to hide the skip prompt at.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SecondsOfIntroToPlay">
|
||||
Seconds of intro to play
|
||||
</label>
|
||||
<input id="SecondsOfIntroToPlay" type="number" is="emby-input" min="0" />
|
||||
<div class="fieldDescription">
|
||||
Seconds of introduction that should be played. Defaults to 2.
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div>
|
||||
@ -201,12 +237,6 @@
|
||||
<button id="btnEraseTimestamps" is="emby-button" class="raised block emby-button">
|
||||
<span>Erase introduction timestamps</span>
|
||||
</button>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -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
|
||||
|
@ -15,22 +15,6 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
/// </summary>
|
||||
public class AnalyzeEpisodesTask : IScheduledTask
|
||||
{
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
private const double MaximumDifferences = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time (in seconds) permitted between timestamps before they are considered non-contiguous.
|
||||
/// </summary>
|
||||
private const double MaximumDistance = 3.5;
|
||||
|
||||
/// <summary>
|
||||
/// Amount to shift inverted index offsets by.
|
||||
/// </summary>
|
||||
private const int InvertedIndexShift = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Seconds of audio in one fingerprint point. This value is defined by the Chromaprint library and should not be changed.
|
||||
/// </summary>
|
||||
@ -57,6 +41,14 @@ public class AnalyzeEpisodesTask : IScheduledTask
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnalyzeEpisodesTask"/> class.
|
||||
/// </summary>
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user