fix Youtube

This commit is contained in:
nadja
2026-09-01 22:46:53 +02:00
parent 1162939720
commit bec7910eff
5 changed files with 193 additions and 25 deletions

60
app.js
View File

@@ -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 = '<div class="loading">Noch keine Videos vorhanden.</div>';
return;
}
renderYouTubeGrid(ids);
})
.catch(function () {
grid.innerHTML =
'<div class="loading error">Videos konnten nicht geladen werden.</div>';
});
}
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 +=
'<div class="video-card">' +
'<div class="video-wrapper">' +
'<iframe src="https://www.youtube.com/embed/' + id +
'" title="Duda17 Video" ' +
'frameborder="0" allow="accelerometer; autoplay; clipboard-write; ' +
'encrypted-media; gyroscope; picture-in-picture; web-share" ' +
'referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>' +
'</div>' +
'</div>';
}
grid.innerHTML = html || '<div class="loading">Keine Videos gefunden.</div>';
}
/* ------------------------------------------------------------------
* 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();
});
})();

118
fetch_videos.py Normal file
View File

@@ -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()

View File

@@ -53,20 +53,8 @@
</div>
</div>
<div class="video-grid">
<!-- Offizieller YouTube Embed: zeigt automatisch die neuesten
Uploads des Kanals. YouTube hostet alles selbst - kein
CORS, kein API-Key, keine externen Dienste noetig und
neue Videos erscheinen automatisch. -->
<div class="video-card video-card-wide">
<div class="video-wrapper">
<iframe src="https://www.youtube.com/embed?listType=user_uploads&list=UU0zG_TbEEic12DQHnEGmlQ"
title="Duda17 - YouTube Uploads"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
</div>
<div id="yt-grid" class="video-grid">
<div class="loading">Lade YouTube-Videos…</div>
</div>
<div class="section-cta">

View File

@@ -170,11 +170,6 @@ body {
gap: 24px;
}
/* Der YouTube-Uploads-Player (alle Videos) soll die volle Breite nutzen */
.video-card-wide {
grid-column: 1 / -1;
}
.video-card {
background: var(--bg-card);
border-radius: 16px;
@@ -236,6 +231,13 @@ body {
color: var(--tiktok-pink);
}
.loading code {
background: var(--bg-card);
padding: 2px 6px;
border-radius: 6px;
color: var(--tiktok-cyan);
}
/* TikTok Embed */
.tiktok-embed-wrap {
background: var(--bg-card);

10
videos.json Normal file
View File

@@ -0,0 +1,10 @@
[
"HPEbsIInMEg",
"4I8ay7l4Gfk",
"AZycMlj2FJc",
"lpClI8-7S7E",
"C5O9fwbMCvc",
"8TJGbSExWTc",
"KIpWKm5puIw",
"HPKnQa6Dv4k"
]