(function () { // =========== README ========== // Update the message below // incrementversion DISMISSED_KEY const DISMISSED_KEY = 'jf-banner-dismissed-v1'; const BANNER_ID = 'custom-announcement-banner'; // Edit these to change banner content: const BANNER_HTML = ` `; const BANNER_CSS = ` #custom-announcement-banner { position: fixed; top: 0; left: 0; display: flex; align-items: center; justify-content: space-between; background: #1c3a5c; color: #e0e0e0; font-size: 0.9em; padding: 8px 16px; box-sizing: border-box; width: 100%; z-index: 9999; border-bottom: 1px solid #2d5a8e; } #custom-announcement-banner a { color: #7cb8f0; } #custom-banner-close { background: none; border: none; color: #e0e0e0; cursor: pointer; font-size: 1.1em; padding: 0 4px; flex-shrink: 0; } `; function applyOffset() { const banner = document.getElementById(BANNER_ID); const offset = banner ? (banner.offsetHeight + 'px') : ''; const header = document.querySelector('.headerTop'); const drawer = document.querySelector('.mainDrawer'); const sections = document.querySelector('.homeSectionsContainer'); if (header) header.style.marginTop = offset; if (drawer) drawer.style.marginTop = offset; if (sections) sections.style.marginTop = offset; } function isHomePage() { const h = window.location.hash; return h === '' || h === '#' || h === '#/home' || h === '#!' || h === '#!/' || h.startsWith('#/home') || h.startsWith('#!/home'); } function injectBanner() { if (document.getElementById(BANNER_ID)) return; const banner = document.createElement('div'); banner.id = BANNER_ID; banner.innerHTML = BANNER_HTML; document.body.insertBefore(banner, document.body.firstChild); document.getElementById('custom-banner-close').addEventListener('click', function () { sessionStorage.setItem(DISMISSED_KEY, '1'); document.getElementById(BANNER_ID).remove(); applyOffset(); }); applyOffset(); } function removeBanner() { const el = document.getElementById(BANNER_ID); if (el) el.remove(); applyOffset(); } function update() { if (sessionStorage.getItem(DISMISSED_KEY)) { removeBanner(); return; } if (isHomePage()) { injectBanner(); } else { removeBanner(); } } // Inject CSS once const style = document.createElement('style'); style.textContent = BANNER_CSS; document.head.appendChild(style); // React to SPA navigation window.addEventListener('hashchange', update); // Watch for Jellyfin's deferred body rendering (SPA bootstraps after DOMContentLoaded) // subtree: true catches .headerTop wherever it appears in the DOM const observer = new MutationObserver(function () { update(); applyOffset(); }); document.addEventListener('DOMContentLoaded', function () { observer.observe(document.body, { childList: true, subtree: true }); update(); }); // Fallback: run immediately if DOMContentLoaded already fired if (document.readyState !== 'loading') update(); })();