Merge pull request #63 from RepoDevil/upstream

Visualizer cleanup
This commit is contained in:
TwistedUmbrellaX 2024-03-06 10:25:11 -05:00 committed by GitHub
commit 3559c7b7d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 193 additions and 90 deletions

View File

@ -39,7 +39,7 @@ jobs:
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4.3.1 uses: actions/upload-artifact@v4.3.1
with: 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 path: ConfusedPolarBear.Plugin.IntroSkipper/bin/Debug/net6.0/ConfusedPolarBear.Plugin.IntroSkipper.dll
if-no-files-found: error if-no-files-found: error

1
.gitignore vendored
View File

@ -8,4 +8,3 @@ docker/dist
# Visual Studio # Visual Studio
.vs/ .vs/
UpgradeLog*.htm

View File

@ -96,6 +96,11 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
config.MaximumIntroDuration : config.MaximumIntroDuration :
config.MaximumEpisodeCreditsDuration; config.MaximumEpisodeCreditsDuration;
if (chapters.Count == 0)
{
return null;
}
if (mode == AnalysisMode.Credits) if (mode == AnalysisMode.Credits)
{ {
// Since the ending credits chapter may be the last chapter in the file, append a virtual // Since the ending credits chapter may be the last chapter in the file, append a virtual
@ -104,8 +109,57 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
{ {
StartPositionTicks = TimeSpan.FromSeconds(episode.Duration).Ticks StartPositionTicks = TimeSpan.FromSeconds(episode.Duration).Ticks
}); });
// Check all chapters in reverse order, skipping the virtual chapter
for (int i = chapters.Count - 2; i >= 0; i--)
{
var current = chapters[i];
var next = chapters[i + 1];
if (string.IsNullOrWhiteSpace(current.Name))
{
continue;
} }
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;
}
matchingChapter = new(episode.EpisodeId, currentRange);
_logger.LogTrace("{Base}: okay", baseMessage);
break;
}
}
else
{
// Check all chapters // Check all chapters
for (int i = 0; i < chapters.Count - 1; i++) for (int i = 0; i < chapters.Count - 1; i++)
{ {
@ -149,6 +203,8 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
continue; continue;
} }
if (!string.IsNullOrWhiteSpace(next.Name))
{
// Check for possibility of overlapping keywords // Check for possibility of overlapping keywords
var overlap = Regex.IsMatch( var overlap = Regex.IsMatch(
next.Name, next.Name,
@ -160,11 +216,13 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
{ {
continue; continue;
} }
}
matchingChapter = new(episode.EpisodeId, currentRange); matchingChapter = new(episode.EpisodeId, currentRange);
_logger.LogTrace("{Base}: okay", baseMessage); _logger.LogTrace("{Base}: okay", baseMessage);
break; break;
} }
}
return matchingChapter; return matchingChapter;
} }

View File

@ -103,7 +103,7 @@ public class PluginConfiguration : BasePluginConfiguration
/// Gets or sets the regular expression used to detect ending credit chapters. /// Gets or sets the regular expression used to detect ending credit chapters.
/// </summary> /// </summary>
public string ChapterAnalyzerEndCreditsPattern { get; set; } = public string ChapterAnalyzerEndCreditsPattern { get; set; } =
@"(^|\s)(Credits?|Ending)(\s|$)"; @"(^|\s)(Credits?|ED|Ending)(\s|$)";
// ===== Playback settings ===== // ===== Playback settings =====

View File

@ -454,33 +454,17 @@
<input style="width:4em" type="number" min="0" id="editRightEpisodeStart"> to <input style="width:4em" type="number" min="0" id="editRightEpisodeStart"> to
<input style="width:4em;margin-bottom:10px" type="number" min="0" id="editRightEpisodeEnd"> <input style="width:4em;margin-bottom:10px" type="number" min="0" id="editRightEpisodeEnd">
<br /> <br />
<br />
<button id="btnUpdateTimestamps" type="button"> <button id="btnUpdateTimestamps" type="button">
Update timestamps Update timestamps
</button> </button>
<br /> <br />
<br />
</div> </div>
<textarea id="timestampError" style="display:none;" rows="2" cols="75" readonly></textarea> <textarea id="timestampError" style="display:none;" rows="2" cols="75" readonly></textarea>
<br /> <br />
<button id="btnEraseSeasonTimestamps" type="button" style="display:none;">
Erase all timestamps for this season
</button>
<hr />
<button id="btnEraseIntroTimestamps">
Erase all introduction timestamps (globally)
</button>
<br />
<button id="btnEraseCreditTimestamps">
Erase all end credits timestamps (globally)
</button>
<br />
<br />
<h3>Fingerprint Visualizer</h3> <h3>Fingerprint Visualizer</h3>
<p> <p>
Interactively compare the audio fingerprints of two episodes. <br /> Interactively compare the audio fingerprints of two episodes. <br />
@ -526,11 +510,27 @@
<br /> <br />
<br /> <br />
<canvas id="troubleshooter"></canvas> <canvas id="troubleshooter" style="display:none;"></canvas>
<span id="timestampContainer"> <span id="timestampContainer">
<span id="timestamps"></span> <br /> <span id="timestamps"></span> <br />
<span id="intros"></span> <span id="intros"></span>
</span> </span>
<br />
<br />
<button id="btnEraseSeasonTimestamps" type="button" style="display:none;">
Erase all timestamps for this season
</button>
<hr />
<button id="btnEraseIntroTimestamps">
Erase all introduction timestamps (globally)
</button>
<br />
<button id="btnEraseCreditTimestamps">
Erase all end credits timestamps (globally)
</button>
</details> </details>
</fieldset> </fieldset>
</div> </div>
@ -602,6 +602,7 @@
var txtSuggested = document.querySelector("span#suggestedShifts"); var txtSuggested = document.querySelector("span#suggestedShifts");
var btnSeasonEraseTimestamps = document.querySelector("button#btnEraseSeasonTimestamps"); var btnSeasonEraseTimestamps = document.querySelector("button#btnEraseSeasonTimestamps");
var timestampError = document.querySelector("textarea#timestampError"); var timestampError = document.querySelector("textarea#timestampError");
var timestampEditor = document.querySelector("#timestampEditor");
var btnUpdateTimestamps = document.querySelector("button#btnUpdateTimestamps"); var btnUpdateTimestamps = document.querySelector("button#btnUpdateTimestamps");
var timeContainer = document.querySelector("span#timestampContainer"); var timeContainer = document.querySelector("span#timestampContainer");
@ -613,8 +614,8 @@
async function autoSkipChanged() { async function autoSkipChanged() {
if (autoSkip.checked) { if (autoSkip.checked) {
skipFirstEpisode.style.display = 'block'; skipFirstEpisode.style.display = 'unset';
autoSkipNotificationText.style.display = 'block'; autoSkipNotificationText.style.display = 'unset';
} else { } else {
skipFirstEpisode.style.display = 'none'; skipFirstEpisode.style.display = 'none';
autoSkipNotificationText.style.display = 'none'; autoSkipNotificationText.style.display = 'none';
@ -633,8 +634,8 @@
showAdjustment.style.display = 'none'; showAdjustment.style.display = 'none';
hideAdjustment.style.display = 'none'; hideAdjustment.style.display = 'none';
} else { } else {
showAdjustment.style.display = 'block'; showAdjustment.style.display = 'unset';
hideAdjustment.style.display = 'block'; hideAdjustment.style.display = 'unset';
} }
} }
@ -716,7 +717,7 @@
clearSelect(selectEpisode1); clearSelect(selectEpisode1);
clearSelect(selectEpisode2); clearSelect(selectEpisode2);
btnSeasonEraseTimestamps.style.display = "block"; btnSeasonEraseTimestamps.style.display = "unset";
let i = 1; let i = 1;
for (let episode of episodes) { for (let episode of episodes) {
@ -742,20 +743,29 @@
Dashboard.showLoadingMsg(); Dashboard.showLoadingMsg();
timestampError.value = ""; timestampError.value = "";
canvas.style.display = "none";
lhs = await getJson("Intros/Episode/" + selectEpisode1.value + "/Chromaprint"); lhs = await getJson("Intros/Episode/" + selectEpisode1.value + "/Chromaprint");
rhs = await getJson("Intros/Episode/" + selectEpisode2.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"; timestampError.value += "Error: " + selectEpisode1.value + " fingerprints failed!\n";
} }
if (rhs === null) {
timestampError.value += "Error: " + selectEpisode2.value + " fingerprints missing!\n";
}
if (rhs === undefined) { if (rhs === undefined) {
timestampError.value += "Error: " + selectEpisode2.value + " fingerprints failed!"; timestampError.value += "Error: " + selectEpisode2.value + " fingerprints failed!";
} }
if (timestampError.value == "") { if (timestampError.value == "") {
timestampError.style.display = "none"; timestampError.style.display = "none";
} else { } else {
timestampError.style.display = "block"; timestampError.style.display = "unset";
} }
Dashboard.hideLoadingMsg(); Dashboard.hideLoadingMsg();
@ -785,7 +795,7 @@
} }
// Update the editor for the first and second episodes // 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("#editLeftEpisodeTitle").textContent = leftEpisode.text;
document.querySelector("#editLeftEpisodeStart").value = Math.round(leftEpisodeIntro.IntroStart); document.querySelector("#editLeftEpisodeStart").value = Math.round(leftEpisodeIntro.IntroStart);
document.querySelector("#editLeftEpisodeEnd").value = Math.round(leftEpisodeIntro.IntroEnd); document.querySelector("#editLeftEpisodeEnd").value = Math.round(leftEpisodeIntro.IntroEnd);
@ -805,6 +815,9 @@
function clearSelect(select) { function clearSelect(select) {
timestampError.value = ""; timestampError.value = "";
timestampError.style.display = "none"; timestampError.style.display = "none";
timestampEditor.style.display = "none";
timeContainer.style.display = "none";
canvas.style.display = "none";
let i, L = select.options.length - 1; let i, L = select.options.length - 1;
for (i = L; i >= 0; i--) { for (i = L; i >= 0; i--) {
select.remove(i); select.remove(i);
@ -842,12 +855,16 @@
switch (e.key) { switch (e.key) {
case "ArrowDown": case "ArrowDown":
if (timestampError.value != "") {
// if the control key is pressed, shift LHS by 10s. Otherwise, shift by 1. // if the control key is pressed, shift LHS by 10s. Otherwise, shift by 1.
offsetDelta = e.ctrlKey ? 10 / 0.128 : 1; offsetDelta = e.ctrlKey ? 10 / 0.128 : 1;
}
break; break;
case "ArrowUp": case "ArrowUp":
if (timestampError.value != "") {
offsetDelta = e.ctrlKey ? -10 / 0.128 : -1; offsetDelta = e.ctrlKey ? -10 / 0.128 : -1;
}
break; break;
case "ArrowRight": case "ArrowRight":

View File

@ -169,6 +169,8 @@ function paintFingerprintDiff(canvas, fp1, fp2, offset) {
return; return;
} }
canvas.style.display = "unset";
let leftOffset = 0, rightOffset = 0; let leftOffset = 0, rightOffset = 0;
if (offset < 0) { if (offset < 0) {
leftOffset -= offset; leftOffset -= offset;

View File

@ -2,8 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<RootNamespace>ConfusedPolarBear.Plugin.IntroSkipper</RootNamespace> <RootNamespace>ConfusedPolarBear.Plugin.IntroSkipper</RootNamespace>
<AssemblyVersion>0.1.16.0</AssemblyVersion> <AssemblyVersion>0.1.16.1</AssemblyVersion>
<FileVersion>0.1.16.0</FileVersion> <FileVersion>0.1.16.1</FileVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>

View File

@ -605,6 +605,25 @@ public static class FFmpegWrapper
Encoding.UTF8).ConfigureAwait(false); Encoding.UTF8).ConfigureAwait(false);
} }
/// <summary>
/// Remove a cached episode fingerprint from disk.
/// </summary>
/// <param name="episodeId">Episode to remove from cache.</param>
/// <param name="mode">Analysis mode.</param>
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);
}
/// <summary> /// <summary>
/// Determines the path an episode should be cached at. /// Determines the path an episode should be cached at.
/// This function was created before the unified caching mechanism was introduced (in v0.1.7). /// This function was created before the unified caching mechanism was introduced (in v0.1.7).

View File

@ -8,6 +8,14 @@
"category": "General", "category": "General",
"imageUrl": "https://raw.githubusercontent.com/jumoog/intro-skipper/master/images/logo.png", "imageUrl": "https://raw.githubusercontent.com/jumoog/intro-skipper/master/images/logo.png",
"versions": [ "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", "version": "0.1.16.0",
"changelog": "- See the full changelog at [GitHub](https://github.com/jumoog/intro-skipper/blob/master/CHANGELOG.md)\n", "changelog": "- See the full changelog at [GitHub](https://github.com/jumoog/intro-skipper/blob/master/CHANGELOG.md)\n",