diff --git a/app.js b/app.js
index 72b229d..5d21914 100644
--- a/app.js
+++ b/app.js
@@ -4,10 +4,57 @@
var TWITCH_CHANNEL = "duda_xd";
/* ------------------------------------------------------------------
- * Twitch: Live-Player einbetten. Zeigt automatisch den aktuellen
- * Stream, sobald du live bist. Die Domain wird dynamisch gesetzt,
- * damit der Player ueberall funktioniert (auch lokal).
- * Twitch ist ein iframe-Embed -> keine CORS-Probleme.
+ * YouTube: Liest die Datei videos.json, 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 grid = document.getElementById("yt-grid");
+ if (!grid) return;
+
+ fetch("videos.json", { cache: "no-cache" })
+ .then(function (r) {
+ if (!r.ok) throw new Error("HTTP " + r.status);
+ return r.json();
+ })
+ .then(function (ids) {
+ if (!Array.isArray(ids) || !ids.length) {
+ grid.innerHTML = '
';
+ });
+ }
+
+ function renderYouTubeGrid(videoIds) {
+ var grid = document.getElementById("yt-grid");
+ var html = "";
+ for (var i = 0; i < videoIds.length; i++) {
+ var id = String(videoIds[i]).trim();
+ if (!id) continue;
+ html +=
+ '
' +
+ '
' +
+ '' +
+ '
' +
+ '
';
+ }
+ grid.innerHTML = html || '
Keine Videos gefunden.
';
+ }
+
+ /* ------------------------------------------------------------------
+ * Twitch: Live-Player einbetten.
* ------------------------------------------------------------------ */
function loadTwitch() {
var wrap = document.getElementById("twitch-embed");
@@ -24,5 +71,8 @@
wrap.appendChild(iframe);
}
- document.addEventListener("DOMContentLoaded", loadTwitch);
-})();
+ document.addEventListener("DOMContentLoaded", function () {
+ loadYouTube();
+ loadTwitch();
+ });
+})();
\ No newline at end of file
diff --git a/fetch_videos.py b/fetch_videos.py
new file mode 100644
index 0000000..f4d082c
--- /dev/null
+++ b/fetch_videos.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+"""
+DUDA17 - YouTube Video-Liste aktualisieren
+==========================================
+Dieses Skript laeuft auf deinem Server (einmal am Tag per Cron)
+und holt automatisch die aktuellen Video-IDs deines YouTube-Kanals
+ueber die offizielle YouTube Data API v3.
+
+Es schreibt die Video-IDs in die Datei "videos.json", die deine
+Webseite dann einfach liest und anzeigt. So bleibt dein API-Key
+auf dem Server versteckt und ist NICHT im Browser/DevTools sichtbar.
+
+EINRICHTUNG:
+ 1. Setze nachfolgend API_KEY und CHANNEL_ID ein.
+ 2. Teste: python3 fetch_videos.py
+ 3. Danach einmal taeglich automatisch ausfuehren (Cron):
+ crontab -e
+ # folgende Zeile einfügen (jeden Tag um 06:00):
+ 0 6 * * * cd /PFAD/ZU/DEINER/WEBSEITE && /usr/bin/python3 fetch_videos.py
+
+ Der Pfad in der Cron-Zeile ist der Ordner, in dem auch 'videos.json'
+ abgelegt werden soll (= WebRoot-Ordner).
+"""
+
+import json
+import sys
+import os
+import urllib.request
+import urllib.parse
+
+# ---------------------------------------------------------------
+# KONFIGURATION - hier eintragen!
+# ---------------------------------------------------------------
+API_KEY = "AIzaSyC-3qzGsalOYpT_gqay1arltMGKjJYPH-8" # dein YouTube API-Key
+CHANNEL_ID = "UCC0zG_TbEEic12DQHnEGmlQ" # deine Kanal-ID
+MAX_RESULTS = 50 # wie viele Videos holen
+
+# Ordner, in den videos.json geschrieben werden soll.
+# Standard: aktuelles Verzeichnis dieses Skripts.
+# Auf dem Server: absolute Pfad zu deiner WebRoot angeben, z.B.:
+# OUT_DIR = "/var/www/html/social"
+OUT_DIR = os.path.dirname(os.path.abspath(__file__))
+# ---------------------------------------------------------------
+
+
+def get_uploads_playlist(channel_id):
+ # Uploads-Playlist eines Kanals: "UU" + Kanal-ID ohne "UC"
+ return "UU" + channel_id[2:] if channel_id.startswith("UC") else "UU" + channel_id
+
+
+def build_url(playlist_id):
+ params = {
+ "part": "snippet",
+ "playlistId": playlist_id,
+ "maxResults": str(MAX_RESULTS),
+ "key": API_KEY,
+ }
+ return "https://www.googleapis.com/youtube/v3/playlistItems?" + urllib.parse.urlencode(params)
+
+
+def fetch_json(url):
+ req = urllib.request.Request(
+ url,
+ headers={"User-Agent": "Mozilla/5.0 (Duda17-fetch)"},
+ )
+ with urllib.request.urlopen(req, timeout=30) as resp:
+ return json.loads(resp.read().decode("utf-8"))
+
+
+def main():
+ if API_KEY == "DEIN_API_KEY_HIER":
+ print("FEHLER: Setze zuerst API_KEY in fetch_videos.py", file=sys.stderr)
+ sys.exit(1)
+
+ playlist_id = get_uploads_playlist(CHANNEL_ID)
+ url = build_url(playlist_id)
+
+ print("Hole Videos von Kanal:", CHANNEL_ID)
+ print("Uploads-Playlist:", playlist_id)
+
+ data = fetch_json(url)
+
+ if "error" in data:
+ print("API-Fehler:", json.dumps(data["error"], indent=2), file=sys.stderr)
+ sys.exit(1)
+
+ items = []
+ for it in data.get("items", []):
+ snippet = it.get("snippet", {})
+ video_id = snippet.get("resourceId", {}).get("videoId")
+ if video_id:
+ items.append(
+ {
+ "id": video_id,
+ "title": snippet.get("title", ""),
+ "thumb": snippet.get("thumbnails", {}).get("high", {}).get("url", ""),
+ "published": snippet.get("publishedAt", ""),
+ }
+ )
+
+ # Neueste zuerst (die API liefert bereits chronologisch; schneller
+ # hier nach Erscheinungsdatum sortieren, um sicherzugehen)
+ items.sort(key=lambda x: x.get("published") or "", reverse=True)
+
+ # Nur die IDs in die Datei schreiben - schlank fuer die Webseite,
+ # die nur die Embed-URLs braucht.
+ video_ids = [v["id"] for v in items]
+
+ os.makedirs(OUT_DIR, exist_ok=True)
+ out_path = os.path.join(OUT_DIR, "videos.json")
+ with open(out_path, "w", encoding="utf-8") as f:
+ json.dump(video_ids, f, ensure_ascii=False, indent=2)
+
+ print(f"Erfolgreich. {len(video_ids)} Videos geschrieben nach {out_path}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/index.html b/index.html
index 6e9074e..1970d77 100644
--- a/index.html
+++ b/index.html
@@ -53,20 +53,8 @@
-