Version 3 mit URL und Newsticker
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
font-family: system-ui, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
@@ -15,22 +16,86 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
img, video {
|
||||
img, video, iframe {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
object-fit: contain;
|
||||
background: black;
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
img, iframe {
|
||||
object-fit: contain;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
video {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.newsticker-text {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.newsticker-track {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
top: 0;
|
||||
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
animation: ticker-scroll 40s linear infinite;
|
||||
}
|
||||
|
||||
.newsticker-track span {
|
||||
padding-right: 4rem;
|
||||
}
|
||||
|
||||
@keyframes ticker-scroll {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-100vw); }
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<img id="image">
|
||||
<video id="video" muted autoplay playsinline></video>
|
||||
<iframe id="iframe"></iframe>
|
||||
|
||||
{% if newsticker_enabled %}
|
||||
<div id="newsticker-bar" style="position:fixed;left:0;right:0;bottom:0;height:40px;z-index:10000;background:#DA002D;color:#fff;display:flex;align-items:center;overflow:hidden;">
|
||||
<div id="newsticker-text" class="newsticker-text">
|
||||
<div class="newsticker-track">
|
||||
<span>{{ newsticker_text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="newsticker-clock" style="padding:0 18px 0 24px;font-size:1.1em;font-family:monospace;min-width:90px;text-align:right;"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
// Newsticker Uhrzeit
|
||||
function updateClock() {
|
||||
const el = document.getElementById('newsticker-clock');
|
||||
if (!el) return;
|
||||
const now = new Date();
|
||||
el.textContent = now.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||
}
|
||||
setInterval(updateClock, 1000);
|
||||
updateClock();
|
||||
/* -----------------------------
|
||||
Daten vom Server
|
||||
----------------------------- */
|
||||
@@ -44,85 +109,110 @@ const screen = "{{ screen }}";
|
||||
----------------------------- */
|
||||
let normalIndex = 0;
|
||||
let prioIndex = 0;
|
||||
let playPrioNext = false;
|
||||
let mode = "normal"; // "normal" oder "prio"
|
||||
|
||||
|
||||
const img = document.getElementById("image");
|
||||
const vid = document.getElementById("video");
|
||||
const iframe = document.getElementById("iframe");
|
||||
|
||||
/* -----------------------------
|
||||
Hilfsfunktionen
|
||||
----------------------------- */
|
||||
function isVideo(file) {
|
||||
return file.toLowerCase().endsWith(".mp4");
|
||||
function normalizeItem(item) {
|
||||
if (typeof item === "string") {
|
||||
const lower = item.toLowerCase();
|
||||
if (lower.startsWith("http://") || lower.startsWith("https://")) {
|
||||
return { kind: "url", url: item };
|
||||
}
|
||||
return { kind: "file", name: item };
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
function isVideo(item) {
|
||||
return item.kind === "file" && item.name.toLowerCase().endsWith(".mp4");
|
||||
}
|
||||
|
||||
function isImage(item) {
|
||||
return item.kind === "file" && /\.(jpg|jpeg|png)$/i.test(item.name);
|
||||
}
|
||||
|
||||
function getNextItem() {
|
||||
const normalizedNormal = normalFiles.map(normalizeItem);
|
||||
const normalizedPrio = prioFiles.map(normalizeItem);
|
||||
|
||||
// ✅ Sonderfall: nur Priority vorhanden
|
||||
if (normalFiles.length === 0 && prioFiles.length > 0) {
|
||||
if (normalizedNormal.length === 0 && normalizedPrio.length > 0) {
|
||||
return {
|
||||
file: prioFiles[prioIndex++ % prioFiles.length],
|
||||
item: normalizedPrio[prioIndex++ % normalizedPrio.length],
|
||||
isPrio: true
|
||||
};
|
||||
}
|
||||
|
||||
// ✅ Sonderfall: nur normale Playlist vorhanden
|
||||
if (prioFiles.length === 0 && normalFiles.length > 0) {
|
||||
if (normalizedPrio.length === 0 && normalizedNormal.length > 0) {
|
||||
return {
|
||||
file: normalFiles[normalIndex++ % normalFiles.length],
|
||||
item: normalizedNormal[normalIndex++ % normalizedNormal.length],
|
||||
isPrio: false
|
||||
};
|
||||
}
|
||||
|
||||
// ✅ Normal-Phase
|
||||
if (mode === "normal") {
|
||||
const file = normalFiles[normalIndex++];
|
||||
if (normalIndex >= normalFiles.length) {
|
||||
const item = normalizedNormal[normalIndex++];
|
||||
if (normalIndex >= normalizedNormal.length) {
|
||||
normalIndex = 0;
|
||||
if (prioFiles.length > 0) {
|
||||
if (normalizedPrio.length > 0) {
|
||||
mode = "prio"; // ➜ nach kompletter Normal-Playlist wechseln
|
||||
}
|
||||
}
|
||||
return { file, isPrio: false };
|
||||
return { item, isPrio: false };
|
||||
}
|
||||
|
||||
// ✅ Priority-Phase
|
||||
if (mode === "prio") {
|
||||
const file = prioFiles[prioIndex++];
|
||||
if (prioIndex >= prioFiles.length) {
|
||||
const item = normalizedPrio[prioIndex++];
|
||||
if (prioIndex >= normalizedPrio.length) {
|
||||
prioIndex = 0;
|
||||
mode = "normal"; // ➜ nach kompletter Priority zurück
|
||||
}
|
||||
return { file, isPrio: true };
|
||||
return { item, isPrio: true };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -----------------------------
|
||||
Medien abspielen
|
||||
----------------------------- */
|
||||
function playNext() {
|
||||
const item = getNextItem();
|
||||
if (!item) return;
|
||||
const entry = getNextItem();
|
||||
if (!entry) return;
|
||||
|
||||
const basePath = item.isPrio ? "priority" : screen;
|
||||
const src = `/media/${basePath}/${item.file}`;
|
||||
const item = entry.item;
|
||||
const basePath = entry.isPrio ? "priority" : screen;
|
||||
|
||||
if (isVideo(item.file)) {
|
||||
img.style.display = "none";
|
||||
img.style.display = "none";
|
||||
vid.style.display = "none";
|
||||
iframe.style.display = "none";
|
||||
vid.pause();
|
||||
vid.src = "";
|
||||
iframe.src = "";
|
||||
|
||||
if (item.kind === "url") {
|
||||
iframe.style.display = "block";
|
||||
iframe.src = item.url;
|
||||
setTimeout(playNext, interval);
|
||||
return;
|
||||
}
|
||||
|
||||
const src = `/media/${basePath}/${item.name}`;
|
||||
if (isVideo(item)) {
|
||||
vid.style.display = "block";
|
||||
vid.src = src;
|
||||
vid.onended = playNext;
|
||||
vid.play();
|
||||
} else {
|
||||
vid.pause();
|
||||
vid.style.display = "none";
|
||||
img.style.display = "block";
|
||||
img.src = src;
|
||||
setTimeout(playNext, interval);
|
||||
|
||||
Reference in New Issue
Block a user