Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6ccd0ea5f | ||
|
|
47827df047 | ||
|
|
7fd781c9d0 | ||
|
|
6faa8f1a4c | ||
|
|
3e05ff1dc9 | ||
|
|
fa06179cd3 | ||
|
|
d8327fc5c9 | ||
|
|
9ffe03f0df | ||
|
|
37e99d7fed | ||
|
|
9b0e3762ac | ||
|
|
48f93e3480 | ||
|
|
2e9c093cdc | ||
|
|
60593dc855 | ||
|
|
0edde43720 | ||
|
|
0f6938a91d |
@@ -31,6 +31,7 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Configuration
|
||||
public bool AlwaysShowArrows { get; set; } = false;
|
||||
public string CustomMediaIds { get; set; } = "";
|
||||
public bool EnableCustomMediaIds { get; set; } = true;
|
||||
public string PreferredVideoQuality { get; set; } = "Auto";
|
||||
public bool EnableSeasonalContent { get; set; } = false;
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,18 @@
|
||||
</label>
|
||||
<div class="fieldDescription">Skip intro/outro segments in YouTube trailers.</div>
|
||||
</div>
|
||||
<div class="selectContainer">
|
||||
<label class="selectLabel" for="PreferredVideoQuality">Preferred YouTube Quality</label>
|
||||
<select is="emby-select" id="PreferredVideoQuality" name="PreferredVideoQuality"
|
||||
class="emby-select-withcolor emby-select">
|
||||
<option value="Auto">Auto (Smart)</option>
|
||||
<option value="Maximum">Maximum (4K+)</option>
|
||||
<option value="1080p">1080p</option>
|
||||
<option value="720p">720p</option>
|
||||
</select>
|
||||
<div class="fieldDescription">"Auto" selects Maximum if screen width > 1920px, otherwise
|
||||
1080p.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="StartMuted" name="StartMuted" />
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
|
||||
<Title>Jellyfin Media Bar Enhanced Plugin</Title>
|
||||
<Authors>CodeDevMLH</Authors>
|
||||
<Version>1.1.0.0</Version>
|
||||
<Version>1.2.1.0</Version>
|
||||
<RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Jellyfin Slideshow by M0RPH3US v3.0.6
|
||||
* Jellyfin Slideshow by M0RPH3US v3.0.8
|
||||
* Modified by CodeDevMLH v1.1.0.0
|
||||
*
|
||||
* New features:
|
||||
@@ -41,11 +41,11 @@
|
||||
|
||||
@keyframes kenBurnsZoomIn {
|
||||
from {
|
||||
transform: scale(1);
|
||||
transform: scale3d(1, 1, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.1);
|
||||
transform: scale3d(1.1, 1.1, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +128,10 @@
|
||||
transition: width 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.layout-mobile .splashLogo {
|
||||
height: 12%;
|
||||
}
|
||||
|
||||
.backdrop.low-quality {
|
||||
filter: blur(0.5px);
|
||||
transform: scale(1.01);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Jellyfin Slideshow by M0RPH3US v3.0.6
|
||||
* Jellyfin Slideshow by M0RPH3US v3.0.8
|
||||
* Modified by CodeDevMLH v1.1.0.0
|
||||
*
|
||||
* New features:
|
||||
@@ -42,6 +42,7 @@ const CONFIG = {
|
||||
fullWidthVideo: true,
|
||||
enableMobileVideo: false,
|
||||
showTrailerButton: true,
|
||||
preferredVideoQuality: "Auto",
|
||||
enableKeyboardControls: true,
|
||||
alwaysShowArrows: false,
|
||||
enableCustomMediaIds: true,
|
||||
@@ -252,31 +253,53 @@ const initLoadingScreen = () => {
|
||||
|
||||
const checkInterval = setInterval(() => {
|
||||
const loginFormLoaded = document.querySelector(".manualLoginForm");
|
||||
const homePageLoaded =
|
||||
document.querySelector(".homeSectionsContainer") &&
|
||||
document.querySelector("#slides-container");
|
||||
const activeTab = document.querySelector(".pageTabContent.is-active");
|
||||
|
||||
if (loginFormLoaded || homePageLoaded) {
|
||||
clearInterval(progressInterval);
|
||||
clearInterval(checkInterval);
|
||||
if (loginFormLoaded) {
|
||||
finishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.style.transition = "width 300ms ease-in-out";
|
||||
progressBar.style.width = "100%";
|
||||
unfilledBar.style.width = "0%";
|
||||
if (activeTab) {
|
||||
const tabIndex = activeTab.getAttribute("data-index");
|
||||
|
||||
progressBar.addEventListener('transitionend', () => {
|
||||
requestAnimationFrame(() => {
|
||||
const loader = document.querySelector(".bar-loading");
|
||||
if (loader) {
|
||||
loader.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
loader.remove();
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
})
|
||||
if (tabIndex === "0") {
|
||||
const homeSections = document.querySelector(".homeSectionsContainer");
|
||||
const slidesContainer = document.querySelector("#slides-container");
|
||||
|
||||
if (homeSections && slidesContainer) {
|
||||
finishLoading();
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
activeTab.children.length > 0 ||
|
||||
activeTab.innerText.trim().length > 0
|
||||
) {
|
||||
finishLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, CONFIG.loadingCheckInterval);
|
||||
|
||||
const finishLoading = () => {
|
||||
clearInterval(progressInterval);
|
||||
clearInterval(checkInterval);
|
||||
progressBar.style.transition = "width 300ms ease-in-out";
|
||||
progressBar.style.width = "100%";
|
||||
unfilledBar.style.width = "0%";
|
||||
|
||||
progressBar.addEventListener("transitionend", () => {
|
||||
requestAnimationFrame(() => {
|
||||
const loader = document.querySelector(".bar-loading");
|
||||
if (loader) {
|
||||
loader.style.opacity = "0";
|
||||
setTimeout(() => {
|
||||
loader.remove();
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1259,11 +1282,13 @@ const VisibilityObserver = {
|
||||
if (isVisible) {
|
||||
if (STATE.slideshow.slideInterval && !STATE.slideshow.isPaused) {
|
||||
STATE.slideshow.slideInterval.start();
|
||||
SlideshowManager.resumeActivePlayback();
|
||||
}
|
||||
} else {
|
||||
if (STATE.slideshow.slideInterval) {
|
||||
STATE.slideshow.slideInterval.stop();
|
||||
}
|
||||
SlideshowManager.stopAllPlayback();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1415,6 +1440,21 @@ const SlideCreator = {
|
||||
loop: 0
|
||||
};
|
||||
|
||||
// Determine video quality
|
||||
let quality = 'hd1080';
|
||||
if (CONFIG.preferredVideoQuality === 'Maximum') {
|
||||
quality = 'highres';
|
||||
} else if (CONFIG.preferredVideoQuality === '720p') {
|
||||
quality = 'hd720';
|
||||
} else if (CONFIG.preferredVideoQuality === '1080p') {
|
||||
quality = 'hd1080';
|
||||
} else { // Auto or fallback
|
||||
// If screen is wider than 1920, prefer highres, otherwise 1080p
|
||||
quality = window.screen.width > 1920 ? 'highres' : 'hd1080';
|
||||
}
|
||||
|
||||
playerVars.suggestedQuality = quality;
|
||||
|
||||
// Apply SponsorBlock start/end times
|
||||
if (segments.intro) {
|
||||
playerVars.start = Math.ceil(segments.intro[1]);
|
||||
@@ -1444,6 +1484,10 @@ const SlideCreator = {
|
||||
event.target.setVolume(40);
|
||||
}
|
||||
|
||||
if (typeof event.target.setPlaybackQuality === 'function') {
|
||||
event.target.setPlaybackQuality(quality);
|
||||
}
|
||||
|
||||
// Only play if this is the active slide
|
||||
const slide = document.querySelector(`.slide[data-item-id="${itemId}"]`);
|
||||
if (slide && slide.classList.contains('active')) {
|
||||
@@ -1492,6 +1536,7 @@ const SlideCreator = {
|
||||
className: "backdrop video-backdrop",
|
||||
src: trailerUrl,
|
||||
autoplay: false,
|
||||
preload: "auto",
|
||||
loop: false,
|
||||
style: "object-fit: cover; width: 100%; height: 100%; pointer-events: none;"
|
||||
};
|
||||
@@ -2317,6 +2362,65 @@ const SlideshowManager = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops all video playback (YouTube and HTML5)
|
||||
* Used when navigating away from the home screen
|
||||
*/
|
||||
stopAllPlayback() {
|
||||
// 1. Pause all YouTube players
|
||||
if (STATE.slideshow.videoPlayers) {
|
||||
Object.values(STATE.slideshow.videoPlayers).forEach(player => {
|
||||
try {
|
||||
if (player && typeof player.pauseVideo === 'function') {
|
||||
player.pauseVideo();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Error pausing YouTube player:", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Pause all HTML5 videos
|
||||
const container = document.getElementById("slides-container");
|
||||
if (container) {
|
||||
container.querySelectorAll('video').forEach(video => {
|
||||
try {
|
||||
video.pause();
|
||||
} catch (e) {
|
||||
console.warn("Error pausing HTML5 video:", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resumes playback for the active slide if not globally paused
|
||||
*/
|
||||
resumeActivePlayback() {
|
||||
if (STATE.slideshow.isPaused) return;
|
||||
|
||||
const currentItemId = STATE.slideshow.itemIds[STATE.slideshow.currentSlideIndex];
|
||||
if (!currentItemId) return;
|
||||
|
||||
const currentSlide = document.querySelector(`.slide[data-item-id="${currentItemId}"]`);
|
||||
if (!currentSlide) return;
|
||||
|
||||
// 1. Try YouTube Player
|
||||
const ytPlayer = STATE.slideshow.videoPlayers[currentItemId];
|
||||
if (ytPlayer && typeof ytPlayer.playVideo === 'function') {
|
||||
ytPlayer.playVideo();
|
||||
}
|
||||
|
||||
// 2. Try HTML5 Video
|
||||
const html5Video = currentSlide.querySelector('video');
|
||||
if (html5Video) {
|
||||
if (STATE.slideshow.isMuted) {
|
||||
html5Video.muted = true;
|
||||
}
|
||||
html5Video.play().catch(e => console.warn("Error resuming HTML5 video:", e));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes touch events for swiping
|
||||
*/
|
||||
|
||||
@@ -2,12 +2,44 @@
|
||||
{
|
||||
"guid": "d7e11d57-819b-4bdd-a88d-53c5f5560225",
|
||||
"name": "Media Bar Enhanced",
|
||||
"description": "A jellyfin plugin to display a media bar (featured content) for jellyfin web.",
|
||||
"overview": "Media Bar for Jellyfin",
|
||||
"description": "A feature-rich fork of the original Media Bar script by MakD that brings your home screen to life.\n\n-> 100% Configurable via Web UI: Manage all features, lists, and settings effortlessly through the plugin configuration page.\n\nKey Highlights:\n- Cinematic Video Backdrops: Supports local & YouTube trailers (incl. SponsorBlock)\n- Custom Content: Curate your slideshow with specific Collections, Playlists, or seasonal events\n\nAdditional Features:\n- Full-width immersive mode\n- Smart resolution handling (up to 4K)\n- Full keyboard navigation & playback control\n- Wait-for-trailer options\n- Customizable pagination & animations\n\nIf you do not have write permissions to the web folder, please also install the file-transformation plugin.",
|
||||
"overview": "Transforms your Jellyfin home screen with an immersive, fully configurable media slideshow featuring video backdrops.",
|
||||
"owner": "CodeDevMLH",
|
||||
"category": "General",
|
||||
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.2.1.0",
|
||||
"changelog": "- Update mediaBarEnhanced.js and mediaBarEnhanced.css with version 3.0.8 from original repo",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.1.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
|
||||
"checksum": "70defc1fb29a17ff4c9362bf7bdc53b5",
|
||||
"timestamp": "2026-01-22T23:50:56Z"
|
||||
},
|
||||
{
|
||||
"version": "1.2.0.0",
|
||||
"changelog": "- Add video quality preference setting (Auto / 1080p / Highres)\n- Set preferred video quality on YouTube player based on setting",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
|
||||
"checksum": "0b6379f68990026240d97fe8f77fbef1",
|
||||
"timestamp": "2026-01-08T23:30:58Z"
|
||||
},
|
||||
{
|
||||
"version": "1.1.2.0",
|
||||
"changelog": "- Add method to resume video playback when slideshow is active",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.2.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
|
||||
"checksum": "a0e8ff5e59b22a1bdedc916cd5e1c16a",
|
||||
"timestamp": "2026-01-08T15:26:55Z"
|
||||
},
|
||||
{
|
||||
"version": "1.1.1.0",
|
||||
"changelog": "- Add method to pause all video playback when navigating away from home screen",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.1.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
|
||||
"checksum": "09da95fc561b11191d23a5cfa30ea731",
|
||||
"timestamp": "2026-01-08T14:54:57Z"
|
||||
},
|
||||
{
|
||||
"version": "1.1.0.0",
|
||||
"changelog": "- 'custom media IDs' setting is now enabled by default (no input --> random selection)\n- improve GUID handling in slideshow manager to handle seperator and description",
|
||||
|
||||
Reference in New Issue
Block a user