diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html
index 8e03f1a..b898079 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html
@@ -615,11 +615,6 @@
-
-
-
@@ -644,7 +639,6 @@
var support = document.querySelector("details#support");
var btnEraseIntroTimestamps = document.querySelector("button#btnEraseIntroTimestamps");
var btnEraseCreditTimestamps = document.querySelector("button#btnEraseCreditTimestamps");
- var btnCleanCache = document.querySelector("button#btnCleanCache");
// all plugin configuration fields that can be get or set with .value (i.e. strings or numbers).
var configurationFields = [
@@ -1060,25 +1054,6 @@
});
}
- // erase all intro/credits cache
- function cleanCache() {
- const title = "Confirm Cache erasure";
- const body = "Are you sure you want to erase all unused fingerprints?";
-
- Dashboard.confirm(
- body,
- title,
- (result) => {
- if (!result) {
- return;
- }
-
- fetchWithAuth("Intros/CleanCache", "POST", null);
-
- Dashboard.alert("Cache cleaned");
- });
- }
-
document.querySelector('#TemplateConfigPage')
.addEventListener('pageshow', function () {
Dashboard.showLoadingMsg();
@@ -1136,10 +1111,6 @@
eraseTimestamps("Credits");
e.preventDefault();
});
- btnCleanCache.addEventListener("click", (e) => {
- cleanCache();
- e.preventDefault();
- });
btnSeasonEraseTimestamps.addEventListener("click", () => {
Dashboard.confirm(
"Are you sure you want to erase all timestamps for this season?",
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs
index a88e551..9e60310 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs
@@ -139,19 +139,6 @@ public class SkipIntroController : ControllerBase
return NoContent();
}
- ///
- /// Erases all previously cached introduction fingerprints.
- ///
- /// Operation successful.
- /// No content.
- [Authorize(Policy = "RequiresElevation")]
- [HttpPost("Intros/CleanCache")]
- public ActionResult CleanIntroCache()
- {
- FFmpegWrapper.CleanCacheFiles();
- return NoContent();
- }
-
///
/// Get all introductions or credits. Only used by the end to end testing script.
///
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs b/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs
index 4926d49..dac33f2 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs
@@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
@@ -641,35 +640,6 @@ public static class FFmpegWrapper
}
}
- ///
- /// Remove a cached episode fingerprint from disk.
- ///
- public static void CleanCacheFiles()
- {
- // Get valid episode IDs from the dictionaries
- HashSet validEpisodeIds = new HashSet(Plugin.Instance!.Intros.Keys.Concat(Plugin.Instance!.Credits.Keys)); // Or use GetMediaItems instead?
-
- // Delete invalid cache files
- foreach (string filePath in Directory.EnumerateFiles(Plugin.Instance!.FingerprintCachePath))
- {
- string fileName = Path.GetFileNameWithoutExtension(filePath);
-
- int dashIndex = fileName.IndexOf('-', StringComparison.Ordinal); // Find the index of the first '-' character
- if (dashIndex > 0)
- {
- fileName = fileName.Substring(0, dashIndex);
- }
-
- if (Guid.TryParse(fileName, out Guid episodeId))
- {
- if (!validEpisodeIds.Contains(episodeId))
- {
- DeleteEpisodeCache(episodeId);
- }
- }
- }
- }
-
///
/// Determines the path an episode should be cached at.
/// This function was created before the unified caching mechanism was introduced (in v0.1.7).
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs
index cef2d2e..f2dcdf5 100644
--- a/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs
@@ -374,6 +374,24 @@ public class Plugin : BasePlugin, IHasWebPages
SaveTimestamps(mode);
}
+ internal void CleanTimestamps(HashSet validEpisodeIds)
+ {
+ var allKeys = new HashSet(Instance!.Intros.Keys);
+ allKeys.UnionWith(Instance!.Credits.Keys);
+
+ foreach (var key in allKeys)
+ {
+ if (!validEpisodeIds.Contains(key))
+ {
+ Instance!.Intros.TryRemove(key, out _);
+ Instance!.Credits.TryRemove(key, out _);
+ }
+ }
+
+ SaveTimestamps(AnalysisMode.Introduction);
+ SaveTimestamps(AnalysisMode.Credits);
+ }
+
///
/// Inject the skip button script into the web interface.
///
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/CleanCacheTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/CleanCacheTask.cs
new file mode 100644
index 0000000..e58e226
--- /dev/null
+++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/CleanCacheTask.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace ConfusedPolarBear.Plugin.IntroSkipper;
+
+///
+/// Analyze all television episodes for introduction sequences.
+///
+public class CleanCacheTask : IScheduledTask
+{
+ private readonly ILogger _logger;
+
+ private readonly ILoggerFactory _loggerFactory;
+
+ private readonly ILibraryManager _libraryManager;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Logger factory.
+ /// Library manager.
+ /// Logger.
+ public CleanCacheTask(
+ ILogger logger,
+ ILoggerFactory loggerFactory,
+ ILibraryManager libraryManager)
+ {
+ _logger = logger;
+ _loggerFactory = loggerFactory;
+ _libraryManager = libraryManager;
+ }
+
+ ///
+ /// Gets the task name.
+ ///
+ public string Name => "Clean Intro Skipper Cache";
+
+ ///
+ /// Gets the task category.
+ ///
+ public string Category => "Intro Skipper";
+
+ ///
+ /// Gets the task description.
+ ///
+ public string Description => "Clear Intro Skipper cache of unused files.";
+
+ ///
+ /// Gets the task key.
+ ///
+ public string Key => "CPBIntroSkipperCleanCache";
+
+ ///
+ /// Cleans the Intro Skipper cache by removing files that are no longer associated with episodes in the library.
+ ///
+ /// Task progress.
+ /// Cancellation token.
+ /// Task.
+ public Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken)
+ {
+ if (_libraryManager is null)
+ {
+ throw new InvalidOperationException("Library manager was null");
+ }
+
+ var queueManager = new QueueManager(
+ _loggerFactory.CreateLogger(),
+ _libraryManager);
+
+ // Retrieve media items and get valid episode IDs
+ var queue = queueManager.GetMediaItems();
+ var validEpisodeIds = new HashSet(queue.Values.SelectMany(episodes => episodes.Select(e => e.EpisodeId)));
+
+ Plugin.Instance!.CleanTimestamps(validEpisodeIds);
+
+ // Identify invalid episode IDs
+ var invalidEpisodeIds = Directory.EnumerateFiles(Plugin.Instance!.FingerprintCachePath)
+ .Select(filePath =>
+ {
+ var fileName = Path.GetFileNameWithoutExtension(filePath);
+ var episodeIdStr = fileName.Split('-')[0];
+ if (Guid.TryParse(episodeIdStr, out Guid episodeId))
+ {
+ return validEpisodeIds.Contains(episodeId) ? (Guid?)null : episodeId;
+ }
+
+ return null;
+ })
+ .OfType()
+ .ToHashSet();
+
+ // Delete cache files for invalid episode IDs
+ foreach (var episodeId in invalidEpisodeIds)
+ {
+ _logger.LogDebug("Deleting cache files for episode ID: {EpisodeId}", episodeId);
+ FFmpegWrapper.DeleteEpisodeCache(episodeId);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// Get task triggers.
+ ///
+ /// Task triggers.
+ public IEnumerable GetDefaultTriggers()
+ {
+ return Array.Empty();
+ }
+}