diff --git a/Jellyfin.Plugin.MediaBarEnhanced/Jellyfin.Plugin.MediaBarEnhanced.csproj b/Jellyfin.Plugin.MediaBarEnhanced/Jellyfin.Plugin.MediaBarEnhanced.csproj
index 8ff4a42..6aa07ee 100644
--- a/Jellyfin.Plugin.MediaBarEnhanced/Jellyfin.Plugin.MediaBarEnhanced.csproj
+++ b/Jellyfin.Plugin.MediaBarEnhanced/Jellyfin.Plugin.MediaBarEnhanced.csproj
@@ -12,7 +12,7 @@
Jellyfin Media Bar Enhanced Plugin
CodeDevMLH
- 1.4.0.12
+ 1.5.0.0
https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced
diff --git a/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js b/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js
index b3f8410..310aa30 100644
--- a/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js
+++ b/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js
@@ -1,5 +1,5 @@
/*
- * Jellyfin Slideshow by M0RPH3US v3.0.9
+ * Jellyfin Slideshow by M0RPH3US v4.0.1
* Modified by CodeDevMLH v1.1.0.0
*
* New features:
@@ -81,6 +81,7 @@ const STATE = {
sponsorBlockInterval: null,
isMuted: CONFIG.startMuted,
customTrailerUrls: {},
+ ytPromise: null,
},
};
@@ -582,23 +583,25 @@ const SlideUtils = {
* @returns {Promise}
*/
loadYouTubeIframeAPI() {
- return new Promise((resolve) => {
+ if (STATE.slideshow.ytPromise) return STATE.slideshow.ytPromise;
+
+ STATE.slideshow.ytPromise = new Promise((resolve) => {
if (window.YT && window.YT.Player) {
- resolve();
+ resolve(window.YT);
return;
}
- const tag = document.createElement('script');
- tag.src = "https://www.youtube.com/iframe_api";
- const firstScriptTag = document.getElementsByTagName('script')[0];
- firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
-
- const previousOnYouTubeIframeAPIReady = window.onYouTubeIframeAPIReady;
- window.onYouTubeIframeAPIReady = () => {
- if (previousOnYouTubeIframeAPIReady) previousOnYouTubeIframeAPIReady();
- resolve();
- };
+ window.onYouTubeIframeAPIReady = () => resolve(window.YT);
+
+ if (!document.querySelector('script[src*="youtube.com/iframe_api"]')) {
+ const tag = document.createElement('script');
+ tag.src = "https://www.youtube.com/iframe_api";
+ const firstScriptTag = document.getElementsByTagName('script')[0];
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+ }
});
+
+ return STATE.slideshow.ytPromise;
},
/**
@@ -3109,6 +3112,84 @@ const MediaBarEnhancedSettingsManager = {
}
};
+/**
+ * Initialize page visibility handling to pause when tab is inactive
+ */
+const initPageVisibilityHandler = () => {
+ let wasVideoPlayingBeforeHide = false;
+
+ document.addEventListener("visibilitychange", () => {
+ if (document.hidden) {
+ console.log("Tab inactive - pausing slideshow and videos");
+ wasVideoPlayingBeforeHide = STATE.slideshow.isVideoPlaying;
+
+ if (STATE.slideshow.slideInterval) {
+ STATE.slideshow.slideInterval.stop();
+ }
+
+ // Pause active video if playing
+ const currentItemId = STATE.slideshow.itemIds[STATE.slideshow.currentSlideIndex];
+ if (currentItemId) {
+ // YouTube
+ if (STATE.slideshow.videoPlayers && STATE.slideshow.videoPlayers[currentItemId]) {
+ const player = STATE.slideshow.videoPlayers[currentItemId];
+ if (typeof player.pauseVideo === "function") {
+ try {
+ player.pauseVideo();
+ STATE.slideshow.isVideoPlaying = false;
+ } catch (e) {
+ console.warn("Error pausing video on tab hide:", e);
+ }
+ } else if (player.tagName === 'VIDEO') { // HTML5 Video
+ player.pause();
+ STATE.slideshow.isVideoPlaying = false;
+ }
+ }
+ }
+ } else {
+ console.log("Tab active - resuming slideshow");
+ if (!STATE.slideshow.isPaused) {
+ const currentItemId = STATE.slideshow.itemIds[STATE.slideshow.currentSlideIndex];
+
+ if (wasVideoPlayingBeforeHide && currentItemId && STATE.slideshow.videoPlayers && STATE.slideshow.videoPlayers[currentItemId]) {
+ const player = STATE.slideshow.videoPlayers[currentItemId];
+
+ // YouTube
+ if (typeof player.playVideo === "function") {
+ try {
+ player.playVideo();
+ STATE.slideshow.isVideoPlaying = true;
+ } catch (e) {
+ console.warn("Error resuming video on tab show:", e);
+ if (STATE.slideshow.slideInterval) {
+ STATE.slideshow.slideInterval.start();
+ }
+ }
+ } else if (player.tagName === 'VIDEO') { // HTML5 Video
+ try {
+ player.play().catch(e => console.warn("Error resuming HTML5 video:", e));
+ STATE.slideshow.isVideoPlaying = true;
+ } catch(e) { console.warn(e); }
+ }
+ } else {
+ // No video was playing, just restart interval
+ const activeSlide = document.querySelector('.slide.active');
+ const hasVideo = activeSlide && activeSlide.querySelector('.video-backdrop');
+
+ if (CONFIG.waitForTrailerToEnd && hasVideo) {
+ // Don't restart interval if waiting for trailer
+ } else {
+ if (STATE.slideshow.slideInterval) {
+ STATE.slideshow.slideInterval.start();
+ }
+ }
+ }
+ wasVideoPlayingBeforeHide = false;
+ }
+ }
+ });
+};
+
/**
* Initialize the slideshow
*/
@@ -3222,6 +3303,8 @@ const slidesInit = async () => {
SlideshowManager.initKeyboardEvents();
+ initPageVisibilityHandler();
+
VisibilityObserver.init();
console.log("✅ Enhanced Jellyfin Slideshow initialized successfully");
diff --git a/manifest.json b/manifest.json
index 44dc1aa..a288372 100644
--- a/manifest.json
+++ b/manifest.json
@@ -9,10 +9,10 @@
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png",
"versions": [
{
- "version": "1.4.0.12",
- "changelog": "- feat: Add client-side settings feature for selected media bar settings",
+ "version": "1.5.0.0",
+ "changelog": "- Update mediaBarEnhanced.js and mediaBarEnhanced.css with version 3.0.9 from original repo",
"targetAbi": "10.11.0.0",
- "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.4.0.12/Jellyfin.Plugin.MediaBarEnhanced.zip",
+ "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.5.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "26edee51b52dcee4ecf388aa376f3869",
"timestamp": "2026-02-04T18:07:40Z"
},