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.