diff --git a/Jellyfin.Plugin.Seasonals/Web/starwars.css b/Jellyfin.Plugin.Seasonals/Web/starwars.css new file mode 100644 index 0000000..154e36e --- /dev/null +++ b/Jellyfin.Plugin.Seasonals/Web/starwars.css @@ -0,0 +1,60 @@ +.starwars-container { + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 5; + contain: strict; + overflow: hidden; +} + +.starwars-center { + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; +} + +.starwars-streak { + position: absolute; + top: 0; + left: 0; + width: 2px; + height: 100vh; + transform-origin: top center; +} + +.starwars-streak::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 2px; + height: 15vh; + background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(200, 230, 255, 0.8) 70%, rgba(255, 255, 255, 1) 100%); + box-shadow: 0 0 8px #88ccff; + border-radius: 2px; + animation: warp-streak cubic-bezier(0.7, 0, 1, 1) infinite; + animation-duration: inherit; + animation-delay: inherit; + animation-fill-mode: both; + will-change: transform, opacity; +} + +@keyframes warp-streak { + 0% { + transform: translateY(2vh) scaleY(0.1); + opacity: 0; + } + 20% { + opacity: 1; + } + 100% { + transform: translateY(150vh) scaleY(3); + opacity: 0; + } +} diff --git a/Jellyfin.Plugin.Seasonals/Web/starwars.js b/Jellyfin.Plugin.Seasonals/Web/starwars.js new file mode 100644 index 0000000..c5227fa --- /dev/null +++ b/Jellyfin.Plugin.Seasonals/Web/starwars.js @@ -0,0 +1,78 @@ +const config = window.SeasonalsPluginConfig?.StarWars || {}; +const starwars = config.EnableStarWars !== undefined ? config.EnableStarWars : true; + +let msgPrinted = false; + +function toggleStarWars() { + const container = document.querySelector('.starwars-container'); + if (!container) return; + + const videoPlayer = document.querySelector('.videoPlayerContainer'); + const trailerPlayer = document.querySelector('.youtubePlayerContainer'); + const isDashboard = document.body.classList.contains('dashboardDocument'); + const hasUserMenu = document.querySelector('#app-user-menu'); + + if (videoPlayer || trailerPlayer || isDashboard || hasUserMenu) { + container.style.display = 'none'; + if (!msgPrinted) { + console.log('StarWars hidden'); + msgPrinted = true; + } + } else { + container.style.display = 'block'; + if (msgPrinted) { + console.log('StarWars visible'); + msgPrinted = false; + } + } +} + +const observer = new MutationObserver(toggleStarWars); +observer.observe(document.body, { + childList: true, + subtree: true, + attributes: true +}); + +function createStarWars(container) { + const center = document.createElement('div'); + center.className = 'starwars-center'; + container.appendChild(center); + + // Create hyperspace streaks + for (let i = 0; i < 60; i++) { + const streak = document.createElement('div'); + streak.className = 'starwars-streak'; + + // Random angle to radiate outward from center + const angle = Math.random() * 360; + streak.style.transform = `rotate(${angle}deg)`; + + // Random delay + const delay = Math.random() * 2; + streak.style.animationDelay = `${delay}s`; + + // Random animation duration for variety + const duration = 0.8 + Math.random() * 1.5; + streak.style.animationDuration = `${duration}s`; + + center.appendChild(streak); + } +} + +function initializeStarWars() { + if (!starwars) return; + + const container = document.querySelector('.starwars-container') || document.createElement("div"); + + if (!document.querySelector('.starwars-container')) { + container.className = "starwars-container"; + container.setAttribute("aria-hidden", "true"); + document.body.appendChild(container); + } + + createStarWars(container); + toggleStarWars(); +} + +initializeStarWars();