16.9.2026, 11:48
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:
Manifest si teda sťahoval klient, ktorý konektivitu na CDN má. Od 2.1.x je tam:
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
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:
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:
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.
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: ForbiddenNá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.
