136 lines
5.3 KiB
JavaScript
136 lines
5.3 KiB
JavaScript
(function () {
|
|
"use strict";
|
|
|
|
var TWITCH_CHANNEL = "duda_xd";
|
|
|
|
/* Rendert die Video-IDs aus videos.js als iframes.
|
|
* Standard-iframe laut YouTube-Empfehlung. Bewusst OHNE
|
|
* referrerpolicy und OHNE ?si-Parameter: Dann sendet der Browser
|
|
* immer einen Referer (auch bei HTTP-Seite), den YouTube braucht,
|
|
* um den Embedder zu erkennen (sonst Fehler 152/153). */
|
|
function renderYouTubeGrid(videoIds) {
|
|
var grid = document.getElementById("yt-grid");
|
|
if (!grid) return;
|
|
if (!videoIds || !videoIds.length) {
|
|
grid.innerHTML = '<div class="loading">Noch keine Videos vorhanden.</div>';
|
|
return;
|
|
}
|
|
var html = "";
|
|
for (var i = 0; i < videoIds.length; i++) {
|
|
var id = String(videoIds[i]).trim();
|
|
if (!id) continue;
|
|
html +=
|
|
'<div class="video-card">' +
|
|
'<div class="video-wrapper">' +
|
|
'<iframe width="560" height="315" ' +
|
|
'src="https://www.youtube.com/embed/' + id + '" ' +
|
|
'title="YouTube video player" ' +
|
|
'frameborder="0" ' +
|
|
'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" ' +
|
|
'allowfullscreen></iframe>' +
|
|
'</div>' +
|
|
'</div>';
|
|
}
|
|
grid.innerHTML = html || '<div class="loading">Keine Videos gefunden.</div>';
|
|
}
|
|
|
|
/* ------------------------------------------------------------------
|
|
* YouTube: Liest die Video-IDs aus videos.js, die auf dem Server
|
|
* von fetch_videos.py (einmal am Tag per Cron) mit den aktuellen
|
|
* Video-IDs deines Kanals aktualisiert wird.
|
|
*
|
|
* Dein API-Key ist dabei NIE im Browser - er bleibt komplett auf
|
|
* dem Server versteckt (siehe fetch_videos.py).
|
|
* ------------------------------------------------------------------ */
|
|
function loadYouTube() {
|
|
var ids = (typeof DUDA17_VIDEOS !== "undefined") ? DUDA17_VIDEOS : [];
|
|
renderYouTubeGrid(ids);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------
|
|
* Twitch: Live-Player einbetten.
|
|
* ------------------------------------------------------------------ */
|
|
function loadTwitch() {
|
|
var wrap = document.getElementById("twitch-embed");
|
|
if (!wrap) return;
|
|
|
|
var domain = window.location.hostname || "localhost";
|
|
var iframe = document.createElement("iframe");
|
|
iframe.src = "https://player.twitch.tv/?channel=" + TWITCH_CHANNEL +
|
|
"&parent=" + domain + "&muted=true";
|
|
iframe.setAttribute("title", "Twitch Stream");
|
|
iframe.setAttribute("allowfullscreen", "true");
|
|
iframe.setAttribute("scrolling", "no");
|
|
iframe.setAttribute("allow", "autoplay; fullscreen");
|
|
wrap.appendChild(iframe);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------
|
|
* Sticky Navigation & Back-to-Top
|
|
* ------------------------------------------------------------------ */
|
|
function initNavigation() {
|
|
var nav = document.getElementById("sticky-nav");
|
|
var backToTop = document.getElementById("back-to-top");
|
|
var navLinks = document.querySelectorAll(".nav-link[data-section]");
|
|
var sections = [];
|
|
|
|
navLinks.forEach(function (link) {
|
|
var id = link.getAttribute("data-section");
|
|
var el = document.getElementById(id);
|
|
if (el) sections.push({ id: id, el: el, link: link });
|
|
});
|
|
|
|
function onScroll() {
|
|
var scrollY = window.scrollY || window.pageYOffset;
|
|
|
|
if (scrollY > 300) {
|
|
nav.classList.add("visible");
|
|
backToTop.classList.add("visible");
|
|
} else {
|
|
nav.classList.remove("visible");
|
|
backToTop.classList.remove("visible");
|
|
}
|
|
|
|
var active = null;
|
|
for (var i = 0; i < sections.length; i++) {
|
|
var rect = sections[i].el.getBoundingClientRect();
|
|
if (rect.top <= 120) active = sections[i];
|
|
}
|
|
|
|
navLinks.forEach(function (l) { l.classList.remove("active"); });
|
|
if (active) active.link.classList.add("active");
|
|
}
|
|
|
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
onScroll();
|
|
|
|
backToTop.addEventListener("click", function () {
|
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
});
|
|
|
|
navLinks.forEach(function (link) {
|
|
link.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
var id = this.getAttribute("data-section");
|
|
var target = document.getElementById(id);
|
|
if (target) {
|
|
target.scrollIntoView({ behavior: "smooth" });
|
|
}
|
|
});
|
|
});
|
|
|
|
var brandLink = document.querySelector(".nav-brand");
|
|
if (brandLink) {
|
|
brandLink.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
});
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
loadYouTube();
|
|
loadTwitch();
|
|
initNavigation();
|
|
});
|
|
})(); |