From 05c5526bca80034b91e2026b607cceb52704c9fa Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Tue, 17 May 2022 01:33:49 -0500 Subject: [PATCH] Cache the fingerprints for a season temporarily --- .../ScheduledTasks/FingerprinterTask.cs | 78 ++++++++++++------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs index d4a4def..8a75883 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs @@ -46,6 +46,14 @@ public class FingerprinterTask : IScheduledTask private readonly ILogger _logger; + private readonly object _fingerprintCacheLock = new object(); + + /// + /// Temporary fingerprint cache to speed up reanalysis. + /// Fingerprints are removed from this after a season is analyzed. + /// + private Dictionary> _fingerprintCache; + /// /// Initializes a new instance of the class. /// @@ -53,6 +61,7 @@ public class FingerprinterTask : IScheduledTask public FingerprinterTask(ILogger logger) { _logger = logger; + _fingerprintCache = new Dictionary>(); } /// @@ -88,9 +97,38 @@ public class FingerprinterTask : IScheduledTask Parallel.ForEach(queue, (season) => { - AnalyzeSeason(season, cancellationToken); + var first = season.Value[0]; + + try + { + AnalyzeSeason(season, cancellationToken); + } + catch (FingerprintException ex) + { + _logger.LogWarning( + "Unable to analyze {Series} season {Season}: unable to fingerprint: {Ex}", + first.SeriesName, + first.SeasonNumber, + ex); + } + catch (KeyNotFoundException ex) + { + _logger.LogWarning( + "Unable to analyze {Series} season {Season}: cache miss: {Ex}", + first.SeriesName, + first.SeasonNumber, + ex); + } + + // Clear this season's episodes from the temporary fingerprint cache. + lock (_fingerprintCacheLock) + { + foreach (var ep in season.Value) + { + _fingerprintCache.Remove(ep.EpisodeId); + } + } - // TODO: report progress on a per episode basis totalProcessed += season.Value.Count; progress.Report((totalProcessed * 100) / Plugin.Instance!.TotalQueued); }); @@ -159,12 +197,6 @@ public class FingerprinterTask : IScheduledTask lhs.EpisodeId, rhs.EpisodeId); - /* - TODO: bring back - totalProcessed += 2; - progress.Report((totalProcessed * 100) / Plugin.Instance!.TotalQueued); - */ - continue; } @@ -189,14 +221,6 @@ public class FingerprinterTask : IScheduledTask { _logger.LogError("Caught fingerprint error: {Ex}", ex); } - finally - { - /* - TODO: bring back - totalProcessed += 2; - progress.Report((totalProcessed * 100) / Plugin.Instance!.TotalQueued); - */ - } } Plugin.Instance!.SaveTimestamps(); @@ -221,6 +245,13 @@ public class FingerprinterTask : IScheduledTask var lhsFingerprint = FPCalc.Fingerprint(lhsEpisode); var rhsFingerprint = FPCalc.Fingerprint(rhsEpisode); + // 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 FingerprintEpisodes( lhsEpisode.EpisodeId, lhsFingerprint, @@ -501,7 +532,6 @@ public class FingerprinterTask : IScheduledTask _logger.LogInformation("Reanalyzing {Count} episodes", totalCount - maxBucket.Count); // TODO: pick two episodes at random - // Cache the fingerprint of the first episode in the max bucket to save CPU cycles var lhs = episodes.Find(x => x.EpisodeId == maxBucket.Episodes[1]); if (lhs is null) { @@ -509,17 +539,7 @@ public class FingerprinterTask : IScheduledTask return; } - ReadOnlyCollection lhsFingerprint; - try - { - lhsFingerprint = FPCalc.Fingerprint(lhs); - } - catch (FingerprintException ex) - { - _logger.LogWarning("Skipping reanalysis of {Show} season {Season}: {Exception}", lhs.SeriesName, lhs.SeasonNumber, ex); - return; - } - + var lhsFingerprint = _fingerprintCache[lhs.EpisodeId]; var lhsDuration = GetIntroDuration(lhs.EpisodeId); var (lowTargetDuration, highTargetDuration) = ( lhsDuration - ReanalysisTolerance, @@ -561,7 +581,7 @@ public class FingerprinterTask : IScheduledTask lhs.EpisodeId, lhsFingerprint, episode.EpisodeId, - FPCalc.Fingerprint(episode)); + _fingerprintCache[episode.EpisodeId]); // Ensure that the new intro duration is within the targeted bucket and longer than what was found previously. var newDuration = Math.Round(newRhs.IntroEnd - newRhs.IntroStart, 2);