analyze movies (#348)
* scan movies * Update ConfusedPolarBear.Plugin.IntroSkipper.csproj * fix * Update SegmentProvider.cs * fix * update * add movies to endpoints * Update * Update QueueManager.cs * revert * Update configPage.html Battery died. I’ll be back * “Borrow” show config to hide seasons * Add IsMovie to ShowInfos * remove unused usings * Add option to enable/disble movies * Use the left episode as movie editor * Timestamp erasure for movies * Add max credits duration for movies * Formatting and button style cleanup * remove fingerprint timings for movies * remove x2 from MaximumCreditsDuration in blackframe analyzer * Update SegmentProvider.cs * Update SegmentProvider.cs * Update SegmentProvider.cs * Update SegmentProvider.cs * Update BaseItemAnalyzerTask.cs --------- Co-Authored-By: rlauu <46294892+rlauu@users.noreply.github.com> Co-Authored-By: TwistedUmbrellaX <1173913+AbandonedCart@users.noreply.github.com>
This commit is contained in:
parent
7198dfdfca
commit
627ae05def
@ -22,6 +22,8 @@ public class BlackFrameAnalyzer : IMediaFileAnalyzer
|
|||||||
|
|
||||||
private readonly int _maximumCreditsDuration;
|
private readonly int _maximumCreditsDuration;
|
||||||
|
|
||||||
|
private readonly int _maximumMovieCreditsDuration;
|
||||||
|
|
||||||
private readonly int _blackFrameMinimumPercentage;
|
private readonly int _blackFrameMinimumPercentage;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -32,7 +34,8 @@ public class BlackFrameAnalyzer : IMediaFileAnalyzer
|
|||||||
{
|
{
|
||||||
var config = Plugin.Instance?.Configuration ?? new PluginConfiguration();
|
var config = Plugin.Instance?.Configuration ?? new PluginConfiguration();
|
||||||
_minimumCreditsDuration = config.MinimumCreditsDuration;
|
_minimumCreditsDuration = config.MinimumCreditsDuration;
|
||||||
_maximumCreditsDuration = 2 * config.MaximumCreditsDuration;
|
_maximumCreditsDuration = config.MaximumCreditsDuration;
|
||||||
|
_maximumMovieCreditsDuration = config.MaximumMovieCreditsDuration;
|
||||||
_blackFrameMinimumPercentage = config.BlackFrameMinimumPercentage;
|
_blackFrameMinimumPercentage = config.BlackFrameMinimumPercentage;
|
||||||
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -66,7 +69,21 @@ public class BlackFrameAnalyzer : IMediaFileAnalyzer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-check to find reasonable starting point.
|
var creditDuration = episode.IsMovie ? _maximumMovieCreditsDuration : _maximumCreditsDuration;
|
||||||
|
|
||||||
|
var chapters = Plugin.Instance!.GetChapters(episode.EpisodeId);
|
||||||
|
var lastSuitableChapter = chapters.LastOrDefault(c =>
|
||||||
|
{
|
||||||
|
var start = TimeSpan.FromTicks(c.StartPositionTicks).TotalSeconds;
|
||||||
|
return start >= _minimumCreditsDuration && start <= creditDuration;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (lastSuitableChapter is not null)
|
||||||
|
{
|
||||||
|
searchStart = TimeSpan.FromTicks(lastSuitableChapter.StartPositionTicks).TotalSeconds;
|
||||||
|
isFirstEpisode = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isFirstEpisode)
|
if (isFirstEpisode)
|
||||||
{
|
{
|
||||||
var scanTime = episode.Duration - searchStart;
|
var scanTime = episode.Duration - searchStart;
|
||||||
@ -83,9 +100,9 @@ public class BlackFrameAnalyzer : IMediaFileAnalyzer
|
|||||||
|
|
||||||
frames = FFmpegWrapper.DetectBlackFrames(episode, tr, _blackFrameMinimumPercentage);
|
frames = FFmpegWrapper.DetectBlackFrames(episode, tr, _blackFrameMinimumPercentage);
|
||||||
|
|
||||||
if (searchStart > _maximumCreditsDuration)
|
if (searchStart > creditDuration)
|
||||||
{
|
{
|
||||||
searchStart = _maximumCreditsDuration;
|
searchStart = creditDuration;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,6 +160,8 @@ public class BlackFrameAnalyzer : IMediaFileAnalyzer
|
|||||||
var end = TimeSpan.FromSeconds(lowerLimit);
|
var end = TimeSpan.FromSeconds(lowerLimit);
|
||||||
var firstFrameTime = 0.0;
|
var firstFrameTime = 0.0;
|
||||||
|
|
||||||
|
var creditDuration = episode.IsMovie ? _maximumMovieCreditsDuration : _maximumCreditsDuration;
|
||||||
|
|
||||||
// Continue bisecting the end of the file until the range that contains the first black
|
// Continue bisecting the end of the file until the range that contains the first black
|
||||||
// frame is smaller than the maximum permitted error.
|
// frame is smaller than the maximum permitted error.
|
||||||
while (start - end > _maximumError)
|
while (start - end > _maximumError)
|
||||||
@ -189,7 +208,7 @@ public class BlackFrameAnalyzer : IMediaFileAnalyzer
|
|||||||
|
|
||||||
if (TimeSpan.FromSeconds(upperLimit) - midpoint < _maximumError)
|
if (TimeSpan.FromSeconds(upperLimit) - midpoint < _maximumError)
|
||||||
{
|
{
|
||||||
upperLimit = Math.Min(upperLimit + (0.5 * searchDistance), _maximumCreditsDuration);
|
upperLimit = Math.Min(upperLimit + (0.5 * searchDistance), creditDuration);
|
||||||
|
|
||||||
// Reset start for a new search with the increased duration
|
// Reset start for a new search with the increased duration
|
||||||
start = TimeSpan.FromSeconds(upperLimit);
|
start = TimeSpan.FromSeconds(upperLimit);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@ -92,9 +91,10 @@ public class ChapterAnalyzer(ILogger<ChapterAnalyzer> logger) : IMediaFileAnalyz
|
|||||||
}
|
}
|
||||||
|
|
||||||
var config = Plugin.Instance?.Configuration ?? new PluginConfiguration();
|
var config = Plugin.Instance?.Configuration ?? new PluginConfiguration();
|
||||||
|
var creditDuration = episode.IsMovie ? config.MaximumMovieCreditsDuration : config.MaximumCreditsDuration;
|
||||||
var reversed = mode != AnalysisMode.Introduction;
|
var reversed = mode != AnalysisMode.Introduction;
|
||||||
var (minDuration, maxDuration) = reversed
|
var (minDuration, maxDuration) = reversed
|
||||||
? (config.MinimumCreditsDuration, config.MaximumCreditsDuration)
|
? (config.MinimumCreditsDuration, creditDuration)
|
||||||
: (config.MinimumIntroDuration, config.MaximumIntroDuration);
|
: (config.MinimumIntroDuration, config.MaximumIntroDuration);
|
||||||
|
|
||||||
// Check all chapters
|
// Check all chapters
|
||||||
|
@ -33,6 +33,11 @@ public class PluginConfiguration : BasePluginConfiguration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SelectAllLibraries { get; set; } = true;
|
public bool SelectAllLibraries { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether movies should be analyzed.
|
||||||
|
/// </summary>
|
||||||
|
public bool AnalyzeMovies { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the list of client to auto skip for.
|
/// Gets or sets the list of client to auto skip for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -107,7 +112,12 @@ public class PluginConfiguration : BasePluginConfiguration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the upper limit (in seconds) on the length of each episode's audio track that will be analyzed when searching for ending credits.
|
/// Gets or sets the upper limit (in seconds) on the length of each episode's audio track that will be analyzed when searching for ending credits.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaximumCreditsDuration { get; set; } = 300;
|
public int MaximumCreditsDuration { get; set; } = 450;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the upper limit (in seconds) on the length of a movie segment that will be analyzed when searching for ending credits.
|
||||||
|
/// </summary>
|
||||||
|
public int MaximumMovieCreditsDuration { get; set; } = 900;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the minimum percentage of a frame that must consist of black pixels before it is considered a black frame.
|
/// Gets or sets the minimum percentage of a frame that must consist of black pixels before it is considered a black frame.
|
||||||
|
@ -52,6 +52,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||||
|
<label class="emby-checkbox-label">
|
||||||
|
<input id="AnalyzeMovies" type="checkbox" is="emby-checkbox" />
|
||||||
|
<span>Analyze Movies</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="fieldDescription">If checked, movies will be included in analysis.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||||
<label class="emby-checkbox-label">
|
<label class="emby-checkbox-label">
|
||||||
<input id="AnalyzeSeasonZero" type="checkbox" is="emby-checkbox" />
|
<input id="AnalyzeSeasonZero" type="checkbox" is="emby-checkbox" />
|
||||||
@ -135,6 +144,13 @@
|
|||||||
|
|
||||||
Increasing either of these settings will cause episode analysis to take much longer.
|
Increasing either of these settings will cause episode analysis to take much longer.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="inputContainer" id="movieCreditsDuration">
|
||||||
|
<label class="inputLabel inputLabelUnfocused" for="MaximumMovieCreditsDuration"> Maximum movie credits duration (in seconds) </label>
|
||||||
|
<input id="MaximumMovieCreditsDuration" type="number" is="emby-input" min="1" />
|
||||||
|
<div class="fieldDescription">Segments longer than this duration will not be considered movie credits.</div>
|
||||||
|
<br />upda
|
||||||
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details id="edl">
|
<details id="edl">
|
||||||
@ -398,10 +414,12 @@
|
|||||||
<summary>Manage Timestamps & Fingerprints</summary>
|
<summary>Manage Timestamps & Fingerprints</summary>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<label class="inputLabel" for="troubleshooterShow">Select TV Series to manage</label>
|
<label class="inputLabel" for="troubleshooterShow">Select TV series / movie to manage</label>
|
||||||
<select is="emby-select" id="troubleshooterShow" class="emby-select-withcolor emby-select"></select>
|
<select is="emby-select" id="troubleshooterShow" class="emby-select-withcolor emby-select"></select>
|
||||||
<label class="inputLabel" for="troubleshooterSeason">Select Season to manage</label>
|
<div id="seasonSelection">
|
||||||
|
<label class="inputLabel" for="troubleshooterSeason">Select season to manage</label>
|
||||||
<select is="emby-select" id="troubleshooterSeason" class="emby-select-withcolor emby-select"></select>
|
<select is="emby-select" id="troubleshooterSeason" class="emby-select-withcolor emby-select"></select>
|
||||||
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<div id="ignorelistSection" style="display: none">
|
<div id="ignorelistSection" style="display: none">
|
||||||
@ -424,16 +442,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<button is="emby-button" id="saveIgnoreListSeries" class="raised button-submit block emby-button">Apply to series</button>
|
<button is="emby-button" id="saveIgnoreListSeries" class="raised button-submit block emby-button">Apply to series / movie</button>
|
||||||
<button is="emby-button" id="saveIgnoreListSeason" class="raised button-submit block emby-button" style="display: none">Apply to season</button>
|
<button is="emby-button" id="saveIgnoreListSeason" class="raised button-submit block emby-button" style="display: none">Apply to season</button>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
<div id="episodeSelection">
|
||||||
<label class="inputLabel" for="troubleshooterEpisode1">Select the first episode</label>
|
<label class="inputLabel" for="troubleshooterEpisode1">Select the first episode</label>
|
||||||
<select is="emby-select" id="troubleshooterEpisode1" class="emby-select-withcolor emby-select"></select>
|
<select is="emby-select" id="troubleshooterEpisode1" class="emby-select-withcolor emby-select"></select>
|
||||||
<label class="inputLabel" for="troubleshooterEpisode1">Select the second episode</label>
|
<label class="inputLabel" for="troubleshooterEpisode1">Select the second episode</label>
|
||||||
<select is="emby-select" id="troubleshooterEpisode2" class="emby-select-withcolor emby-select"></select>
|
<select is="emby-select" id="troubleshooterEpisode2" class="emby-select-withcolor emby-select"></select>
|
||||||
<br />
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="timestampEditor" style="display: none">
|
<div id="timestampEditor" style="display: none">
|
||||||
<h3 style="margin: 0">Introduction timestamp editor</h3>
|
<h3 style="margin: 0">Introduction timestamp editor</h3>
|
||||||
@ -465,6 +485,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
<div id="rightEpisodeEditor">
|
||||||
<h4 style="margin: 0" id="editRightEpisodeTitle"></h4>
|
<h4 style="margin: 0" id="editRightEpisodeTitle"></h4>
|
||||||
<br />
|
<br />
|
||||||
<div class="inlineForm">
|
<div class="inlineForm">
|
||||||
@ -492,6 +513,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
</div>
|
||||||
<button is="emby-button" id="btnUpdateTimestamps" class="raised button-submit block emby-button" type="button">Update timestamps</button>
|
<button is="emby-button" id="btnUpdateTimestamps" class="raised button-submit block emby-button" type="button">Update timestamps</button>
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
@ -502,6 +524,8 @@
|
|||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="fingerprintVisualizer">
|
||||||
|
|
||||||
<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 />
|
||||||
@ -538,15 +562,18 @@
|
|||||||
<span>Shift amount:</span>
|
<span>Shift amount:</span>
|
||||||
<input type="number" min="-3000" max="3000" value="0" id="offset" />
|
<input type="number" min="-3000" max="3000" value="0" id="offset" />
|
||||||
<br />
|
<br />
|
||||||
<span id="suggestedShifts">Suggested shifts:</span>
|
<span id="suggestedShifts">
|
||||||
|
<span>Suggested shifts:</span>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
</span>
|
||||||
|
|
||||||
<canvas id="troubleshooter" style="display: none"></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>
|
||||||
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
@ -555,8 +582,16 @@
|
|||||||
|
|
||||||
<input type="checkbox" id="eraseSeasonCacheCheckbox" style="margin-left: 10px" />
|
<input type="checkbox" id="eraseSeasonCacheCheckbox" style="margin-left: 10px" />
|
||||||
<label for="eraseSeasonCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
<label for="eraseSeasonCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
||||||
</div>
|
|
||||||
<br />
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="eraseMovieContainer" style="display: none">
|
||||||
|
<button is="emby-button" id="btnEraseMovieTimestamps" class="button-submit emby-button" type="button">Erase all timestamps for this movie</button>
|
||||||
|
|
||||||
|
<input type="checkbox" id="eraseMovieCacheCheckbox" style="margin-left: 10px" />
|
||||||
|
<label for="eraseMovieCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
<button is="emby-button" class="button-submit emby-button" id="btnEraseIntroTimestamps">Erase all introduction timestamps (globally)</button>
|
<button is="emby-button" class="button-submit emby-button" id="btnEraseIntroTimestamps">Erase all introduction timestamps (globally)</button>
|
||||||
<br />
|
<br />
|
||||||
@ -616,6 +651,7 @@
|
|||||||
"MaximumIntroDuration",
|
"MaximumIntroDuration",
|
||||||
"MinimumCreditsDuration",
|
"MinimumCreditsDuration",
|
||||||
"MaximumCreditsDuration",
|
"MaximumCreditsDuration",
|
||||||
|
"MaximumMovieCreditsDuration",
|
||||||
"EdlAction",
|
"EdlAction",
|
||||||
"ProcessPriority",
|
"ProcessPriority",
|
||||||
"ProcessThreads",
|
"ProcessThreads",
|
||||||
@ -635,7 +671,7 @@
|
|||||||
"AutoSkipCreditsNotificationText",
|
"AutoSkipCreditsNotificationText",
|
||||||
];
|
];
|
||||||
|
|
||||||
var booleanConfigurationFields = ["AutoDetectIntros", "AutoDetectCredits", "AnalyzeSeasonZero", "SelectAllLibraries", "RegenerateEdlFiles", "CacheFingerprints", "AutoSkip", "AutoSkipCredits", "SkipFirstEpisode", "PersistSkipButton", "SkipButtonVisible"];
|
var booleanConfigurationFields = ["AutoDetectIntros", "AutoDetectCredits", "AnalyzeMovies", "AnalyzeSeasonZero", "SelectAllLibraries", "RegenerateEdlFiles", "CacheFingerprints", "AutoSkip", "AutoSkipCredits", "SkipFirstEpisode", "PersistSkipButton", "SkipButtonVisible"];
|
||||||
|
|
||||||
// visualizer elements
|
// visualizer elements
|
||||||
var ignorelistSection = document.querySelector("div#ignorelistSection");
|
var ignorelistSection = document.querySelector("div#ignorelistSection");
|
||||||
@ -645,20 +681,27 @@
|
|||||||
var saveIgnoreListSeriesButton = ignorelistSection.querySelector("button#saveIgnoreListSeries");
|
var saveIgnoreListSeriesButton = ignorelistSection.querySelector("button#saveIgnoreListSeries");
|
||||||
var canvas = document.querySelector("canvas#troubleshooter");
|
var canvas = document.querySelector("canvas#troubleshooter");
|
||||||
var selectShow = document.querySelector("select#troubleshooterShow");
|
var selectShow = document.querySelector("select#troubleshooterShow");
|
||||||
|
var seasonSelection = document.getElementById("seasonSelection");
|
||||||
var selectSeason = document.querySelector("select#troubleshooterSeason");
|
var selectSeason = document.querySelector("select#troubleshooterSeason");
|
||||||
|
var episodeSelection = document.getElementById("episodeSelection");
|
||||||
var selectEpisode1 = document.querySelector("select#troubleshooterEpisode1");
|
var selectEpisode1 = document.querySelector("select#troubleshooterEpisode1");
|
||||||
var selectEpisode2 = document.querySelector("select#troubleshooterEpisode2");
|
var selectEpisode2 = document.querySelector("select#troubleshooterEpisode2");
|
||||||
var txtOffset = document.querySelector("input#offset");
|
var txtOffset = document.querySelector("input#offset");
|
||||||
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 eraseSeasonContainer = document.getElementById("eraseSeasonContainer");
|
var eraseSeasonContainer = document.getElementById("eraseSeasonContainer");
|
||||||
|
var btnMovieEraseTimestamps = document.querySelector("button#btnEraseMovieTimestamps");
|
||||||
|
var eraseMovieContainer = document.getElementById("eraseMovieContainer");
|
||||||
var timestampError = document.querySelector("textarea#timestampError");
|
var timestampError = document.querySelector("textarea#timestampError");
|
||||||
var timestampEditor = document.querySelector("#timestampEditor");
|
var timestampEditor = document.querySelector("#timestampEditor");
|
||||||
|
var rightEpisodeEditor = document.getElementById("rightEpisodeEditor");
|
||||||
var btnUpdateTimestamps = document.querySelector("button#btnUpdateTimestamps");
|
var btnUpdateTimestamps = document.querySelector("button#btnUpdateTimestamps");
|
||||||
var timeContainer = document.querySelector("span#timestampContainer");
|
var timeContainer = document.querySelector("span#timestampContainer");
|
||||||
|
var fingerprintVisualizer = document.getElementById("fingerprintVisualizer");
|
||||||
|
|
||||||
var windowHashInterval = 0;
|
var windowHashInterval = 0;
|
||||||
|
|
||||||
|
var analyzeMovies = document.getElementById("AnalyzeMovies");
|
||||||
var autoSkip = document.querySelector("input#AutoSkip");
|
var autoSkip = document.querySelector("input#AutoSkip");
|
||||||
var skipButtonVisible = document.getElementById("SkipButtonVisible");
|
var skipButtonVisible = document.getElementById("SkipButtonVisible");
|
||||||
var skipButtonVisibleLabel = document.getElementById("SkipButtonVisibleLabel");
|
var skipButtonVisibleLabel = document.getElementById("SkipButtonVisibleLabel");
|
||||||
@ -669,6 +712,7 @@
|
|||||||
var secondsOfIntroStartToPlay = document.querySelector("div#divSecondsOfIntroStartToPlay");
|
var secondsOfIntroStartToPlay = document.querySelector("div#divSecondsOfIntroStartToPlay");
|
||||||
var autoSkipClientList = document.getElementById("AutoSkipClientList");
|
var autoSkipClientList = document.getElementById("AutoSkipClientList");
|
||||||
var secondsOfCreditsStartToPlay = document.querySelector("div#divSecondsOfCreditsStartToPlay");
|
var secondsOfCreditsStartToPlay = document.querySelector("div#divSecondsOfCreditsStartToPlay");
|
||||||
|
var movieCreditsDuration = document.getElementById("movieCreditsDuration");
|
||||||
var autoSkipNotificationText = document.querySelector("div#divAutoSkipNotificationText");
|
var autoSkipNotificationText = document.querySelector("div#divAutoSkipNotificationText");
|
||||||
var autoSkipCredits = document.querySelector("input#AutoSkipCredits");
|
var autoSkipCredits = document.querySelector("input#AutoSkipCredits");
|
||||||
var autoSkipCreditsNotificationText = document.querySelector("div#divAutoSkipCreditsNotificationText");
|
var autoSkipCreditsNotificationText = document.querySelector("div#divAutoSkipCreditsNotificationText");
|
||||||
@ -780,7 +824,7 @@
|
|||||||
|
|
||||||
async function populateLibraries() {
|
async function populateLibraries() {
|
||||||
const response = await getJson("Library/VirtualFolders");
|
const response = await getJson("Library/VirtualFolders");
|
||||||
const tvLibraries = response.filter((item) => item.CollectionType === undefined || item.CollectionType === "tvshows");
|
const tvLibraries = response.filter((item) => item.CollectionType === undefined || item.CollectionType === "tvshows" || item.CollectionType === "movies");
|
||||||
const libraryNames = tvLibraries.map((lib) => lib.Name || "Unnamed Library");
|
const libraryNames = tvLibraries.map((lib) => lib.Name || "Unnamed Library");
|
||||||
generateCheckboxList(libraryNames, "libraryCheckboxes", "SelectedLibraries");
|
generateCheckboxList(libraryNames, "libraryCheckboxes", "SelectedLibraries");
|
||||||
}
|
}
|
||||||
@ -802,6 +846,16 @@
|
|||||||
|
|
||||||
persistSkip.addEventListener("change", persistSkipChanged);
|
persistSkip.addEventListener("change", persistSkipChanged);
|
||||||
|
|
||||||
|
async function analyzeMoviesChanged() {
|
||||||
|
if (analyzeMovies.checked) {
|
||||||
|
movieCreditsDuration.style.display = "unset";
|
||||||
|
} else {
|
||||||
|
movieCreditsDuration.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeMovies.addEventListener("change", analyzeMoviesChanged);
|
||||||
|
|
||||||
// when the fingerprint visualizer opens, populate show names
|
// when the fingerprint visualizer opens, populate show names
|
||||||
async function visualizerToggled() {
|
async function visualizerToggled() {
|
||||||
if (!visualizer.open) {
|
if (!visualizer.open) {
|
||||||
@ -893,8 +947,11 @@
|
|||||||
|
|
||||||
// show changed, populate seasons
|
// show changed, populate seasons
|
||||||
async function showChanged() {
|
async function showChanged() {
|
||||||
|
seasonSelection.style.display = "unset";
|
||||||
clearSelect(selectSeason);
|
clearSelect(selectSeason);
|
||||||
eraseSeasonContainer.style.display = "none";
|
eraseSeasonContainer.style.display = "none";
|
||||||
|
eraseMovieContainer.style.display = "none";
|
||||||
|
episodeSelection.style.display = "unset";
|
||||||
clearSelect(selectEpisode1);
|
clearSelect(selectEpisode1);
|
||||||
clearSelect(selectEpisode2);
|
clearSelect(selectEpisode2);
|
||||||
|
|
||||||
@ -907,6 +964,11 @@
|
|||||||
saveIgnoreListSeasonButton.style.display = "none";
|
saveIgnoreListSeasonButton.style.display = "none";
|
||||||
Dashboard.hideLoadingMsg();
|
Dashboard.hideLoadingMsg();
|
||||||
|
|
||||||
|
if (shows[selectShow.value].IsMovie) {
|
||||||
|
movieLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// add all seasons from this show to the season select
|
// add all seasons from this show to the season select
|
||||||
for (const season in shows[selectShow.value].Seasons) {
|
for (const season in shows[selectShow.value].Seasons) {
|
||||||
addItem(selectSeason, "Season " + shows[selectShow.value].Seasons[season], season);
|
addItem(selectSeason, "Season " + shows[selectShow.value].Seasons[season], season);
|
||||||
@ -957,6 +1019,7 @@
|
|||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
timestampError.value = "";
|
timestampError.value = "";
|
||||||
|
fingerprintVisualizer.style.display = "unset";
|
||||||
canvas.style.display = "none";
|
canvas.style.display = "none";
|
||||||
|
|
||||||
lhs = await getJson("Intros/Episode/" + selectEpisode1.value + "/Chromaprint");
|
lhs = await getJson("Intros/Episode/" + selectEpisode1.value + "/Chromaprint");
|
||||||
@ -966,6 +1029,8 @@
|
|||||||
timestampError.value += "Error: " + selectEpisode1.value + " fingerprints missing!\n";
|
timestampError.value += "Error: " + selectEpisode1.value + " fingerprints missing!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rightEpisodeEditor.style.display = "unset";
|
||||||
|
|
||||||
rhs = await getJson("Intros/Episode/" + selectEpisode2.value + "/Chromaprint");
|
rhs = await getJson("Intros/Episode/" + selectEpisode2.value + "/Chromaprint");
|
||||||
if (rhs === undefined) {
|
if (rhs === undefined) {
|
||||||
timestampError.value += "Error: " + selectEpisode2.value + " fingerprints failed!";
|
timestampError.value += "Error: " + selectEpisode2.value + " fingerprints failed!";
|
||||||
@ -988,6 +1053,57 @@
|
|||||||
updateTimestampEditor();
|
updateTimestampEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function movieLoaded() {
|
||||||
|
|
||||||
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
|
seasonSelection.style.display = "none";
|
||||||
|
episodeSelection.style.display = "none";
|
||||||
|
eraseMovieContainer.style.display = "unset";
|
||||||
|
|
||||||
|
timestampError.value = "";
|
||||||
|
fingerprintVisualizer.style.display = "none";
|
||||||
|
|
||||||
|
lhs = await getJson("Intros/Episode/" + selectShow.value + "/Chromaprint");
|
||||||
|
if (lhs === undefined) {
|
||||||
|
timestampError.value += "Error: " + selectShow.value + " fingerprints failed!\n";
|
||||||
|
} else if (lhs === null) {
|
||||||
|
timestampError.value += "Error: " + selectShow.value + " fingerprints missing!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
rightEpisodeEditor.style.display = "none";
|
||||||
|
|
||||||
|
if (timestampError.value == "") {
|
||||||
|
timestampErrorDiv.style.display = "none";
|
||||||
|
} else {
|
||||||
|
timestampErrorDiv.style.display = "unset";
|
||||||
|
}
|
||||||
|
|
||||||
|
Dashboard.hideLoadingMsg();
|
||||||
|
|
||||||
|
txtOffset.value = "0";
|
||||||
|
|
||||||
|
// Try to get the timestamps of each intro, falling back a default value of zero if no intro was found
|
||||||
|
const leftEpisodeJson = await getJson("Episode/" + selectShow.value + "/Timestamps");
|
||||||
|
|
||||||
|
// Update the editor for the first and second episodes
|
||||||
|
timestampEditor.style.display = "unset";
|
||||||
|
document.querySelector("#editLeftEpisodeTitle").textContent = selectShow.value;
|
||||||
|
document.querySelector("#editLeftIntroEpisodeStartEdit").value = leftEpisodeJson.Introduction.Start;
|
||||||
|
document.querySelector("#editLeftIntroEpisodeEndEdit").value = leftEpisodeJson.Introduction.End;
|
||||||
|
document.querySelector("#editLeftCreditEpisodeStartEdit").value = leftEpisodeJson.Credits.Start;
|
||||||
|
document.querySelector("#editLeftCreditEpisodeEndEdit").value = leftEpisodeJson.Credits.End
|
||||||
|
|
||||||
|
// Update display inputs
|
||||||
|
const inputs = document.querySelectorAll('#timestampEditor input[type="number"]');
|
||||||
|
inputs.forEach((input) => {
|
||||||
|
const displayInput = document.getElementById(input.id.replace("Edit", "Display"));
|
||||||
|
displayInput.value = formatTime(parseFloat(input.value) || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
setupTimeInputs();
|
||||||
|
}
|
||||||
|
|
||||||
function setupTimeInputs() {
|
function setupTimeInputs() {
|
||||||
const timestampEditor = document.getElementById("timestampEditor");
|
const timestampEditor = document.getElementById("timestampEditor");
|
||||||
timestampEditor.querySelectorAll(".inputContainer").forEach((container) => {
|
timestampEditor.querySelectorAll(".inputContainer").forEach((container) => {
|
||||||
@ -1285,6 +1401,22 @@
|
|||||||
document.getElementById("eraseSeasonCacheCheckbox").checked = false;
|
document.getElementById("eraseSeasonCacheCheckbox").checked = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
btnMovieEraseTimestamps.addEventListener("click", () => {
|
||||||
|
Dashboard.confirm("Are you sure you want to erase all timestamps for this movie?", "Confirm timestamp erasure", (result) => {
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const show = selectShow.value;
|
||||||
|
const eraseCacheChecked = document.getElementById("eraseMovieCacheCheckbox").checked;
|
||||||
|
|
||||||
|
const url = "Intros/Show/" + encodeURIComponent(show);
|
||||||
|
fetchWithAuth(url + "?eraseCache=" + eraseCacheChecked, "DELETE", null);
|
||||||
|
|
||||||
|
Dashboard.alert("Erased timestamps for " + show);
|
||||||
|
document.getElementById("eraseMovieCacheCheckbox").checked = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
saveIgnoreListSeasonButton.addEventListener("click", () => {
|
saveIgnoreListSeasonButton.addEventListener("click", () => {
|
||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ using System.Net.Mime;
|
|||||||
using IntroSkipper.Configuration;
|
using IntroSkipper.Configuration;
|
||||||
using IntroSkipper.Data;
|
using IntroSkipper.Data;
|
||||||
using MediaBrowser.Common.Api;
|
using MediaBrowser.Common.Api;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -63,7 +64,7 @@ public class SkipIntroController : ControllerBase
|
|||||||
{
|
{
|
||||||
// only update existing episodes
|
// only update existing episodes
|
||||||
var rawItem = Plugin.Instance!.GetItem(id);
|
var rawItem = Plugin.Instance!.GetItem(id);
|
||||||
if (rawItem == null || rawItem is not Episode episode)
|
if (rawItem == null || rawItem is not Episode and not Movie)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
@ -99,7 +100,7 @@ public class SkipIntroController : ControllerBase
|
|||||||
{
|
{
|
||||||
// only get return content for episodes
|
// only get return content for episodes
|
||||||
var rawItem = Plugin.Instance!.GetItem(id);
|
var rawItem = Plugin.Instance!.GetItem(id);
|
||||||
if (rawItem == null || rawItem is not Episode episode)
|
if (rawItem == null || rawItem is not Episode and not Movie)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public class VisualizationController(ILogger<VisualizationController> logger) :
|
|||||||
var seasonNumber = first.SeasonNumber;
|
var seasonNumber = first.SeasonNumber;
|
||||||
if (!showSeasons.TryGetValue(seriesId, out var showInfo))
|
if (!showSeasons.TryGetValue(seriesId, out var showInfo))
|
||||||
{
|
{
|
||||||
showInfo = new ShowInfos { SeriesName = first.SeriesName, ProductionYear = GetProductionYear(seriesId), LibraryName = GetLibraryName(seriesId), Seasons = [] };
|
showInfo = new ShowInfos { SeriesName = first.SeriesName, ProductionYear = GetProductionYear(seriesId), LibraryName = GetLibraryName(seriesId), IsMovie = first.IsMovie, Seasons = [] };
|
||||||
showSeasons[seriesId] = showInfo;
|
showSeasons[seriesId] = showInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ public class VisualizationController(ILogger<VisualizationController> logger) :
|
|||||||
SeriesName = kvp.Value.SeriesName,
|
SeriesName = kvp.Value.SeriesName,
|
||||||
ProductionYear = kvp.Value.ProductionYear,
|
ProductionYear = kvp.Value.ProductionYear,
|
||||||
LibraryName = kvp.Value.LibraryName,
|
LibraryName = kvp.Value.LibraryName,
|
||||||
|
IsMovie = kvp.Value.IsMovie,
|
||||||
Seasons = kvp.Value.Seasons
|
Seasons = kvp.Value.Seasons
|
||||||
.OrderBy(s => s.Value)
|
.OrderBy(s => s.Value)
|
||||||
.ToDictionary(s => s.Key, s => s.Value)
|
.ToDictionary(s => s.Key, s => s.Value)
|
||||||
|
@ -47,6 +47,11 @@ public class QueuedEpisode
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAnime { get; set; }
|
public bool IsAnime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether an item is a movie.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the timestamp (in seconds) to stop searching for an introduction at.
|
/// Gets or sets the timestamp (in seconds) to stop searching for an introduction at.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -23,6 +23,11 @@ namespace IntroSkipper.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public required string LibraryName { get; set; }
|
public required string LibraryName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether its a movie.
|
||||||
|
/// </summary>
|
||||||
|
public required bool IsMovie { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Seasons of the show.
|
/// Gets the Seasons of the show.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -6,6 +6,7 @@ using IntroSkipper.Data;
|
|||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
using Jellyfin.Extensions;
|
using Jellyfin.Extensions;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -28,6 +29,7 @@ public class QueueManager(ILogger<QueueManager> logger, ILibraryManager libraryM
|
|||||||
private double _analysisPercent;
|
private double _analysisPercent;
|
||||||
private List<string> _selectedLibraries = [];
|
private List<string> _selectedLibraries = [];
|
||||||
private bool _selectAllLibraries;
|
private bool _selectAllLibraries;
|
||||||
|
private bool _analyzeMovies;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all media items on the server.
|
/// Gets all media items on the server.
|
||||||
@ -90,6 +92,8 @@ public class QueueManager(ILogger<QueueManager> logger, ILibraryManager libraryM
|
|||||||
|
|
||||||
_selectAllLibraries = config.SelectAllLibraries;
|
_selectAllLibraries = config.SelectAllLibraries;
|
||||||
|
|
||||||
|
_analyzeMovies = config.AnalyzeMovies;
|
||||||
|
|
||||||
if (!_selectAllLibraries)
|
if (!_selectAllLibraries)
|
||||||
{
|
{
|
||||||
// Get the list of library names which have been selected for analysis, ignoring whitespace and empty entries.
|
// Get the list of library names which have been selected for analysis, ignoring whitespace and empty entries.
|
||||||
@ -123,7 +127,7 @@ public class QueueManager(ILogger<QueueManager> logger, ILibraryManager libraryM
|
|||||||
// Order by series name, season, and then episode number so that status updates are logged in order
|
// Order by series name, season, and then episode number so that status updates are logged in order
|
||||||
ParentId = id,
|
ParentId = id,
|
||||||
OrderBy = [(ItemSortBy.SeriesSortName, SortOrder.Ascending), (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Ascending),],
|
OrderBy = [(ItemSortBy.SeriesSortName, SortOrder.Ascending), (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Ascending),],
|
||||||
IncludeItemTypes = [BaseItemKind.Episode],
|
IncludeItemTypes = [BaseItemKind.Episode, BaseItemKind.Movie],
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IsVirtualItem = false
|
IsVirtualItem = false
|
||||||
};
|
};
|
||||||
@ -141,14 +145,19 @@ public class QueueManager(ILogger<QueueManager> logger, ILibraryManager libraryM
|
|||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
if (item is not Episode episode)
|
if (item is Episode episode)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Item {Name} is not an episode", item.Name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QueueEpisode(episode);
|
QueueEpisode(episode);
|
||||||
}
|
}
|
||||||
|
else if (_analyzeMovies && item is Movie movie)
|
||||||
|
{
|
||||||
|
QueueMovie(movie);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Item {Name} is not an episode or movie", item.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogDebug("Queued {Count} episodes", items.Count);
|
_logger.LogDebug("Queued {Count} episodes", items.Count);
|
||||||
}
|
}
|
||||||
@ -197,8 +206,11 @@ public class QueueManager(ILogger<QueueManager> logger, ILibraryManager libraryM
|
|||||||
duration >= 5 * 60 ? duration * _analysisPercent : duration,
|
duration >= 5 * 60 ? duration * _analysisPercent : duration,
|
||||||
60 * pluginInstance.Configuration.AnalysisLengthLimit);
|
60 * pluginInstance.Configuration.AnalysisLengthLimit);
|
||||||
|
|
||||||
|
var maxCreditsDuration = Math.Min(
|
||||||
|
duration >= 5 * 60 ? duration * _analysisPercent : duration,
|
||||||
|
60 * pluginInstance.Configuration.MaximumCreditsDuration);
|
||||||
|
|
||||||
// Queue the episode for analysis
|
// Queue the episode for analysis
|
||||||
var maxCreditsDuration = pluginInstance.Configuration.MaximumCreditsDuration;
|
|
||||||
seasonEpisodes.Add(new QueuedEpisode
|
seasonEpisodes.Add(new QueuedEpisode
|
||||||
{
|
{
|
||||||
SeriesName = episode.SeriesName,
|
SeriesName = episode.SeriesName,
|
||||||
@ -216,6 +228,34 @@ public class QueueManager(ILogger<QueueManager> logger, ILibraryManager libraryM
|
|||||||
pluginInstance.TotalQueued++;
|
pluginInstance.TotalQueued++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void QueueMovie(Movie movie)
|
||||||
|
{
|
||||||
|
var pluginInstance = Plugin.Instance ?? throw new InvalidOperationException("Plugin instance was null");
|
||||||
|
if (string.IsNullOrEmpty(movie.Path))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Not queuing movie \"{Name}\" ({Id}) as no path was provided by Jellyfin",
|
||||||
|
movie.Name,
|
||||||
|
movie.Id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a new list for each Movie
|
||||||
|
_queuedEpisodes.TryAdd(movie.Id, []);
|
||||||
|
var duration = TimeSpan.FromTicks(movie.RunTimeTicks ?? 0).TotalSeconds;
|
||||||
|
_queuedEpisodes[movie.Id].Add(new QueuedEpisode
|
||||||
|
{
|
||||||
|
SeriesName = movie.Name,
|
||||||
|
SeriesId = movie.Id,
|
||||||
|
EpisodeId = movie.Id,
|
||||||
|
Name = movie.Name,
|
||||||
|
Path = movie.Path,
|
||||||
|
Duration = Convert.ToInt32(duration),
|
||||||
|
IsMovie = true
|
||||||
|
});
|
||||||
|
pluginInstance.TotalQueued++;
|
||||||
|
}
|
||||||
|
|
||||||
private Guid GetSeasonId(Episode episode)
|
private Guid GetSeasonId(Episode episode)
|
||||||
{
|
{
|
||||||
if (episode.ParentIndexNumber == 0 && episode.AiredSeasonNumber != 0) // In-season special
|
if (episode.ParentIndexNumber == 0 && episode.AiredSeasonNumber != 0) // In-season special
|
||||||
|
@ -122,11 +122,8 @@ public class BaseItemAnalyzerTask
|
|||||||
|
|
||||||
Interlocked.Add(ref totalProcessed, episodes.Count * _analysisModes.Count); // Update total Processed directly
|
Interlocked.Add(ref totalProcessed, episodes.Count * _analysisModes.Count); // Update total Processed directly
|
||||||
progress.Report(totalProcessed * 100 / totalQueued);
|
progress.Report(totalProcessed * 100 / totalQueued);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (_analysisModes.Count != requiredModes.Count)
|
||||||
if (_analysisModes.Count != requiredModes.Count)
|
|
||||||
{
|
{
|
||||||
Interlocked.Add(ref totalProcessed, episodes.Count);
|
Interlocked.Add(ref totalProcessed, episodes.Count);
|
||||||
progress.Report(totalProcessed * 100 / totalQueued); // Partial analysis some modes have already been analyzed
|
progress.Report(totalProcessed * 100 / totalQueued); // Partial analysis some modes have already been analyzed
|
||||||
@ -188,7 +185,7 @@ public class BaseItemAnalyzerTask
|
|||||||
|
|
||||||
// Only analyze specials (season 0) if the user has opted in.
|
// Only analyze specials (season 0) if the user has opted in.
|
||||||
var first = items[0];
|
var first = items[0];
|
||||||
if (first.SeasonNumber == 0 && !Plugin.Instance!.Configuration.AnalyzeSeasonZero)
|
if (!first.IsMovie && first.SeasonNumber == 0 && !Plugin.Instance!.Configuration.AnalyzeSeasonZero)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -211,7 +208,7 @@ public class BaseItemAnalyzerTask
|
|||||||
new ChapterAnalyzer(_loggerFactory.CreateLogger<ChapterAnalyzer>())
|
new ChapterAnalyzer(_loggerFactory.CreateLogger<ChapterAnalyzer>())
|
||||||
};
|
};
|
||||||
|
|
||||||
if (first.IsAnime && Plugin.Instance!.Configuration.WithChromaprint)
|
if (first.IsAnime && Plugin.Instance!.Configuration.WithChromaprint && !first.IsMovie)
|
||||||
{
|
{
|
||||||
analyzers.Add(new ChromaprintAnalyzer(_loggerFactory.CreateLogger<ChromaprintAnalyzer>()));
|
analyzers.Add(new ChromaprintAnalyzer(_loggerFactory.CreateLogger<ChromaprintAnalyzer>()));
|
||||||
}
|
}
|
||||||
@ -221,7 +218,7 @@ public class BaseItemAnalyzerTask
|
|||||||
analyzers.Add(new BlackFrameAnalyzer(_loggerFactory.CreateLogger<BlackFrameAnalyzer>()));
|
analyzers.Add(new BlackFrameAnalyzer(_loggerFactory.CreateLogger<BlackFrameAnalyzer>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!first.IsAnime && Plugin.Instance!.Configuration.WithChromaprint)
|
if (!first.IsAnime && Plugin.Instance!.Configuration.WithChromaprint && !first.IsMovie)
|
||||||
{
|
{
|
||||||
analyzers.Add(new ChromaprintAnalyzer(_loggerFactory.CreateLogger<ChromaprintAnalyzer>()));
|
analyzers.Add(new ChromaprintAnalyzer(_loggerFactory.CreateLogger<ChromaprintAnalyzer>()));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IntroSkipper.Data;
|
using IntroSkipper.Data;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IntroSkipper.Data;
|
using IntroSkipper.Data;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IntroSkipper.Data;
|
using IntroSkipper.Data;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user