fix Youtube
This commit is contained in:
62
app.js
62
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 = '<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
118
fetch_videos.py
Normal 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()
|
||||
16
index.html
16
index.html
@@ -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">
|
||||
|
||||
12
style.css
12
style.css
@@ -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
10
videos.json
Normal file
@@ -0,0 +1,10 @@
|
||||
[
|
||||
"HPEbsIInMEg",
|
||||
"4I8ay7l4Gfk",
|
||||
"AZycMlj2FJc",
|
||||
"lpClI8-7S7E",
|
||||
"C5O9fwbMCvc",
|
||||
"8TJGbSExWTc",
|
||||
"KIpWKm5puIw",
|
||||
"HPKnQa6Dv4k"
|
||||
]
|
||||
Reference in New Issue
Block a user