diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs
index db86ce3..741c561 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs
@@ -78,4 +78,10 @@ public class PluginConfiguration : BasePluginConfiguration
/// Gets or sets the seconds after the intro starts to hide the skip prompt at.
///
public int HidePromptAdjustment { get; set; } = 10;
+
+ ///
+ /// Gets or sets the amount of intro to play (in seconds).
+ /// TODO: rename.
+ ///
+ public int AmountOfIntroToPlay { get; set; } = 5;
}
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs
index d4d07b7..4fcb8c6 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs
@@ -44,6 +44,7 @@ public class SkipIntroController : ControllerBase
var config = Plugin.Instance!.Configuration;
intro.ShowSkipPromptAt = Math.Max(0, intro.IntroStart - config.ShowPromptAdjustment);
intro.HideSkipPromptAt = intro.IntroStart + config.HidePromptAdjustment;
+ intro.IntroEnd -= config.AmountOfIntroToPlay;
return intro;
}
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs
index e97dee2..f8d71be 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs
@@ -26,6 +26,11 @@ public class AnalyzeEpisodesTask : IScheduledTask
///
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.
///
@@ -275,18 +280,6 @@ public class AnalyzeEpisodesTask : IScheduledTask
}
}
- /* Theory of operation:
- * Episodes are analyzed in the same order that Jellyfin displays them in and are
- * sorted into buckets based off of the intro sequence that the episode contains.
- *
- * Jellyfin's episode ordering is used because it is assumed that the introduction
- * in each season of a show will likely either:
- * - remain constant throughout the entire season
- * - remain constant in subranges of the season (e.g. episodes 1 - 5 and 6 - 10 share intros)
- * If the intros do not follow this pattern, the plugin should still find most
- * of them.
- */
-
// While there are still episodes in the queue
while (episodes.Count > 0)
{
@@ -304,14 +297,30 @@ public class AnalyzeEpisodesTask : IScheduledTask
remainingEpisode.EpisodeId,
fingerprintCache[remainingEpisode.EpisodeId]);
- // If we found an intro, save it.
- if (currentIntro.Valid)
+ // If one of the intros isn't valid, ignore this comparison result.
+ if (!currentIntro.Valid)
+ {
+ continue;
+ }
+
+ // Only save the discovered intro if it is:
+ // - the first intro discovered for this episode
+ // - longer than the previously discovered intro
+ if (
+ !seasonIntros.TryGetValue(currentIntro.EpisodeId, out var savedCurrentIntro) ||
+ currentIntro.Duration > savedCurrentIntro.Duration)
{
seasonIntros[currentIntro.EpisodeId] = currentIntro;
- seasonIntros[remainingIntro.EpisodeId] = remainingIntro;
-
- break;
}
+
+ if (
+ !seasonIntros.TryGetValue(remainingIntro.EpisodeId, out var savedRemainingIntro) ||
+ remainingIntro.Duration > savedRemainingIntro.Duration)
+ {
+ seasonIntros[remainingIntro.EpisodeId] = remainingIntro;
+ }
+
+ break;
}
// If no intro is found at this point, the popped episode is not reinserted into the queue.
@@ -435,13 +444,18 @@ public class AnalyzeEpisodesTask : IScheduledTask
// If an exact match is found, calculate the shift that must be used to align the points.
foreach (var kvp in lhsIndex)
{
- var point = kvp.Key;
+ var originalPoint = kvp.Key;
- if (rhsIndex.ContainsKey(point))
+ for (var i = -1 * InvertedIndexShift; i <= InvertedIndexShift; i++)
{
- var lhsFirst = (int)lhsIndex[point];
- var rhsFirst = (int)rhsIndex[point];
- indexShifts.Add(rhsFirst - lhsFirst);
+ var modifiedPoint = (uint)(originalPoint + i);
+
+ if (rhsIndex.ContainsKey(modifiedPoint))
+ {
+ var lhsFirst = (int)lhsIndex[originalPoint];
+ var rhsFirst = (int)rhsIndex[modifiedPoint];
+ indexShifts.Add(rhsFirst - lhsFirst);
+ }
}
}