AutoSkip: allow to adjust the intro/credit playback duration (#238)

Co-authored-by: rlauu <46294892+rlauu@users.noreply.github.com>
Co-authored-by: rlauuzo <46294892+rlauuzo@users.noreply.github.com>
Co-authored-by: CasuallyFilthy <adamsdeloach@yahoo.com>
This commit is contained in:
Kilian von Pflugk 2024-08-02 13:41:03 +00:00 committed by TwistedUmbrellaX
parent d351a6225e
commit 252e30cde0
5 changed files with 57 additions and 19 deletions

View File

@ -149,15 +149,16 @@ public class AutoSkip : IServerEntryPoint
} }
// Seek is unreliable if called at the very start of an episode. // Seek is unreliable if called at the very start of an episode.
var adjustedStart = Math.Max(5, intro.IntroStart); var adjustedStart = Math.Max(5, intro.IntroStart + Plugin.Instance.Configuration.SecondsOfIntroStartToPlay);
var adjustedEnd = intro.IntroEnd - Plugin.Instance.Configuration.RemainingSecondsOfIntro;
_logger.LogTrace( _logger.LogTrace(
"Playback position is {Position}, intro runs from {Start} to {End}", "Playback position is {Position}, intro runs from {Start} to {End}",
position, position,
adjustedStart, adjustedStart,
intro.IntroEnd); adjustedEnd);
if (position < adjustedStart || position > intro.IntroEnd) if (position < adjustedStart || position > adjustedEnd)
{ {
continue; continue;
} }
@ -180,8 +181,6 @@ public class AutoSkip : IServerEntryPoint
_logger.LogDebug("Sending seek command to {Session}", deviceId); _logger.LogDebug("Sending seek command to {Session}", deviceId);
var introEnd = (long)intro.IntroEnd - Plugin.Instance!.Configuration.SecondsOfIntroToPlay;
_sessionManager.SendPlaystateCommand( _sessionManager.SendPlaystateCommand(
session.Id, session.Id,
session.Id, session.Id,
@ -189,7 +188,7 @@ public class AutoSkip : IServerEntryPoint
{ {
Command = PlaystateCommand.Seek, Command = PlaystateCommand.Seek,
ControllingUserId = session.UserId.ToString("N"), ControllingUserId = session.UserId.ToString("N"),
SeekPositionTicks = introEnd * TimeSpan.TicksPerSecond, SeekPositionTicks = (long)adjustedEnd * TimeSpan.TicksPerSecond,
}, },
CancellationToken.None); CancellationToken.None);

View File

@ -142,16 +142,17 @@ public class AutoSkipCredits : IServerEntryPoint
continue; continue;
} }
// Seek is unreliable if called at the very start of an episode. // Seek is unreliable if called at the very end of an episode.
var adjustedStart = Math.Max(5, credit.IntroStart); var adjustedStart = credit.IntroStart + Plugin.Instance.Configuration.SecondsOfCreditsStartToPlay;
var adjustedEnd = credit.IntroEnd - Plugin.Instance.Configuration.RemainingSecondsOfIntro;
_logger.LogTrace( _logger.LogTrace(
"Playback position is {Position}, credits run from {Start} to {End}", "Playback position is {Position}, credits run from {Start} to {End}",
position, position,
adjustedStart, adjustedStart,
credit.IntroEnd); adjustedEnd);
if (position < adjustedStart || position > credit.IntroEnd) if (position < adjustedStart || position > adjustedEnd)
{ {
continue; continue;
} }
@ -174,8 +175,6 @@ public class AutoSkipCredits : IServerEntryPoint
_logger.LogDebug("Sending seek command to {Session}", deviceId); _logger.LogDebug("Sending seek command to {Session}", deviceId);
var creditEnd = (long)credit.IntroEnd;
_sessionManager.SendPlaystateCommand( _sessionManager.SendPlaystateCommand(
session.Id, session.Id,
session.Id, session.Id,
@ -183,7 +182,7 @@ public class AutoSkipCredits : IServerEntryPoint
{ {
Command = PlaystateCommand.Seek, Command = PlaystateCommand.Seek,
ControllingUserId = session.UserId.ToString("N"), ControllingUserId = session.UserId.ToString("N"),
SeekPositionTicks = creditEnd * TimeSpan.TicksPerSecond, SeekPositionTicks = (long)adjustedEnd * TimeSpan.TicksPerSecond,
}, },
CancellationToken.None); CancellationToken.None);

View File

@ -161,7 +161,17 @@ public class PluginConfiguration : BasePluginConfiguration
/// <summary> /// <summary>
/// Gets or sets the amount of intro to play (in seconds). /// Gets or sets the amount of intro to play (in seconds).
/// </summary> /// </summary>
public int SecondsOfIntroToPlay { get; set; } = 2; public int RemainingSecondsOfIntro { get; set; } = 2;
/// <summary>
/// Gets or sets the amount of intro at start to play (in seconds).
/// </summary>
public int SecondsOfIntroStartToPlay { get; set; } = 0;
/// <summary>
/// Gets or sets the amount of credit at start to play (in seconds).
/// </summary>
public int SecondsOfCreditsStartToPlay { get; set; } = 0;
// ===== Internal algorithm settings ===== // ===== Internal algorithm settings =====

View File

@ -365,6 +365,17 @@
<br /> <br />
</div> </div>
<div id="divSecondsOfIntroStartToPlay" class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="SecondsOfIntroStartToPlay">
Intro playback duration (in seconds)
</label>
<input id="SecondsOfIntroStartToPlay" type="number" is="emby-input" min="0" />
<div class="fieldDescription">
Seconds of introduction start that should be played. Defaults to 0.
</div>
<br />
</div>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label class="emby-checkbox-label"> <label class="emby-checkbox-label">
<input id="AutoSkipCredits" type="checkbox" is="emby-checkbox" /> <input id="AutoSkipCredits" type="checkbox" is="emby-checkbox" />
@ -378,6 +389,17 @@
</div> </div>
</div> </div>
<div id="divSecondsOfCreditsStartToPlay" class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="SecondsOfCreditsStartToPlay">
Credit playback duration (in seconds)
</label>
<input id="SecondsOfCreditsStartToPlay" type="number" is="emby-input" min="0" />
<div class="fieldDescription">
Seconds of credits start that should be played. Defaults to 0.
</div>
<br />
</div>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label class="emby-checkbox-label"> <label class="emby-checkbox-label">
<input id="SkipButtonVisible" type="checkbox" is="emby-checkbox" /> <input id="SkipButtonVisible" type="checkbox" is="emby-checkbox" />
@ -427,10 +449,10 @@
<br /> <br />
<div class="inputContainer"> <div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="SecondsOfIntroToPlay"> <label class="inputLabel inputLabelUnfocused" for="RemainingSecondsOfIntro">
Intro playback duration (in seconds) Intro playback duration (in seconds)
</label> </label>
<input id="SecondsOfIntroToPlay" type="number" is="emby-input" min="0" /> <input id="RemainingSecondsOfIntro" type="number" is="emby-input" min="0" />
<div class="fieldDescription"> <div class="fieldDescription">
Seconds of introduction ending that should be played. Defaults to 2. Seconds of introduction ending that should be played. Defaults to 2.
</div> </div>
@ -648,7 +670,9 @@
// playback // playback
"ShowPromptAdjustment", "ShowPromptAdjustment",
"HidePromptAdjustment", "HidePromptAdjustment",
"SecondsOfIntroToPlay", "RemainingSecondsOfIntro",
"SecondsOfIntroStartToPlay",
"SecondsOfCreditsStartToPlay",
// internals // internals
"SilenceDetectionMaximumNoise", "SilenceDetectionMaximumNoise",
"SilenceDetectionMinimumDuration", "SilenceDetectionMinimumDuration",
@ -691,6 +715,8 @@
var autoSkip = document.querySelector("input#AutoSkip"); var autoSkip = document.querySelector("input#AutoSkip");
var skipFirstEpisode = document.querySelector("div#divSkipFirstEpisode"); var skipFirstEpisode = document.querySelector("div#divSkipFirstEpisode");
var secondsOfIntroStartToPlay = document.querySelector("div#divSecondsOfIntroStartToPlay");
var secondsOfCreditsStartToPlay = document.querySelector("div#divSecondsOfCreditsStartToPlay");
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");
@ -699,9 +725,11 @@
if (autoSkip.checked) { if (autoSkip.checked) {
skipFirstEpisode.style.display = 'unset'; skipFirstEpisode.style.display = 'unset';
autoSkipNotificationText.style.display = 'unset'; autoSkipNotificationText.style.display = 'unset';
secondsOfIntroStartToPlay.style.display = 'unset';
} else { } else {
skipFirstEpisode.style.display = 'none'; skipFirstEpisode.style.display = 'none';
autoSkipNotificationText.style.display = 'none'; autoSkipNotificationText.style.display = 'none';
secondsOfIntroStartToPlay.style.display = 'none';
} }
} }
@ -710,8 +738,10 @@
async function autoSkipCreditsChanged() { async function autoSkipCreditsChanged() {
if (autoSkipCredits.checked) { if (autoSkipCredits.checked) {
autoSkipCreditsNotificationText.style.display = 'unset'; autoSkipCreditsNotificationText.style.display = 'unset';
secondsOfCreditsStartToPlay.style.display = 'unset';
} else { } else {
autoSkipCreditsNotificationText.style.display = 'none'; autoSkipCreditsNotificationText.style.display = 'none';
secondsOfCreditsStartToPlay.style.display = 'none';
} }
} }

View File

@ -86,8 +86,8 @@ public class SkipIntroController : ControllerBase
// Operate on a copy to avoid mutating the original Intro object stored in the dictionary. // Operate on a copy to avoid mutating the original Intro object stored in the dictionary.
var segment = new Intro(timestamp); var segment = new Intro(timestamp);
var config = Plugin.Instance!.Configuration; var config = Plugin.Instance.Configuration;
segment.IntroEnd -= config.SecondsOfIntroToPlay; segment.IntroEnd -= config.RemainingSecondsOfIntro;
if (config.PersistSkipButton) if (config.PersistSkipButton)
{ {
segment.ShowSkipPromptAt = segment.IntroStart; segment.ShowSkipPromptAt = segment.IntroStart;