Compare commits

..

15 Commits

Author SHA1 Message Date
CodeDevMLH
23a73543c9 Update manifest.json for release v1.8.1.3 [skip ci] 2026-03-23 22:47:55 +00:00
CodeDevMLH
8804048c61 Bump version to 1.8.1.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 46s
2026-03-23 23:47:09 +01:00
CodeDevMLH
992f854dd2 Add configuration options for backdrop video delay and plot width constraint 2026-03-23 23:37:47 +01:00
CodeDevMLH
c30300d1ba Update manifest.json for release v1.8.1.2 [skip ci] 2026-03-23 17:35:37 +00:00
CodeDevMLH
387f0dd26f Bump version to 1.8.1.2
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 46s
2026-03-23 18:34:50 +01:00
CodeDevMLH
71d9cddebb Add failsafe to remove loading screen after 15 seconds to prevent infinite lockouts 2026-03-23 18:34:33 +01:00
CodeDevMLH
9abcdf522d Fix slides container initialization to create a dummy element if not present 2026-03-23 18:26:18 +01:00
CodeDevMLH
8c703ce171 Update manifest.json for release v1.8.1.1 [skip ci] 2026-03-23 16:42:42 +00:00
CodeDevMLH
a40ee4a40d Bump version to 1.8.1.1 and update changelog for mobile pagination fix
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 46s
2026-03-23 17:41:55 +01:00
CodeDevMLH
d7e9238e21 Add padding to the slides container for improved layout 2026-03-23 17:41:40 +01:00
CodeDevMLH
a296caf70d Update manifest.json for release v1.8.1.0 [skip ci] 2026-03-23 16:28:17 +00:00
CodeDevMLH
86e9968243 bump version 1.8.1.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 55s
2026-03-23 17:27:08 +01:00
CodeDevMLH
e9fe356cee Enhance slideshow responsiveness by adjusting dot display for small screens 2026-03-23 17:25:48 +01:00
CodeDevMLH
e25a99439a Update manifest.json for release v1.8.0.0 [skip ci] 2026-03-11 01:38:44 +00:00
CodeDevMLH
ba2ad8f2cc Bump version to 1.8.0.0 in project files and manifest
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 45s
2026-03-11 02:37:57 +01:00
6 changed files with 131 additions and 40 deletions

View File

@@ -49,6 +49,8 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Configuration
public bool IncludeWatchedContent { get; set; } = false; public bool IncludeWatchedContent { get; set; } = false;
public string SortBy { get; set; } = "Random"; public string SortBy { get; set; } = "Random";
public string SortOrder { get; set; } = "Ascending"; public string SortOrder { get; set; } = "Ascending";
public int BackdropVideoDelay { get; set; } = 0;
public bool ConstrainPlotWidth { get; set; } = false;
public bool EnableCustomOverlay { get; set; } = false; public bool EnableCustomOverlay { get; set; } = false;
public string CustomOverlayText { get; set; } = ""; public string CustomOverlayText { get; set; } = "";

View File

@@ -418,6 +418,13 @@
on on
mobile devices. (looks bad on desktops)</div> mobile devices. (looks bad on desktops)</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="ConstrainPlotWidth" name="ConstrainPlotWidth" />
<span>Constrain Plot Width</span>
</label>
<div class="fieldDescription">Align the description text left to match the logo width, preventing it from crossing the entire screen. (Increases the text limit to 3 lines instead of 2).</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input is="emby-checkbox" type="checkbox" id="EnableLoadingScreen" <input is="emby-checkbox" type="checkbox" id="EnableLoadingScreen"
@@ -463,6 +470,11 @@
<input is="emby-input" type="number" id="ShuffleInterval" name="ShuffleInterval" /> <input is="emby-input" type="number" id="ShuffleInterval" name="ShuffleInterval" />
<div class="fieldDescription">Time in milliseconds between changing slides.</div> <div class="fieldDescription">Time in milliseconds between changing slides.</div>
</div> </div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="BackdropVideoDelay">Backdrop Video Delay (ms)</label>
<input is="emby-input" type="number" id="BackdropVideoDelay" name="BackdropVideoDelay" />
<div class="fieldDescription">Time in milliseconds to wait before playing backdrops/theme videos (leaves static backdrop visible longer).</div>
</div>
<div class="inputContainer"> <div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="RetryInterval">Retry Interval <label class="inputLabel inputLabelUnfocused" for="RetryInterval">Retry Interval
@@ -663,7 +675,8 @@
'MaxDaysRecent', 'ExcludeSeasonalContent', 'HideArrowsOnMobile', 'MaxDaysRecent', 'ExcludeSeasonalContent', 'HideArrowsOnMobile',
'EnableCustomOverlay', 'CustomOverlayText', 'CustomOverlayImageUrl', 'EnableCustomOverlay', 'CustomOverlayText', 'CustomOverlayImageUrl',
'CustomOverlayStyle', 'CustomOverlayImageStyle', 'CustomOverlayPriority', 'CustomOverlayStyle', 'CustomOverlayImageStyle', 'CustomOverlayPriority',
'CustomOverlayPositionX', 'CustomOverlayPositionY', 'CustomOverlayScale' 'CustomOverlayPositionX', 'CustomOverlayPositionY', 'CustomOverlayScale',
'BackdropVideoDelay', 'ConstrainPlotWidth'
]; ];
// Manual mapping for MediaBarIsEnabled -> IsEnabled, to avoid conflicts with other plugins // Manual mapping for MediaBarIsEnabled -> IsEnabled, to avoid conflicts with other plugins
@@ -908,7 +921,8 @@
'MaxDaysRecent', 'ExcludeSeasonalContent', 'HideArrowsOnMobile', 'MaxDaysRecent', 'ExcludeSeasonalContent', 'HideArrowsOnMobile',
'EnableCustomOverlay', 'CustomOverlayText', 'CustomOverlayImageUrl', 'EnableCustomOverlay', 'CustomOverlayText', 'CustomOverlayImageUrl',
'CustomOverlayStyle', 'CustomOverlayImageStyle', 'CustomOverlayPriority', 'CustomOverlayStyle', 'CustomOverlayImageStyle', 'CustomOverlayPriority',
'CustomOverlayPositionX', 'CustomOverlayPositionY', 'CustomOverlayScale' 'CustomOverlayPositionX', 'CustomOverlayPositionY', 'CustomOverlayScale',
'BackdropVideoDelay', 'ConstrainPlotWidth'
]; ];
keys.forEach(function (key) { keys.forEach(function (key) {

View File

@@ -12,7 +12,7 @@
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> --> <!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
<Title>Jellyfin Media Bar Enhanced Plugin</Title> <Title>Jellyfin Media Bar Enhanced Plugin</Title>
<Authors>CodeDevMLH</Authors> <Authors>CodeDevMLH</Authors>
<Version>1.7.2.16</Version> <Version>1.8.1.3</Version>
<RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced</RepositoryUrl> <RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced</RepositoryUrl>
</PropertyGroup> </PropertyGroup>

View File

@@ -489,6 +489,15 @@
overflow: hidden; overflow: hidden;
} }
.plot-container.constrained-plot {
width: 40%;
}
.plot-container.constrained-plot .plot {
line-clamp: 3;
-webkit-line-clamp: 3;
}
.genre { .genre {
display: flex; display: flex;
gap: 5px; gap: 5px;
@@ -749,6 +758,15 @@
left: 50%; left: 50%;
transform: translateX(-50%) scale(0.8); transform: translateX(-50%) scale(0.8);
background-color: #ffffff00; background-color: #ffffff00;
width: max-content;
max-width: 90vw;
flex-wrap: nowrap;
overflow: hidden;
padding: 10px 0;
}
.dot {
flex-shrink: 0;
} }
.dot.active { .dot.active {

View File

@@ -340,6 +340,15 @@ const initLoadingScreen = () => {
}); });
}); });
}; };
// Global Failsafe, force remove loading screen after 15 seconds to prevent infinite lockouts
setTimeout(() => {
const loader = document.querySelector(".bar-loading");
if (loader) {
console.warn("🎬 Media Bar:", "Loading screen timed out! Forcing removal as a failsafe.");
finishLoading();
}
}, 15000);
}; };
/** /**
@@ -2046,7 +2055,7 @@ const SlideCreator = {
SlideUtils.truncateText(plotElement, CONFIG.maxPlotLength); SlideUtils.truncateText(plotElement, CONFIG.maxPlotLength);
const plotContainer = SlideUtils.createElement("div", { const plotContainer = SlideUtils.createElement("div", {
className: "plot-container", className: "plot-container" + (CONFIG.constrainPlotWidth ? " constrained-plot" : ""),
}); });
plotContainer.appendChild(plotElement); plotContainer.appendChild(plotElement);
@@ -2363,8 +2372,17 @@ const SlideshowManager = {
const totalItems = STATE.slideshow.totalItems || 0; const totalItems = STATE.slideshow.totalItems || 0;
// dynamically lower the max dots threshold on small screens
let effectiveMaxDots = CONFIG.maxPaginationDots;
if (window.matchMedia("(max-width: 767px) and (orientation: portrait)").matches) {
const availableWidth = window.innerWidth * 0.9;
const dotWidth = 18; // approximate width per dot
const fittingDots = Math.floor(availableWidth / dotWidth) - 1;
effectiveMaxDots = Math.min(effectiveMaxDots, fittingDots);
}
// Switch to counter style if too many items // Switch to counter style if too many items
if (totalItems > CONFIG.maxPaginationDots) { if (totalItems > effectiveMaxDots) {
const counter = document.createElement("span"); const counter = document.createElement("span");
counter.className = "slide-counter"; counter.className = "slide-counter";
counter.id = "slide-counter"; counter.id = "slide-counter";
@@ -2425,6 +2443,11 @@ const SlideshowManager = {
STATE.slideshow.isTransitioning = true; STATE.slideshow.isTransitioning = true;
if (STATE.slideshow.backdropVideoTimeout) {
clearTimeout(STATE.slideshow.backdropVideoTimeout);
STATE.slideshow.backdropVideoTimeout = null;
}
let previousVisibleSlide; let previousVisibleSlide;
try { try {
const container = SlideUtils.getOrCreateSlidesContainer(); const container = SlideUtils.getOrCreateSlidesContainer();
@@ -2516,11 +2539,13 @@ const SlideshowManager = {
} }
if (videoBackdrop) { if (videoBackdrop) {
// preload logic
if (videoBackdrop.tagName === 'VIDEO') { if (videoBackdrop.tagName === 'VIDEO') {
// Restore src from data-src if it was deactivated to release connections // Restore src from data-src if it was deactivated to release connections
const lazySrc = videoBackdrop.getAttribute('data-src'); const lazySrc = videoBackdrop.getAttribute('data-src');
if (lazySrc && !videoBackdrop.src) { if (lazySrc && !videoBackdrop.src) {
videoBackdrop.src = lazySrc; videoBackdrop.src = lazySrc;
videoBackdrop.load(); // Force pre-buffering
} }
videoBackdrop.currentTime = 0; videoBackdrop.currentTime = 0;
@@ -2529,7 +2554,33 @@ const SlideshowManager = {
if (!STATE.slideshow.isMuted) { if (!STATE.slideshow.isMuted) {
videoBackdrop.volume = 0.4; videoBackdrop.volume = 0.4;
} }
} else if (STATE.slideshow.videoPlayers && STATE.slideshow.videoPlayers[currentItemId]) {
const player = STATE.slideshow.videoPlayers[currentItemId];
if (player && typeof player.cueVideoById === 'function' && player._videoId) {
// Use cueVideoById to buffer video without auto-playing it
player.cueVideoById({
videoId: player._videoId,
startSeconds: player._startTime || 0,
endSeconds: player._endTime
});
if (STATE.slideshow.isMuted) {
player.mute();
} else {
player.unMute();
player.setVolume(40);
}
} else if (player && typeof player.seekTo === 'function') {
const startTime = player._startTime || 0;
player.seekTo(startTime);
}
}
// play logic
const playVideoLogic = () => {
if (!currentSlide.classList.contains('active')) return;
if (videoBackdrop.tagName === 'VIDEO') {
videoBackdrop.play().catch(e => { videoBackdrop.play().catch(e => {
// Check if it actually started playing after a short delay (handling autoplay blocks) // Check if it actually started playing after a short delay (handling autoplay blocks)
setTimeout(() => { setTimeout(() => {
@@ -2542,20 +2593,8 @@ const SlideshowManager = {
}); });
} else if (STATE.slideshow.videoPlayers && STATE.slideshow.videoPlayers[currentItemId]) { } else if (STATE.slideshow.videoPlayers && STATE.slideshow.videoPlayers[currentItemId]) {
const player = STATE.slideshow.videoPlayers[currentItemId]; const player = STATE.slideshow.videoPlayers[currentItemId];
if (player && typeof player.loadVideoById === 'function' && player._videoId) { if (player && typeof player.playVideo === 'function') {
// Use loadVideoById to enforce start and end times player.playVideo();
player.loadVideoById({
videoId: player._videoId,
startSeconds: player._startTime || 0,
endSeconds: player._endTime
});
if (STATE.slideshow.isMuted) {
player.mute();
} else {
player.unMute();
player.setVolume(40);
}
// Check if playback successfully started, otherwise fallback to muted // Check if playback successfully started, otherwise fallback to muted
setTimeout(() => { setTimeout(() => {
@@ -2563,18 +2602,20 @@ const SlideshowManager = {
if (player.getPlayerState && if (player.getPlayerState &&
player.getPlayerState() !== YT.PlayerState.PLAYING && player.getPlayerState() !== YT.PlayerState.PLAYING &&
player.getPlayerState() !== YT.PlayerState.BUFFERING) { player.getPlayerState() !== YT.PlayerState.BUFFERING) {
console.log("🎬 Media Bar:", "YouTube loadVideoById didn't start playback, retrying muted..."); console.log("🎬 Media Bar:", "YouTube didn't start playback, retrying muted...");
player.mute(); player.mute();
player.playVideo(); player.playVideo();
} }
}, 1000); }, 1000);
} else if (player && typeof player.seekTo === 'function') {
// Fallback if loadVideoById is not available or videoId missing
const startTime = player._startTime || 0;
player.seekTo(startTime);
player.playVideo();
} }
} }
};
if (CONFIG.backdropVideoDelay > 0) {
STATE.slideshow.backdropVideoTimeout = setTimeout(playVideoLogic, CONFIG.backdropVideoDelay);
} else {
playVideoLogic();
}
} }
const enableAnimations = MediaBarEnhancedSettingsManager.getSetting('slideAnimations', CONFIG.slideAnimationEnabled); const enableAnimations = MediaBarEnhancedSettingsManager.getSetting('slideAnimations', CONFIG.slideAnimationEnabled);
@@ -3892,8 +3933,16 @@ const slidesInit = async () => {
homeSections.style.top = '0'; homeSections.style.top = '0';
homeSections.style.marginTop = '0'; homeSections.style.marginTop = '0';
} }
const container = document.getElementById('slides-container'); let container = document.getElementById('slides-container');
if (container) container.style.display = 'none'; if (container) {
container.style.display = 'none';
} else {
// Create dummy container so loading screen's interval can trigger its own cleanup
container = document.createElement('div');
container.id = 'slides-container';
container.style.display = 'none';
document.body.appendChild(container);
}
return; return;
} }

View File

@@ -9,12 +9,20 @@
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png", "imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png",
"versions": [ "versions": [
{ {
"version": "1.7.2.16", "version": "1.8.1.3",
"changelog": "feat: add custom text/image overlay option\n- feat: add option to disable pagination dots/counter\n- feat: add exclude seasonal content from random fetching option\n- Add hide arrows on mobile option \n- fix button issue on mobile when using ElegantFin Theme", "changelog": "- fix pagination dot issue on mobile when showing more than 10 dots (should now dynamically adjust the max dots threshold based on screen size)\n- add option to delay trailer playback\n- add option to limit the plot width",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.7.2.16/Jellyfin.Plugin.MediaBarEnhanced.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.8.1.3/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "7cee3461f232a361fc9167a0a43fc023", "checksum": "9be63bf948fc4a41d643afbed301dd8a",
"timestamp": "2026-03-11T00:46:02Z" "timestamp": "2026-03-23T22:47:55Z"
},
{
"version": "1.8.0.0",
"changelog": "- feat: add custom text/image overlay option\n- feat: add option to disable pagination dots/counter\n- feat: add exclude seasonal content from random fetching option\n- Add hide arrows on mobile option \n- fix button issue on mobile when using ElegantFin Theme",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.8.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "0aac723796d41fc15987c94ac0476584",
"timestamp": "2026-03-11T01:38:43Z"
}, },
{ {
"version": "1.7.0.14", "version": "1.7.0.14",