16.9.2026, 14:11
(16.9.2026, 11:48)andrebas Napsal(a): Ahoj, narazil som na problém s /play/ a myslím, že mám aj návrh riešenia.
Problém
Endpoint /play/ mi vracia 500 Internal Server Error pre všetky kanály. /stream_url/ pritom funguje normálne a vráti platnú URL.
Príčina
Server, na ktorom beží doplnok, má výstupnú IP v datacentrovom rozsahu a CDN (CETIN) ju odmieta — pri sťahovaní manifestu dostane HTTP 403. Overil som to: rovnaká URL a rovnaký token v tej istej chvíli dá z tohto stroja 403, ale z inej siete 200. Token na IP viazaný nie je (pole sip je prázdne), takže rozhoduje výhradne to, odkiaľ ide HTTP požiadavka.
Do 2.0.2 to nevadilo, lebo /play/ robil len:
Kód:return redirect(stream)
Manifest si teda sťahoval klient, ktorý konektivitu na CDN má. Od 2.1.x je tam:
Kód:return rewrite_manifest(stream, get_base_url())
Manifest sťahuje server sám, urlopen() vyhodí HTTPError 403, tá nie je nikde ošetrená a bottle to vráti ako 500. Rovnako sa správa aj /proxy_hls.
Traceback
Kód:File "/usr/lib/python3.11/urllib/request.py", line 643, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden
Návrh riešenia
Všimol som si, že pri živom vysielaní bez timeshiftu (offset_seconds == 0) robí rewrite_manifest() vlastne len dve veci — prepíše URI na absolútne a pridá #EXT-X-START:TIME-OFFSET=-3. Proxovanie cez /proxy_hls sa zapína až pri use_proxy, teda pri offsete. Pre bežné živé vysielanie teda nie je nutné manifest sťahovať na serveri.
Napadli ma tri možnosti, od najjednoduchšej:
1) Prepisovať manifest len keď treba — pri timeshift == 0 sa vrátiť k redirectu:
Kód:if timeshift > 0:
return rewrite_manifest(stream, get_base_url(), timeshift)
return redirect(stream)
Stratí sa tým len tá trojsekundová korekcia štartu, ktorú si vie klient doriešiť sám.
2) Automatický fallback — nechať pokus o prepis, ale pri zlyhaní spadnúť na redirect:
Kód:try:
return rewrite_manifest(stream, get_base_url())
except (HTTPError, URLError):
return redirect(stream)
Toto mi príde najelegantnejšie, lebo to rieši aj iné výpadky CDN a nič netreba konfigurovať.
3) Prepínač v konfigurácii, napr. prepisovat_manifest 0/1, pre tých, čo si chcú vynútiť staré správanie.
A nezávisle od toho by som prosil ošetriť výnimku z urlopen() v rewrite_manifest() aj /proxy_hls a vrátiť čitateľnú hlášku (napr. 502 s HTTP kódom od CDN). Holá 500 bez akejkoľvek informácie vedie k tomu, že človek hľadá chybu úplne inde — mňa to stálo dosť času, kým som sa dostal k tracebacku.
Chápem, že blokovaná IP je špecifikum môjho nastavenia a nie chyba doplnku. Ale scenár, keď klient má na CDN prístup a server nie, asi nebudem mať len ja — a do 2.0.2 fungoval bez problémov.
Verzia: 2.1.4, beží priamo na Debiane (nie Docker), Python 3.11, bottle 0.12.23.
Vopred vďaka za pohľad na to.
Ahoj,
proxování manifestu má své výhody.
Každopádně řešení č.2 je super nápad - jen bych kód trochu rozšířil - napřiklad takto:
Kód:
from urllib.error import HTTPError, URLError
try:
return rewrite_manifest(stream, get_base_url())
except HTTPError as e:
if e.code == 403:
return redirect(stream)
# Vrátí konkrétní HTTP chybu (např. 404, 500 atd.) s chybovou zprávou
return HTTPResponse(body=str(e), status=e.code)
except URLError as e:
# Problémy se sítí (Internal Server Error)
return HTTPResponse(body=str(e), status=500)Sedlin2
