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); + } } }