Allow the intro skip button to be confirmed with the Enter key (#189)
* allow the intro skip button to be confirmed with the Enter key tested with LG webOS * add some comments * Update inject.js (#173) * Update inject.js * Update inject.js --------- Co-authored-by: Kilian von Pflugk <github@jumoog.io> Co-authored-by: rlauu <46294892+rlauu@users.noreply.github.com>
This commit is contained in:
parent
87272075ed
commit
50529c4a0b
@ -1,4 +1,5 @@
|
|||||||
let introSkipper = {
|
let introSkipper = {
|
||||||
|
allowEnter: true,
|
||||||
skipSegments: {},
|
skipSegments: {},
|
||||||
videoPlayer: {},
|
videoPlayer: {},
|
||||||
// .bind() is used here to prevent illegal invocation errors
|
// .bind() is used here to prevent illegal invocation errors
|
||||||
@ -60,6 +61,7 @@ introSkipper.d = function (msg) {
|
|||||||
if (introSkipper.videoPlayer != null) {
|
if (introSkipper.videoPlayer != null) {
|
||||||
introSkipper.d("Hooking video timeupdate");
|
introSkipper.d("Hooking video timeupdate");
|
||||||
introSkipper.videoPlayer.addEventListener("timeupdate", introSkipper.videoPositionChanged);
|
introSkipper.videoPlayer.addEventListener("timeupdate", introSkipper.videoPositionChanged);
|
||||||
|
document.body.addEventListener('keydown', introSkipper.eventHandler, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -169,13 +171,28 @@ introSkipper.getCurrentSegment = function (position) {
|
|||||||
}
|
}
|
||||||
return { "SegmentType": "None" };
|
return { "SegmentType": "None" };
|
||||||
}
|
}
|
||||||
|
introSkipper.overrideBlur = function(embyButton) {
|
||||||
|
if (!embyButton.originalBlur) {
|
||||||
|
embyButton.originalBlur = embyButton.blur;
|
||||||
|
}
|
||||||
|
embyButton.blur = function () {
|
||||||
|
if (!introSkipper.osdVisible() || !embyButton.contains(document.activeElement)) {
|
||||||
|
embyButton.originalBlur.call(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
introSkipper.restoreBlur = function(embyButton) {
|
||||||
|
if (embyButton.originalBlur) {
|
||||||
|
embyButton.blur = embyButton.originalBlur;
|
||||||
|
delete embyButton.originalBlur;
|
||||||
|
}
|
||||||
|
};
|
||||||
/** Playback position changed, check if the skip button needs to be displayed. */
|
/** Playback position changed, check if the skip button needs to be displayed. */
|
||||||
introSkipper.videoPositionChanged = function () {
|
introSkipper.videoPositionChanged = function () {
|
||||||
const skipButton = document.querySelector("#skipIntro");
|
const skipButton = document.querySelector("#skipIntro");
|
||||||
if (!skipButton) {
|
if (introSkipper.videoPlayer.currentTime === 0 || !skipButton || !introSkipper.allowEnter) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const embyButton = skipButton.querySelector(".emby-button");
|
const embyButton = skipButton.querySelector(".emby-button");
|
||||||
|
const tvLayout = document.documentElement.classList.contains("layout-tv");
|
||||||
const segment = introSkipper.getCurrentSegment(introSkipper.videoPlayer.currentTime);
|
const segment = introSkipper.getCurrentSegment(introSkipper.videoPlayer.currentTime);
|
||||||
switch (segment.SegmentType) {
|
switch (segment.SegmentType) {
|
||||||
case "None":
|
case "None":
|
||||||
@ -184,6 +201,10 @@ introSkipper.videoPositionChanged = function () {
|
|||||||
embyButton.style.opacity = '0';
|
embyButton.style.opacity = '0';
|
||||||
embyButton.addEventListener("transitionend", () => {
|
embyButton.addEventListener("transitionend", () => {
|
||||||
skipButton.classList.add("hide");
|
skipButton.classList.add("hide");
|
||||||
|
if (tvLayout) {
|
||||||
|
introSkipper.restoreBlur(embyButton);
|
||||||
|
embyButton.blur();
|
||||||
|
}
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
return;
|
return;
|
||||||
case "Introduction":
|
case "Introduction":
|
||||||
@ -196,22 +217,44 @@ introSkipper.videoPositionChanged = function () {
|
|||||||
if (!skipButton.classList.contains("hide")) return;
|
if (!skipButton.classList.contains("hide")) return;
|
||||||
|
|
||||||
skipButton.classList.remove("hide");
|
skipButton.classList.remove("hide");
|
||||||
embyButton.offsetWidth; // Force reflow
|
embyButton.style.opacity = '1';
|
||||||
requestAnimationFrame(() => {
|
|
||||||
embyButton.style.opacity = '1';
|
if (tvLayout) {
|
||||||
});
|
introSkipper.overrideBlur(embyButton);
|
||||||
|
embyButton.focus({ focusVisible: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
introSkipper.throttle = function (func, limit) {
|
||||||
|
let inThrottle;
|
||||||
|
return function(...args) {
|
||||||
|
const context = this;
|
||||||
|
if (!inThrottle) {
|
||||||
|
func.apply(context, args);
|
||||||
|
inThrottle = true;
|
||||||
|
setTimeout(() => inThrottle = false, limit);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
/** Seeks to the end of the intro. */
|
/** Seeks to the end of the intro. */
|
||||||
introSkipper.doSkip = function (e) {
|
introSkipper.doSkip = introSkipper.throttle(function (e) {
|
||||||
introSkipper.d("Skipping intro");
|
introSkipper.d("Skipping intro");
|
||||||
introSkipper.d(introSkipper.skipSegments);
|
introSkipper.d(introSkipper.skipSegments);
|
||||||
const segment = introSkipper.getCurrentSegment(introSkipper.videoPlayer.currentTime);
|
const segment = introSkipper.getCurrentSegment(introSkipper.videoPlayer.currentTime);
|
||||||
if (segment["SegmentType"] === "None") {
|
if (segment.SegmentType === "None") {
|
||||||
console.warn("[intro skipper] doSkip() called without an active segment");
|
console.warn("[intro skipper] doSkip() called without an active segment");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
introSkipper.videoPlayer.currentTime = segment["IntroEnd"];
|
// Disable keydown events
|
||||||
}
|
introSkipper.allowEnter = false;
|
||||||
|
introSkipper.videoPlayer.currentTime = segment.IntroEnd;
|
||||||
|
// Listen for the seeked event to re-enable keydown events
|
||||||
|
const onSeeked = async () => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50)); // Wait 50ms
|
||||||
|
introSkipper.allowEnter = true;
|
||||||
|
introSkipper.videoPlayer.removeEventListener('seeked', onSeeked);
|
||||||
|
};
|
||||||
|
introSkipper.videoPlayer.addEventListener('seeked', onSeeked);
|
||||||
|
}, 3000);
|
||||||
/** Tests if an element with the provided selector exists. */
|
/** Tests if an element with the provided selector exists. */
|
||||||
introSkipper.testElement = function (selector) { return document.querySelector(selector); }
|
introSkipper.testElement = function (selector) { return document.querySelector(selector); }
|
||||||
/** Make an authenticated fetch to the Jellyfin server and parse the response body as JSON. */
|
/** Make an authenticated fetch to the Jellyfin server and parse the response body as JSON. */
|
||||||
@ -222,4 +265,25 @@ introSkipper.secureFetch = async function (url) {
|
|||||||
if (res.status !== 200) { throw new Error(`Expected status 200 from ${url}, but got ${res.status}`); }
|
if (res.status !== 200) { throw new Error(`Expected status 200 from ${url}, but got ${res.status}`); }
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
/** Handle keydown events. */
|
||||||
|
introSkipper.eventHandler = function (e) {
|
||||||
|
const skipButton = document.querySelector("#skipIntro");
|
||||||
|
if (!skipButton || skipButton.classList.contains("hide")) return;
|
||||||
|
// Ignore all keydown events
|
||||||
|
if (!introSkipper.allowEnter) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.key !== "Enter") return;
|
||||||
|
const embyButton = skipButton.querySelector(".emby-button");
|
||||||
|
if (document.documentElement.classList.contains("layout-tv") && embyButton.contains(document.activeElement)) {
|
||||||
|
e.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (document.documentElement.classList.contains("layout-desktop")) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
introSkipper.doSkip();
|
||||||
|
}
|
||||||
|
}
|
||||||
introSkipper.setup();
|
introSkipper.setup();
|
||||||
|
@ -92,14 +92,14 @@ public class SkipIntroController : ControllerBase
|
|||||||
if (config.PersistSkipButton)
|
if (config.PersistSkipButton)
|
||||||
{
|
{
|
||||||
segment.ShowSkipPromptAt = segment.IntroStart;
|
segment.ShowSkipPromptAt = segment.IntroStart;
|
||||||
segment.HideSkipPromptAt = segment.IntroEnd - 1;
|
segment.HideSkipPromptAt = segment.IntroEnd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
segment.ShowSkipPromptAt = Math.Max(0, segment.IntroStart - config.ShowPromptAdjustment);
|
segment.ShowSkipPromptAt = Math.Max(0, segment.IntroStart - config.ShowPromptAdjustment);
|
||||||
segment.HideSkipPromptAt = Math.Min(
|
segment.HideSkipPromptAt = Math.Min(
|
||||||
segment.IntroStart + config.HidePromptAdjustment,
|
segment.IntroStart + config.HidePromptAdjustment,
|
||||||
segment.IntroEnd - 1);
|
segment.IntroEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return segment;
|
return segment;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user