Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44f0b1cb38 | ||
|
|
d31dcbabdc | ||
|
|
4ed6509505 | ||
|
|
6427b8422a | ||
|
|
ebfbe1d563 | ||
|
|
67e5d8e4d2 | ||
|
|
d68ba7e846 | ||
|
|
0444cf333d | ||
|
|
10279e97d9 | ||
|
|
f6ccd0ea5f | ||
|
|
47827df047 | ||
|
|
7fd781c9d0 | ||
|
|
6faa8f1a4c | ||
|
|
3e05ff1dc9 | ||
|
|
fa06179cd3 | ||
|
|
d8327fc5c9 | ||
|
|
9ffe03f0df | ||
|
|
37e99d7fed | ||
|
|
9b0e3762ac | ||
|
|
48f93e3480 | ||
|
|
2e9c093cdc | ||
|
|
60593dc855 | ||
|
|
0edde43720 | ||
|
|
0f6938a91d |
2
.github/workflows/release_automation.yml
vendored
2
.github/workflows/release_automation.yml
vendored
@@ -99,7 +99,7 @@ jobs:
|
||||
with:
|
||||
tag_name: "v${{ env.VERSION }}"
|
||||
name: "v${{ env.VERSION }}"
|
||||
body: ${{ env.CHANGELOG }}
|
||||
# body: ${{ env.CHANGELOG }}
|
||||
files: ${{ env.ZIP_PATH }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
@@ -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.3.2</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);
|
||||
@@ -166,6 +170,12 @@
|
||||
height: 90%;
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#slides-container[style*="display: none"],
|
||||
#slides-container[style*="visibility: hidden"] {
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
@@ -780,6 +790,28 @@
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
.button-container {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.play-button,
|
||||
.trailer-button {
|
||||
padding: 8px 14px;
|
||||
}
|
||||
|
||||
.misc-info {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.runTime {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Landscape Mode Phones*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1252,18 +1275,23 @@ const VisibilityObserver = {
|
||||
const isVisible =
|
||||
(window.location.hash === "#/home.html" ||
|
||||
window.location.hash === "#/home") &&
|
||||
activeTab &&
|
||||
activeTab.getAttribute("data-index") === "0";
|
||||
|
||||
container.style.display = isVisible ? "block" : "none";
|
||||
container.style.visibility = isVisible ? "visible" : "hidden";
|
||||
container.style.pointerEvents = isVisible ? "auto" : "none";
|
||||
|
||||
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();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1271,11 +1299,11 @@ const VisibilityObserver = {
|
||||
* Initializes visibility observer
|
||||
*/
|
||||
init() {
|
||||
const observer = new MutationObserver(this.updateVisibility);
|
||||
const observer = new MutationObserver(() => this.updateVisibility());
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
document.body.addEventListener("click", this.updateVisibility);
|
||||
window.addEventListener("hashchange", this.updateVisibility);
|
||||
document.body.addEventListener("click", () => this.updateVisibility());
|
||||
window.addEventListener("hashchange", () => this.updateVisibility());
|
||||
|
||||
this.updateVisibility();
|
||||
},
|
||||
@@ -1415,6 +1443,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 +1487,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 +1539,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 +2365,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
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,8 @@ Setzt deine Commits neu auf die Spitze eines anderen Branches. Die Commit-IDs we
|
||||
|
||||
```bash
|
||||
git checkout dev
|
||||
git rebase main
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
```
|
||||
|
||||
| Details | |
|
||||
|
||||
@@ -2,12 +2,60 @@
|
||||
{
|
||||
"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.3.2",
|
||||
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.2/Jellyfin.Plugin.MediaBarEnhanced.zip",
|
||||
"checksum": "4109a3ea10eb3145217b24ee8f8b37b5",
|
||||
"timestamp": "2026-01-28T00:30:36Z"
|
||||
},
|
||||
{
|
||||
"version": "1.2.2.0",
|
||||
"changelog": "- Fixes issues with persistent slides-container visibility",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.2.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
|
||||
"checksum": "3362f93815845c4e85b66b31bcd0f52c",
|
||||
"timestamp": "2026-01-24T22:53:55Z"
|
||||
},
|
||||
{
|
||||
"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