From 86bda2594690d71157775bde0675ddc18a6e17c5 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Tue, 5 Mar 2024 17:33:51 -0500 Subject: [PATCH 1/7] Catch legitimately empty fingerprints --- .../Configuration/configPage.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html index c4bc9a1..b63d77d 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html @@ -746,12 +746,20 @@ lhs = await getJson("Intros/Episode/" + selectEpisode1.value + "/Chromaprint"); rhs = await getJson("Intros/Episode/" + selectEpisode2.value + "/Chromaprint"); - if (lhs === undefined) { + if (lhs === null) { + timestampError.value += "Error: " + selectEpisode1.value + " fingerprints missing!\n"; + } + else if (lhs === undefined) { timestampError.value += "Error: " + selectEpisode1.value + " fingerprints failed!\n"; } + + if (rhs === null) { + timestampError.value += "Error: " + selectEpisode2.value + " fingerprints missing!\n"; + } if (rhs === undefined) { timestampError.value += "Error: " + selectEpisode2.value + " fingerprints failed!"; } + if (timestampError.value == "") { timestampError.style.display = "none"; } else { From 79c834cf08c7be7c9df566304a996357d010aab3 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Tue, 5 Mar 2024 17:58:32 -0500 Subject: [PATCH 2/7] Don't "shift" episodes that didn't load --- .../Configuration/configPage.html | 10 +++++++--- .../FFmpegWrapper.cs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html index b63d77d..9ecdfdc 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html @@ -850,12 +850,16 @@ switch (e.key) { case "ArrowDown": - // if the control key is pressed, shift LHS by 10s. Otherwise, shift by 1. - offsetDelta = e.ctrlKey ? 10 / 0.128 : 1; + if (timestampError.value != "") { + // if the control key is pressed, shift LHS by 10s. Otherwise, shift by 1. + offsetDelta = e.ctrlKey ? 10 / 0.128 : 1; + } break; case "ArrowUp": - offsetDelta = e.ctrlKey ? -10 / 0.128 : -1; + if (timestampError.value != "") { + offsetDelta = e.ctrlKey ? -10 / 0.128 : -1; + } break; case "ArrowRight": diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs b/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs index 95779e6..26a9f75 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/FFmpegWrapper.cs @@ -605,6 +605,25 @@ public static class FFmpegWrapper Encoding.UTF8).ConfigureAwait(false); } + /// + /// Remove a cached episode fingerprint from disk. + /// + /// Episode to remove from cache. + /// Analysis mode. + public static void DeleteEpisodeCache(string episodeId, AnalysisMode mode) + { + var cachePath = Path.Join( + Plugin.Instance!.FingerprintCachePath, + episodeId); + + if (mode == AnalysisMode.Credits) + { + cachePath += "-credits"; + } + + File.Delete(cachePath); + } + /// /// Determines the path an episode should be cached at. /// This function was created before the unified caching mechanism was introduced (in v0.1.7). From 05541b9db0c19ef357d71c014a75bb3bed6364f5 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Tue, 5 Mar 2024 23:32:51 -0500 Subject: [PATCH 3/7] Move visualizer above delete items --- .../Configuration/configPage.html | 55 ++++++++++--------- .../Configuration/visualizer.js | 2 + 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html index 9ecdfdc..67010ea 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html @@ -454,33 +454,17 @@ to
+

-

- -
- - -
- - -
-
-

Fingerprint Visualizer

Interactively compare the audio fingerprints of two episodes.
@@ -526,11 +510,27 @@

- +
+
+
+ + +


+ + +
+ + @@ -602,6 +602,7 @@ var txtSuggested = document.querySelector("span#suggestedShifts"); var btnSeasonEraseTimestamps = document.querySelector("button#btnEraseSeasonTimestamps"); var timestampError = document.querySelector("textarea#timestampError"); + var timestampEditor = document.querySelector("#timestampEditor"); var btnUpdateTimestamps = document.querySelector("button#btnUpdateTimestamps"); var timeContainer = document.querySelector("span#timestampContainer"); @@ -613,8 +614,8 @@ async function autoSkipChanged() { if (autoSkip.checked) { - skipFirstEpisode.style.display = 'block'; - autoSkipNotificationText.style.display = 'block'; + skipFirstEpisode.style.display = 'unset'; + autoSkipNotificationText.style.display = 'unset'; } else { skipFirstEpisode.style.display = 'none'; autoSkipNotificationText.style.display = 'none'; @@ -633,8 +634,8 @@ showAdjustment.style.display = 'none'; hideAdjustment.style.display = 'none'; } else { - showAdjustment.style.display = 'block'; - hideAdjustment.style.display = 'block'; + showAdjustment.style.display = 'unset'; + hideAdjustment.style.display = 'unset'; } } @@ -716,7 +717,7 @@ clearSelect(selectEpisode1); clearSelect(selectEpisode2); - btnSeasonEraseTimestamps.style.display = "block"; + btnSeasonEraseTimestamps.style.display = "unset"; let i = 1; for (let episode of episodes) { @@ -742,6 +743,7 @@ Dashboard.showLoadingMsg(); timestampError.value = ""; + canvas.style.display = "none"; lhs = await getJson("Intros/Episode/" + selectEpisode1.value + "/Chromaprint"); rhs = await getJson("Intros/Episode/" + selectEpisode2.value + "/Chromaprint"); @@ -763,7 +765,7 @@ if (timestampError.value == "") { timestampError.style.display = "none"; } else { - timestampError.style.display = "block"; + timestampError.style.display = "unset"; } Dashboard.hideLoadingMsg(); @@ -793,7 +795,7 @@ } // Update the editor for the first and second episodes - document.querySelector("#timestampEditor").style.display = "unset"; + timestampEditor.style.display = "unset"; document.querySelector("#editLeftEpisodeTitle").textContent = leftEpisode.text; document.querySelector("#editLeftEpisodeStart").value = Math.round(leftEpisodeIntro.IntroStart); document.querySelector("#editLeftEpisodeEnd").value = Math.round(leftEpisodeIntro.IntroEnd); @@ -813,6 +815,9 @@ function clearSelect(select) { timestampError.value = ""; timestampError.style.display = "none"; + timestampEditor.style.display = "none"; + timeContainer.style.display = "none"; + canvas.style.display = "none"; let i, L = select.options.length - 1; for (i = L; i >= 0; i--) { select.remove(i); diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/visualizer.js b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/visualizer.js index 75b2b5a..b4c7401 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/visualizer.js +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/visualizer.js @@ -169,6 +169,8 @@ function paintFingerprintDiff(canvas, fp1, fp2, offset) { return; } + canvas.style.display = "unset"; + let leftOffset = 0, rightOffset = 0; if (offset < 0) { leftOffset -= offset; From 7e2f1b56d5442d97af7b0a25fb66a72eeeea6b61 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Wed, 6 Mar 2024 08:56:19 -0500 Subject: [PATCH 4/7] Only check next chapter is possible --- .gitignore | 1 - .../Analyzers/ChapterAnalyzer.cs | 21 +++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 6908286..bc18978 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,3 @@ docker/dist # Visual Studio .vs/ -UpgradeLog*.htm diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs index 1474d74..0b146a7 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs @@ -149,16 +149,19 @@ public class ChapterAnalyzer : IMediaFileAnalyzer continue; } - // Check for possibility of overlapping keywords - var overlap = Regex.IsMatch( - next.Name, - expression, - RegexOptions.None, - TimeSpan.FromSeconds(1)); - - if (overlap) + if (!string.IsNullOrWhiteSpace(next.Name)) { - continue; + // Check for possibility of overlapping keywords + var overlap = Regex.IsMatch( + next.Name, + expression, + RegexOptions.None, + TimeSpan.FromSeconds(1)); + + if (overlap) + { + continue; + } } matchingChapter = new(episode.EpisodeId, currentRange); From dfe28b708081270f36a61be0e9bd45fa51c6d783 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Wed, 6 Mar 2024 09:08:04 -0500 Subject: [PATCH 5/7] Make the artifacts a little more useful --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 833d7bf..c3b1fa5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,7 +39,7 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4.3.1 with: - name: intro-skipper-${{ github.sha }}.dll + name: ConfusedPolarBear.Plugin.IntroSkipper-${{ env.GIT_HASH }}.dll path: ConfusedPolarBear.Plugin.IntroSkipper/bin/Debug/net6.0/ConfusedPolarBear.Plugin.IntroSkipper.dll if-no-files-found: error From c6bb3dbad5c1349eb0d60209f1b4b6abb489b995 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Wed, 6 Mar 2024 10:15:03 -0500 Subject: [PATCH 6/7] Search credits from the end of episode --- .../Analyzers/ChapterAnalyzer.cs | 151 ++++++++++++------ .../Configuration/PluginConfiguration.cs | 2 +- 2 files changed, 104 insertions(+), 49 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs index 0b146a7..dd2b2cf 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Analyzers/ChapterAnalyzer.cs @@ -96,6 +96,11 @@ public class ChapterAnalyzer : IMediaFileAnalyzer config.MaximumIntroDuration : config.MaximumEpisodeCreditsDuration; + if (chapters.Count == 0) + { + return null; + } + if (mode == AnalysisMode.Credits) { // Since the ending credits chapter may be the last chapter in the file, append a virtual @@ -104,69 +109,119 @@ public class ChapterAnalyzer : IMediaFileAnalyzer { StartPositionTicks = TimeSpan.FromSeconds(episode.Duration).Ticks }); - } - // Check all chapters - for (int i = 0; i < chapters.Count - 1; i++) - { - var current = chapters[i]; - var next = chapters[i + 1]; - - if (string.IsNullOrWhiteSpace(current.Name)) + // Check all chapters in reverse order, skipping the virtual chapter + for (int i = chapters.Count - 2; i >= 0; i--) { - continue; - } + var current = chapters[i]; + var next = chapters[i + 1]; - var currentRange = new TimeRange( - TimeSpan.FromTicks(current.StartPositionTicks).TotalSeconds, - TimeSpan.FromTicks(next.StartPositionTicks).TotalSeconds); + if (string.IsNullOrWhiteSpace(current.Name)) + { + continue; + } - var baseMessage = string.Format( - CultureInfo.InvariantCulture, - "{0}: Chapter \"{1}\" ({2} - {3})", - episode.Path, - current.Name, - currentRange.Start, - currentRange.End); + var currentRange = new TimeRange( + TimeSpan.FromTicks(current.StartPositionTicks).TotalSeconds, + TimeSpan.FromTicks(next.StartPositionTicks).TotalSeconds); - if (currentRange.Duration < minDuration || currentRange.Duration > maxDuration) - { - _logger.LogTrace("{Base}: ignoring (invalid duration)", baseMessage); - continue; - } + var baseMessage = string.Format( + CultureInfo.InvariantCulture, + "{0}: Chapter \"{1}\" ({2} - {3})", + episode.Path, + current.Name, + currentRange.Start, + currentRange.End); - // Regex.IsMatch() is used here in order to allow the runtime to cache the compiled regex - // between function invocations. - var match = Regex.IsMatch( - current.Name, - expression, - RegexOptions.None, - TimeSpan.FromSeconds(1)); + if (currentRange.Duration < minDuration || currentRange.Duration > maxDuration) + { + _logger.LogTrace("{Base}: ignoring (invalid duration)", baseMessage); + continue; + } - if (!match) - { - _logger.LogTrace("{Base}: ignoring (does not match regular expression)", baseMessage); - continue; - } - - if (!string.IsNullOrWhiteSpace(next.Name)) - { - // Check for possibility of overlapping keywords - var overlap = Regex.IsMatch( - next.Name, + // Regex.IsMatch() is used here in order to allow the runtime to cache the compiled regex + // between function invocations. + var match = Regex.IsMatch( + current.Name, expression, RegexOptions.None, TimeSpan.FromSeconds(1)); - if (overlap) + if (!match) + { + _logger.LogTrace("{Base}: ignoring (does not match regular expression)", baseMessage); + continue; + } + + matchingChapter = new(episode.EpisodeId, currentRange); + _logger.LogTrace("{Base}: okay", baseMessage); + break; + } + } + else + { + // Check all chapters + for (int i = 0; i < chapters.Count - 1; i++) + { + var current = chapters[i]; + var next = chapters[i + 1]; + + if (string.IsNullOrWhiteSpace(current.Name)) { continue; } - } - matchingChapter = new(episode.EpisodeId, currentRange); - _logger.LogTrace("{Base}: okay", baseMessage); - break; + var currentRange = new TimeRange( + TimeSpan.FromTicks(current.StartPositionTicks).TotalSeconds, + TimeSpan.FromTicks(next.StartPositionTicks).TotalSeconds); + + var baseMessage = string.Format( + CultureInfo.InvariantCulture, + "{0}: Chapter \"{1}\" ({2} - {3})", + episode.Path, + current.Name, + currentRange.Start, + currentRange.End); + + if (currentRange.Duration < minDuration || currentRange.Duration > maxDuration) + { + _logger.LogTrace("{Base}: ignoring (invalid duration)", baseMessage); + continue; + } + + // Regex.IsMatch() is used here in order to allow the runtime to cache the compiled regex + // between function invocations. + var match = Regex.IsMatch( + current.Name, + expression, + RegexOptions.None, + TimeSpan.FromSeconds(1)); + + if (!match) + { + _logger.LogTrace("{Base}: ignoring (does not match regular expression)", baseMessage); + continue; + } + + if (!string.IsNullOrWhiteSpace(next.Name)) + { + // Check for possibility of overlapping keywords + var overlap = Regex.IsMatch( + next.Name, + expression, + RegexOptions.None, + TimeSpan.FromSeconds(1)); + + if (overlap) + { + continue; + } + } + + matchingChapter = new(episode.EpisodeId, currentRange); + _logger.LogTrace("{Base}: okay", baseMessage); + break; + } } return matchingChapter; diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs index 76e5896..06384eb 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs @@ -103,7 +103,7 @@ public class PluginConfiguration : BasePluginConfiguration /// Gets or sets the regular expression used to detect ending credit chapters. ///
public string ChapterAnalyzerEndCreditsPattern { get; set; } = - @"(^|\s)(Credits?|Ending)(\s|$)"; + @"(^|\s)(Credits?|ED|Ending)(\s|$)"; // ===== Playback settings ===== From defc3f1da51ef7cac5f748d4b181f46eef26b179 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Wed, 6 Mar 2024 10:23:34 -0500 Subject: [PATCH 7/7] v0.1.16.1 --- .../ConfusedPolarBear.Plugin.IntroSkipper.csproj | 4 ++-- manifest.json | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj b/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj index 254bf30..86ac372 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj @@ -2,8 +2,8 @@ net6.0 ConfusedPolarBear.Plugin.IntroSkipper - 0.1.16.0 - 0.1.16.0 + 0.1.16.1 + 0.1.16.1 true true enable diff --git a/manifest.json b/manifest.json index 6a3e2ff..c131344 100644 --- a/manifest.json +++ b/manifest.json @@ -8,6 +8,14 @@ "category": "General", "imageUrl": "https://raw.githubusercontent.com/jumoog/intro-skipper/master/images/logo.png", "versions": [ + { + "version": "0.1.16.1", + "changelog": "- See the full changelog at [GitHub](https://github.com/jumoog/intro-skipper/blob/master/CHANGELOG.md)\n", + "targetAbi": "10.8.4.0", + "sourceUrl": "https://github.com/jumoog/intro-skipper/releases/download/v0.1.16.1/intro-skipper-v0.1.16.1.zip", + "checksum": "d8e5370f974bd5624206f87b3fed05bb", + "timestamp": "2024-03-06T10:17:25Z" + }, { "version": "0.1.16.0", "changelog": "- See the full changelog at [GitHub](https://github.com/jumoog/intro-skipper/blob/master/CHANGELOG.md)\n",