From e4da9342c838eee35f4f3ada7acc3e610f188f27 Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 25 Aug 2022 23:01:46 -0500 Subject: [PATCH] Change fingerprint cache policy --- .../TestAudioFingerprinting.cs | 15 ++- .../ScheduledTasks/AnalyzeEpisodesTask.cs | 91 +++++-------------- 2 files changed, 36 insertions(+), 70 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestAudioFingerprinting.cs b/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestAudioFingerprinting.cs index dbd4fab..a67e858 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestAudioFingerprinting.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestAudioFingerprinting.cs @@ -89,8 +89,14 @@ public class TestAudioFingerprinting var lhsEpisode = queueEpisode("audio/big_buck_bunny_intro.mp3"); var rhsEpisode = queueEpisode("audio/big_buck_bunny_clip.mp3"); + var lhsFingerprint = Chromaprint.Fingerprint(lhsEpisode); + var rhsFingerprint = Chromaprint.Fingerprint(rhsEpisode); - var (lhs, rhs) = task.CompareEpisodes(lhsEpisode, rhsEpisode); + var (lhs, rhs) = task.CompareEpisodes( + lhsEpisode.EpisodeId, + lhsFingerprint, + rhsEpisode.EpisodeId, + rhsFingerprint); Assert.True(lhs.Valid); Assert.Equal(0, lhs.IntroStart); @@ -111,10 +117,11 @@ public class TestAudioFingerprinting } } -public class FactSkipFFmpegTests : FactAttribute { - #if SKIP_FFMPEG_TESTS +public class FactSkipFFmpegTests : FactAttribute +{ +#if SKIP_FFMPEG_TESTS public FactSkipFFmpegTests() { Skip = "SKIP_FFMPEG_TESTS defined, skipping unit tests that require FFmpeg to be installed"; } - #endif +#endif } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs index d66cae7..941f8b0 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/AnalyzeEpisodesTask.cs @@ -36,22 +36,11 @@ public class AnalyzeEpisodesTask : IScheduledTask private readonly ILibraryManager? _libraryManager; - /// - /// Lock which guards the fingerprint cache dictionary. - /// - private readonly object _fingerprintCacheLock = new object(); - /// /// Lock which guards the shared dictionary of intros. /// private readonly object _introsLock = new object(); - /// - /// Temporary fingerprint cache to speed up reanalysis. - /// Fingerprints are removed from this after a season is analyzed. - /// - private Dictionary _fingerprintCache; - /// /// Statistics for the currently running analysis task. /// @@ -81,8 +70,6 @@ public class AnalyzeEpisodesTask : IScheduledTask _logger = loggerFactory.CreateLogger(); _queueLogger = loggerFactory.CreateLogger(); - _fingerprintCache = new Dictionary(); - EdlManager.Initialize(_logger); } @@ -182,15 +169,6 @@ public class AnalyzeEpisodesTask : IScheduledTask ex); } - // Clear this season's episodes from the temporary fingerprint cache. - lock (_fingerprintCacheLock) - { - foreach (var ep in season.Value) - { - _fingerprintCache.Remove(ep.EpisodeId); - } - } - if (writeEdl && Plugin.Instance!.Configuration.EdlAction != EdlAction.None) { EdlManager.UpdateEDLFiles(season.Value.AsReadOnly()); @@ -255,6 +233,7 @@ public class AnalyzeEpisodesTask : IScheduledTask CancellationToken cancellationToken) { var seasonIntros = new Dictionary(); + var fingerprintCache = new Dictionary(); /* Don't analyze specials or seasons with an insufficient number of episodes. * A season with only 1 episode can't be analyzed as it would compare the episode to itself, @@ -273,7 +252,23 @@ public class AnalyzeEpisodesTask : IScheduledTask first.SeriesName, first.SeasonNumber); - // TODO: cache fingerprints and inverted indexes + // Cache all fingerprints + foreach (var episode in episodes) + { + try + { + fingerprintCache[episode.EpisodeId] = Chromaprint.Fingerprint(episode); + } + catch (FingerprintException ex) + { + _logger.LogWarning("Caught fingerprint error: {Ex}", ex); + + // fallback to an empty fingerprint + fingerprintCache[episode.EpisodeId] = Array.Empty(); + } + } + + // TODO: cache inverted indexes // TODO: implementing bucketing @@ -293,16 +288,11 @@ public class AnalyzeEpisodesTask : IScheduledTask Intro outerIntro; Intro innerIntro; - try - { - (outerIntro, innerIntro) = CompareEpisodes(outer, inner); - } - catch (FingerprintException ex) - { - // TODO: remove the episode that threw the error from additional processing - _logger.LogWarning("Caught fingerprint error: {Ex}", ex); - continue; - } + (outerIntro, innerIntro) = CompareEpisodes( + outer.EpisodeId, + fingerprintCache[outer.EpisodeId], + inner.EpisodeId, + fingerprintCache[inner.EpisodeId]); if (!outerIntro.Valid) { @@ -349,34 +339,6 @@ public class AnalyzeEpisodesTask : IScheduledTask #pragma warning restore CA1002 - /// - /// Analyze two episodes to find an introduction sequence shared between them. - /// - /// First episode to analyze. - /// Second episode to analyze. - /// Intros for the first and second episodes. - public (Intro Lhs, Intro Rhs) CompareEpisodes(QueuedEpisode lhsEpisode, QueuedEpisode rhsEpisode) - { - var start = DateTime.Now; - var lhsFingerprint = Chromaprint.Fingerprint(lhsEpisode); - var rhsFingerprint = Chromaprint.Fingerprint(rhsEpisode); - analysisStatistics.FingerprintCPUTime.AddDuration(start); - - // Cache the fingerprints for quicker recall in the second pass (if one is needed). - lock (_fingerprintCacheLock) - { - _fingerprintCache[lhsEpisode.EpisodeId] = lhsFingerprint; - _fingerprintCache[rhsEpisode.EpisodeId] = rhsFingerprint; - } - - return CompareEpisodes( - lhsEpisode.EpisodeId, - lhsFingerprint, - rhsEpisode.EpisodeId, - rhsFingerprint, - true); - } - /// /// Analyze two episodes to find an introduction sequence shared between them. /// @@ -384,17 +346,14 @@ public class AnalyzeEpisodesTask : IScheduledTask /// First episode fingerprint points. /// Second episode id. /// Second episode fingerprint points. - /// If this was called as part of the first analysis pass, add the elapsed time to the statistics. /// Intros for the first and second episodes. public (Intro Lhs, Intro Rhs) CompareEpisodes( Guid lhsId, uint[] lhsPoints, Guid rhsId, - uint[] rhsPoints, - bool isFirstPass) + uint[] rhsPoints) { - // If this isn't running as part of the first analysis pass, don't count this CPU time as first pass time. - var start = isFirstPass ? DateTime.Now : DateTime.MinValue; + var start = DateTime.Now; // Creates an inverted fingerprint point index for both episodes. // For every point which is a 100% match, search for an introduction at that point.