• Vítejte na XBMC-Kodi.cz
  • Česko-slovenská komunita fanoušků XBMC/Kodi
Vítejte návštevníku! Přihlášení Registrace


Hodnocení tématu:
  • 6 Hlas(ů) - 3.5 Průměr
  • 1
  • 2
  • 3
  • 4
  • 5
Oneplay Server
@mmiillaa: to budou různé problémy. Zkontroluj, že v TVheadendu máš správně URL (jestli tam nemáš opravdu "paylist"), případně ho zkus normálně otevřít v prohlížeči, soubor ulož a pak se do něj podívěj, jestli obsahuje korektní playlist. Kdyby byl nějaký problém, tak mi napiš SZ, zkusíme to vyřešit bokem.
 
Citovat
V prvním příspěvku jsou ke stažení přepracovaný Oneplay Server a TVheadend skripty. Nejsou tam funkční změny, ale snažil jsem se sjednotit kód s doplňkem Oneplay. Dál jsem provedl pomocí AI refaktoring kódu. Měl by být odolnější na různé nestandardní stavy, chybějící data a případné chyby v komunikaci s Oneplay. Z doplňku Oneplay jsem mj. převzal ošetření výběru profilu, které se může objevit při přehrání.

V případě TVheadend skriptů doporučuju instalaci do čistého adresáře. Do config.txt přibily u tři nové proměnné převzaté z Oneplay Serveru. Není nutné je mít vyplněné, doporučuju konfiguraci upravit podle config.txt.sample.

Počítejte prosím s tím, že změn uvnitř bylo relativně hodně Snažil jsem se všechno otestovat, ale neobsáhnu úplně všechno. Zatím jsou nové verze k dispozici jen ke stažení  (Oneplay Server lze nainstalovat i jako doplněk v Kodi) pro případné dobrovolníky. Pokud někdo narazíte na nějakou chybu, dejte vědět, případně i napište, pokud bude všechno v pořádku. Do repozitáře (Kodi, docker) dám nové verze později.
 
Citovat
@waladir: Řekl bych, že v balíku tvheadend skriptů chybí obsah podadresářů lib, data, resources
 
Citovat
@directcz: díky za upozornění. Vypadl mi parametr při zipování. Uploadnul jsem opravený soubor.
 
Citovat
Bylo by možné opravit v nastavení IPTV odkazy tlačítka na Kopírovat. Nejsou funkční a nic nekopírují.
 
Citovat
@100karel: to bude spiš nějaký problém v prohlížeči. Tlačítka fungují přes javascript a zkoušel jsem Firefox, Chrome i Edge a kopírování odkazu fungovalo všude. Nevím jestli například javascript nemůže něco blokovat.
 
Citovat
Mě to nefunguje v žádném prohlížeči, ikdyž je čerstvě nainstalovaný, bez doplňků, anonymní režim... prostě mě to nikdy nefungovalo
 
Citovat
@100karel: zkusím se podívat na to, jak by to šlo oddebugovat. JS je ale pro mě španělská vesnice a vůbec mě nenapadá, kde by mohl být problém. Předpokládám, že jde o kopírovaní IPTV odkazů (pro playlist a EPG).
 
Citovat
Ve verzi 2.0.2 by mělo být funkční kopírování, pokud je blokované prohlížečem (díky @100karel: a @sedlin2: ). Zároveň už je i dostupná v repozitáři.

Bohužel se ještě nevytvořila nová verze v Kodi repozitáři. Je tam 2.0.1 v které je chyba. Pokud by se vám v Kodi udělal update na 2.0.1 a 2.0.2 nebyla ještě dostupná, udělejte downgrade na 1.6.2 nebo si stáhněte zip z prvního příspěvku a nainstalujte Oneplay Server z něj.
 
Citovat
V prvním příspěvku si můžete stáhnout verzi 2.1.0, v které jsou úpravy od @sedlin2: přidávají podporu timeshiftu a úpravy přetáčení. Díky nim by mělo fungovat přetáčení např. v TiviMate.Protože se tím mění způsob jak funguje přehrávání ve Oneplay Server, do repozitáře dám úpravy už začátkem příštího týdne. Ale co jsem mohl otestovat funguje.
 
Citovat
Verze 2.1.1, kde je navíc oprava načítání účtů a defaultních hodnot je už i v repozitáři. Stejné změny jsou i v TVheadend skriptech.
 
Citovat
Dobrý den, bylo by prosím možné přidat podporu Docker Compose secrets pro přihlašovací údaje Oneplay?Aktuální Docker image načítá v Docker režimu hodnoty `USERNAME` a `PASSWORD` z environment variables. Docker Compose secrets jsou ale standardně dostupné jako soubory v `/run/secrets/...`, například: 
 
Kód:
environment:
  USERNAME_FILE: /run/secrets/USERNAME
  PASSWORD_FILE: /run/secrets/PASSWORD

secrets:
  - USERNAME
  - PASSWORD

Aplikace nyní 'USERNAME_FILE' a `PASSWORD_FILE` neinterpretuje, takže musím mít user/pass v config nebo v compose. Navrhuji přidat podporu konvence `<PROMENNA>_FILE` do `get_config_value()` v `resources/lib/utils.py`.

Požadované chování:
1. Pokud je nastavena `USERNAME_FILE`, načíst obsah tohoto souboru jako hodnotu `USERNAME`.
2. Pokud je nastavena `PASSWORD_FILE`, načíst obsah tohoto souboru jako hodnotu `PASSWORD`.
3. Hodnota z `*_FILE` má přednost před přímou proměnnou `USERNAME` / `PASSWORD`.
4. Pokud `*_FILE` není nastaveno, zachovat stávající chování beze změny.
5. Odstranit pouze koncový LF/CRLF ze souboru se secretem.
6. Při nečitelném nebo neexistujícím souboru skončit s jasnou chybou, aby nedošlo k tichému přihlášení s prázdným nebo chybným údajem.

Tím bude image kompatibilní s Docker Compose secrets, Docker Swarm secrets a běžnou `_FILE` konvencí používanou mnoha Docker images.

Níže přikládám návrh minimální změny. Změny jsem otestoval u sebe a fungují jak při použití USERNAME tak i USERNAME_FILE resp. PASSWORD i PASSWORD_FILE. Tento návrh je schválně obecný, nepodporuje jen USERNAME_FILE a PASSWORD_FILE ale i AUTH_PASS_FILE nebo PIN_FILE atp. aniž by se musela stejná logika kopírovat.
 
Kód:
def get_config_value(setting):
     if is_kodi():
         import xbmcaddon

         return xbmcaddon.Addon().getSetting(setting)

     config_file = os.path.join(get_script_path(), 'config.txt')
     defaults = {
         'WEBSERVER_IP': '0.0.0.0',
         'WEBSERVER_PORT': 8082,
         'EPG_DNU_ZPETNE': 1,
         'EPG_DNU_DOPREDU': 1,
         'INTERVAL_STAHOVANI_EPG': 0,
         'ODSTRANIT_HD': 0,
         'POUZIVAT_CISLA_KANALU': 0,
         'PORADI_SLUZBY': -1,
         'PIN': '4321',
         'PROFILE_PIN': '4321',
         'DEBUG': 0,
         'CESTA_FFMPEG': '/usr/bin/ffmpeg',
         'AUTH_USER': '',
         'AUTH_PASS': '',
     }

     if is_docker() and not os.path.exists(config_file):
-        return os.getenv(setting.upper(), defaults.get(setting.upper()))
+        env_name = setting.upper()
+        secret_file = os.getenv(f'{env_name}_FILE')
+
+        if secret_file:
+            try:
+                with open(secret_file, encoding='utf-8') as file:
+                    return file.read().rstrip('\r\n')
+            except OSError as error:
+                raise RuntimeError(
+                    f'Cannot read Docker secret from {env_name}_FILE: {secret_file}'
+                ) from error
+
+        return os.getenv(env_name, defaults.get(env_name))

     with open(config_file, encoding='utf-8') as file:
         return json.load(file).get(setting, defaults.get(setting.upper()))

Jak bude fungovat Compose
 
Kód:
services:
  oneplayserver:
    image: XXXX/oneplayserver:verze-s-podporou-secrets

    environment:
      USERNAME_FILE: /run/secrets/USERNAME
      PASSWORD_FILE: /run/secrets/PASSWORD
      DEVICEID: atv34
      WEBSERVER_IP: 192.168.X.X
      WEBSERVER_PORT: 8082

    secrets:
      - USERNAME
      - PASSWORD

secrets:
  USERNAME:
    file: /share/Docker_data/secrets/O2TV/USERNAME
  PASSWORD:
    file: /share/Docker_data/secrets/O2TV/PASSWORD
  
Aplikace pak při volání najde nejdříve USERNAME_FILE a PASSWORD_FILE, načte obsah těchto souborů a vrátí jej jako hodnotu uživatelského jména a hesla. Současné nasazení s běžnými proměnnými USERNAME a PASSWORD zůstane plně kompatibilní.
 
Citovat
@rasti: přidám to do další verze jako variantu. Pro jednoduchost nechám docker-compose.yml v repozitáři jak je, ale v kódu bude přidaná podpora načítání ze secrets souborů.
 
Citovat
Ve verzi 2.1.1 je opravená chyba při volání timeshiftu u živého vysílání a přidaná podpora secrets souburů v dockeru.
 
Citovat
(08.9.2026, 21:10)waladir Napsal(a): Ve verzi 2.1.1 je opravená chyba při volání timeshiftu u živého vysílání a přidaná podpora secrets souburů v dockeru.

Perfektne, docker secrets funguje, diky za rychlou reakci
 
Citovat
Bohužel mi včera omylem vypadla oprava timeshiftu. Opravené je to ve verzi 2.1.3.
 
Citovat
Ve verzi 2.1.4 je opravené disablování při refreshi kanálů
 
Citovat
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.
 
Citovat
@andrebas: díky za podrobnou analýzu i s návrhy řešení. Asi půjdu cestou fallbacku, ať se nemusí přidávat nějaké další nastavení. Vrácení 500 je standardní chování, resp. důsledek neošetřené výjimky, která by měla být pak v logu. Někdy je i lepší, když ošetřená není, protože je hned na první pohled vidět, kde je problém :-)
 
Citovat
(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
 
Citovat
  


Přejít na fórum:


Prochází: 2 host(ů)