feat(savetv): direkter Download via Hetzner-IP statt Cloudflare

- SAVETV_DIRECT_BASE / SAVETV_TUNNEL_BASE Konstanten eingefuegt
- Downloads-Seite: gruener Download-Button -> Hetzner :9443 (ohne CF, Basic-Auth mike)
- CF-Fallback-Link pro Zeile -> savetv.orbitalo.net (Cloudflare-Tunnel)
- Infobox mit URL, Auth-Hinweis und CF-Erlaeuterung unterhalb der Dateianzahl
This commit is contained in:
Homelab Cursor 2026-03-28 18:43:08 +01:00
parent 1527b86cbb
commit ba13fc2659

View file

@ -18,6 +18,10 @@ JELLYFIN_URL = _os.environ.get("JELLYFIN_URL", "http://100.77.105.3:8096")
JELLYFIN_USER = _os.environ.get("JELLYFIN_USER", "admin")
JELLYFIN_PASS = _os.environ.get("JELLYFIN_PASS", "astral66")
# Direkter Download ohne Cloudflare (Hetzner :9443 → nginx → CT 116)
SAVETV_DIRECT_BASE = _os.environ.get("SAVETV_DIRECT_BASE", "http://138.201.84.95:9443")
SAVETV_TUNNEL_BASE = _os.environ.get("SAVETV_TUNNEL_BASE", "https://savetv.orbitalo.net")
def _normalize_film_title(s: str) -> str:
"""Gleiche Logik wie normTitle() in savetv_web.js fuer Abgleich."""
@ -177,6 +181,8 @@ def register_extra_routes(app, progress_lock=None, load_progress_raw=None, save_
clean = name.rsplit(".", 1)[0]
esc = _html.escape(name, quote=True)
date_str = _dt.fromtimestamp(mtime).strftime("%d.%m.%Y")
href_direct = SAVETV_DIRECT_BASE.rstrip("/") + "/files/" + _urlquote(name)
href_tunnel = SAVETV_TUNNEL_BASE.rstrip("/") + "/files/" + _urlquote(name)
rows += (
'<tr data-name="' + _html.escape(clean.lower(), quote=True) + '" '
'data-date="' + str(int(mtime)) + '" '
@ -185,9 +191,11 @@ def register_extra_routes(app, progress_lock=None, load_progress_raw=None, save_
'<td style="padding:16px 20px;color:#666;font-size:14px;white-space:nowrap">' + date_str + '</td>'
'<td style="padding:16px 20px;color:#888;font-size:15px;white-space:nowrap">' + str(size) + ' MB</td>'
'<td style="padding:16px 20px;white-space:nowrap">'
'<a href="/files/' + _urlquote(name) + '" download="' + esc + '" '
'<a href="' + href_direct + '" download="' + esc + '" '
'style="background:#4caf92;color:#000;font-weight:700;padding:8px 20px;border-radius:5px;text-decoration:none;font-size:15px">'
'&#11015; Download</a> '
'<a href="' + href_tunnel + '" title="Cloudflare-Tunnel" '
'style="color:#5a7fa8;font-size:13px;font-weight:600;margin-left:8px;text-decoration:none">CF</a> '
'<button data-file="' + esc + '" onclick="delFile(this)" '
'style="background:#ff3d3d;color:#fff;font-weight:700;padding:8px 16px;border-radius:5px;border:none;cursor:pointer;font-size:15px;margin-left:10px">'
'&#128465; L\u00f6schen</button>'
@ -213,6 +221,13 @@ def register_extra_routes(app, progress_lock=None, load_progress_raw=None, save_
+ nav +
'<h1>&#128193; Gespeicherte Filme</h1>'
'<div class="sub">' + str(len(files)) + ' Dateien &middot; ' + str(total_gb) + ' GB</div>'
'<div class="sub" style="margin-top:16px;padding:12px 16px;background:#1a1a24;border:1px solid #2a2a3a;border-radius:8px;font-size:14px;max-width:1100px;line-height:1.55">'
'Direkt vom Hetzner (ohne Cloudflare): Download-Links zeigen auf '
'<code style="color:#e0e0e8">' + _html.escape(SAVETV_DIRECT_BASE, quote=True) + '</code> &mdash; '
'Basic-Auth mit Benutzer <code>mike</code>, Passwort wie in <code>homelab.conf</code>. '
'Fallback: Link <span style="color:#888">CF</span> pro Zeile (Cloudflare-Tunnel, '
'<code style="color:#e0e0e8">' + _html.escape(SAVETV_TUNNEL_BASE, quote=True) + '</code>).'
'</div>'
'<div class="sortbar"><span>Sortieren:</span>'
'<button class="sbtn active" data-sort="date" data-dir="desc" onclick="sortBy(this)">Datum <span class="arrow">&#9660;</span></button>'
'<button class="sbtn" data-sort="name" data-dir="asc" onclick="sortBy(this)">Name <span class="arrow">&#9650;</span></button>'