Systém modulů Streamlet

Úvod

Tento dokument popisuje, jak v projektu Streamlet vytvářet a integrovat moduly formou JSON konfigurací. Cílem je, aby vývojář mohl přidat nové zdroje dat katalogů a streamů (API i scraper moduly) pro filmy a seriály.

  • Dva typy modulů:
    • API moduly - volají HTTP API (JSON/XML) a mapují odpovědi.
    • Scraper moduly - stahují HTML stránky a extrahují data pomocí CSS selektorů a malého DSL.
  • Šifrované moduly (.slet) - aplikace podporuje i šifrované json moduly ve formátu .slet pro ochranu proprietárního kódu. Šifrování modulů je možné provést na https://streamlet.info/encrypt/.

Společná metadata modulu (top‑level JSON)

Každý modul (API i Scraper) začíná základními metadaty. Příklady viz TMDB (API katalog), ČSFD (scraper katalog), Webshare (API streamy).

  • id: unikátní identifikátor modulu (např. "tmdb", "csfd").
  • media: pole typů obsahu, které modul podporuje - ["movies", "series"].
  • type: seznam schopností modulu - ["catalogues", "details", "stream"].
  • name, website, author, description: informační pole pro UI a katalog.
  • version, repository: definice repozitáře (url) a verze - po změně verze dojde k automatciké aktualizaci v aplikaci.
  • baseUrl: základ URL pro všechny endpointy modulu. Nově podporuje placeholdery (např. https://api.example.com/{catalogueLanguage}, {token:authToken}, {apiKey}), které se před voláním nahradí.
  • responseFormat:
    • API moduly: "json" nebo "xml" (default json).
    • Scraper moduly: "scraper".
  • headers: volitelné HTTP hlavičky přidávané ke všem požadavkům (API i Scraper).
  • userAgent: volitelný UA string pro Scraper modul (pokud není uveden, použije se výchozí desktop UA).
  • config: definice konfiguračních položek (např. přihlašovací údaje nebo API klíče). Struktura:
    • Každá položka má: type ("string"/"password"), label, default, required (bool).

Příklad (zjednodušený):

{
    "id": "tmdb",
    "media": ["movies", "series"],
    "type": ["catalogues", "details"],
    "name": "TMDB",
    "baseUrl": "https://api.themoviedb.org/3",
    "responseFormat": "json",
    "headers": { "accept": "application/json", "Authorization": "Bearer ..." },
    "config": {
        "apiKey": { "type": "string", "label": "API Key", "required": false }
    }
}
            

Konvence endpointů a placeholderů

V obou typech modulů se nadále používají pojmenované „typy“ endpointů, které Streamlet umí zpracovat a namapovat:

  • Katalogy a vyhledávání: catalogue_movies, catalogue_series, search_movies, search_series
  • Detaily: movie_detail, series_detail, series_episodes (epizody konkrétní sezóny)
  • Streamy: stream_search (vyhledání souborů/zdrojů), serviceId (volitelný - získání service ID pro stream provider), link (získání stream linku pro konkrétní id)

Běžné placeholdery v URL a tělech požadavků:

  • Paging a jazyk: {page}, {catalogueLanguage}
  • Identifikátory: {id}, {movieId}, {seriesId}, {seasonNumber}
  • Hledání: {what}, {title}, {searchTerm}
  • Tokeny po autentizaci: {token:authToken} (viz Autentizace)
  • Media parametry: {tmdbId}, {imdbId}, {year}, {originalTitle} (dostupné při vyhledávání streamů)
  • Service ID: {serviceId} (dostupný po volání serviceId endpointu)

Placeholdery nahrazuje aplikace automaticky – fungují jak v URL, tak v tělech požadavků.

Placeholder systém

Placeholdery se nahrazují ve dvou oblastech: v URL/tělech endpointů a v textových labelech (přes vícejazyčnou podporu aplikace).

Endpoint placeholdery

Aplikace podporuje následující placeholdery v URL i tělech požadavků:

{id}
Obecný identifikátor (film/seriál/epizoda) – předává se explicitně parametrem id.
{page}
Číslo stránky (1‑n). Pokročilá varianta: {page(offset,limit)} (dříve {page(start,multiplier)}). Vrací offset: page=1 → offset, page>1 → offset + (page-1) * limit. Příklad: {page(0,50)} → 0, 50, 100…; použijte např. offset={page(0,50)}. (Změna: již se nepoužívá samostatné start + offset.)
{catalogueLanguage}, {appLanguage}, {subtitlesLanguage}, {audioLanguage}
Jazykové kódy předané z aplikace (např. cs-CZ, en-US).
Vlastní placeholdery
  • customPlaceholders: mapa "key" → "value", nahrazuje {key}.
  • customParams: libovolné typy hodnot – aplikace je převede na řetězec a nahradí {key} (podporuje čísla i boolean).

Aplikace rozpozná přítomnost placeholderu {page} (včetně varianty s parametry) a podle toho řídí stránkování.

Auth token placeholdery

Po autentizaci API modulu lze do URL/těl vkládat tokeny:

  • {token:<key>} – např. {token:authToken}; nahradí se hodnotou uloženou během auth kroků.
  • „Přímé“ token klíče – pokud řetězec obsahuje {authToken} nebo cokoliv končící na Token, pokusí se nahradit z uložených tokenů.

Náhrady tokenů probíhají i uvnitř vnořených struktur (řetězce, mapy, seznamy).

Překlady textů

Aplikace umí překládat známé textové klíče v závorkách {...} (např. v popisech, labelech nastavení). Pokud jsou složené závorky vypnuté, je celý řetězec brán jako klíč překladu. Podporované příklady: media, catalogues, movies, series, search, appLanguage, popularMovies, topRatedMovies, popularSeries, topRatedSeries, apiKey, username, usernameEmail, password a řada žánrů (action, adventure, comedy, …). Konkrétní zobrazované texty závisejí na zvoleném jazyce aplikace.

API moduly

API modul definuje pole api s listem endpointů. Každý endpoint typicky obsahuje:

  • name: volitelný popisný název (pro UI).
  • type: viz „Konvence endpointů“.
  • method: GET nebo POST.
  • url: relativní cesta (bude připojena k baseUrl), může obsahovat placeholdery.
  • body: volitelné - objekt klíč=hodnota pro POST (placeholdery se vyhodnotí a odešlou jako application/x-www-form-urlencoded).
  • response: nastavení parsování odpovědi
    • itemsKey: cesta k poli položek v odpovědi (pro listové endpointy). Pokud chybí a odpověď je pole, použije se přímo.
    • mapping: mapování polí z odpovědi na interní klíče (viz Mapování dat níže).
    • status: volitelné mapování stavů na chyby - { path: "...", states: { ok: "OK", autherror: "LOGIN_FATAL_1", ... } }.
  • imageBaseUrl / posterBaseUrl / backdropBaseUrl: volitelná základna pro skládání URL obrázků na úrovni endpointu. Nově podporují placeholdery (jazyk, token, API klíč), např. "imageBaseUrl": "https://cdn.example.com/{catalogueLanguage}/img".

Příklad list endpointu (zkrácený):

{
    "type": "search_movies",
    "method": "GET",
    "url": "/search/movie?query={what}&language={catalogueLanguage}&page={page}",
    "response": {
        "itemsKey": "results",
        "mapping": {
            "id": "id",
            "title": "title",
            "poster": "poster_path",
            "rating": "vote_average"
        }
    },
    "imageBaseUrl": "https://image.tmdb.org/t/p/w500"
}
            

Scraper moduly

Scraper modul definuje pole scraper s listem endpointů. Každý endpoint obsahuje:

  • type: viz „Konvence endpointů“.
  • name: volitelný popis pro UI.
  • url: absolutní nebo relativní cesta (pokud začíná /, připojí se baseUrl). Může obsahovat placeholdery.
  • mapping: mapování názvů polí na selektory/DSL výrazy. Tyto klíče odpovídají mapovacím klíčům (např. id, title, poster, rating, link, atd.).
  • imageBaseUrl / posterBaseUrl / backdropBaseUrl: volitelné základny pro skládání URL obrázků. Nově podporují placeholdery (např. {catalogueLanguage}, {token:authToken}). Pole elements bylo sjednoceno do mapping – starší moduly přejmenujte.

Extraktor automaticky rozpoznává, zda jde o seznam (typy začínající catalogue_ nebo search_) nebo detail.

Poznámky k seznamům:

  • Scraper se pokusí najít „kontejnery“ položek heuristicky (article, .item, .card, li, tr, …).
  • Selektory v mapping se při listových endpointech aplikují relativně k jednotlivé nalezené položce. Doporučuje se používat krátké relativní selektory (např. a.title, img.poster, span.rating).
  • Pokud kontejner nelze spolehlivě detekovat, extraktor se pokusí vyčíst data jako „single“ a výsledek zabalí do seznamu.

Selektorové DSL (Scraper)

Kromě běžných CSS selektorů lze použít rozšíření:

  • selector(query) - vrátí text prvního elementu dle CSS selektoru.
  • selectorAll(query) - vrátí list textů všech odpovídajících elementů.
  • attribute(query, attr) - vrátí hodnotu atributu attr z elementu nalezeného query.
  • attribute(attr) - speciální varianta pro „aktuální“ element (v režimu listu je to položka). Vrátí hodnotu atributu přímo z něj.
  • attributeAll(query, attr) - list všech hodnot atributů attr z elementů dle query.
  • regex(baseSelector, pattern, groupIndex) - vyhledá text (nebo atribut - viz níže) a aplikací regulárního výrazu vrátí skupinu groupIndex (default 0). pattern uzavírejte do uvozovek.
    • baseSelector může být: selector(...), text(...), attribute(query, attr), attribute(attr), nebo přímý CSS selektor na text.
  • regex_replace(baseSelector, pattern, replacement) - jako výše, ale provede nahrazení a vrátí upravený text.
  • Podpora :not(...) - pro složitější selekce (např. vyřazení potomků z textu). Implementace najde základní selektor a odstraní podstromy odpovídající :not().

Příklady selektorů:

"title": "selector(h1.movie-title)"
"poster": "attribute(img.poster, src)"
"genres": "selectorAll(.genres a)"  // list hodnot
"rating": "regex(selector(.rating), '([0-9]+\.?[0-9]*)', 1)"
"plot": "selector(.plot-full p:not(em.span-more-small))"
            

Mapování dat do interních modelů

Interní mapování probíhá v následujících mapperech. Fallback logika: pokud klíč není v mapping definován, mapper použije vestavěný výchozí název pole (např. posterPath → poster_path, rating → vote_average). ID hodnoty se vždy převádějí bezpečně na String. Seznamy jsou získány z pole objektů (genres[name]) nebo ze stringu (rozdělením podle , ; /). Dynamické placeholdery {{endpoint_type}} se vyhodnotí před mapováním a injektované výsledky lze pak číst standardně pod daným klíčem.

  • CatalogItemMapper (katalogy a vyhledávání):
    • Klíče: id, title, poster/posterPath, rating, link, volitelně releaseDate, genres.
    • poster může být relativní cesta (kombinuje se s imageBaseUrl/posterBaseUrl) nebo absolutní URL.
    • genres akceptuje pole objektů (genres[name]) i jednoduchý string (rozdělí se).
    • Výsledný model: CatalogItem (doplní se mediaType z endpointu a sourceModuleId).
  • MovieDetailMapper (detail filmu):
    • Klíče: id, title, originalTitle, tmdbId, imdbId, overview, tagline, status, releaseDate, runtime, popularity, rating, posterPath, backdropPath, homepage, revenue, budget, adult, seznamy: genres, originCountry, productionCompanies, productionCountries, spokenLanguages, actors, originalLanguage.
    • runtime se parsuje z formátů typu "142", "142 min", "2h 20m".
    • ID vždy převedeno na String (podporuje int). posterPath/backdropPath kombinují base URL pokud není absolutní.
  • SeriesDetailMapper (detail seriálu):
    • Klíče: id, title/name, originalTitle/originalName, numberOfSeasons, numberOfEpisodes, overview, tagline, status, firstAirDate, lastAirDate, popularity, rating, posterPath, backdropPath, homepage, adult, seznamy: genres, originCountry, productionCompanies, productionCountries, spokenLanguages, languages, networks, createdBy, episodeRunTime (list int), seasonsUrls (list string).
    • Inference: pokud numberOfSeasons chybí, dopočítá se z délky pole seasons. Pokud numberOfEpisodes chybí, sečtou se episodeCount každé sezóny.
    • ID a číselné počty jsou robustně parsovány (int nebo string).
  • SeriesEpisodesMapper (epizody sezóny):
    • Klíče: id, showId, seasonNumber, episodeNumber, name, overview, airDate, rating/vote_average, stillPath, episodeType, runtime.
    • ID i showId vždy jako String. Číselné hodnoty bezpečně parsovány ze stringu.
  • StreamModelMapper (výsledky stream vyhledávání):
    • Klíče: id, title, name, type, size (string/number → double), ratingUp, ratingDown, seeds, info, audioLanguages, subtitleLanguages, hash, custom.
    • size převod string/number → double, vote counts a seeds → int (fallback 0).
    • Jazykové seznamy musí být pole; prvky se převádějí na string.

Nové možnosti: episodeMapping (u kombinovaných seriálových endpointů), dynamické injektování {{endpoint_type}}, placeholdery v baseUrl a *BaseUrl. Přidáním dalších klíčů do mapping nikdy „nerozbijete“ mapper – neznámé klíče jsou ignorovány.

Cesty v mapování (path syntax)

Pro API moduly se používá dot‑notace a speciální zápis pro pole:

  • Jednoduché pole: "title": "title", "id": "id".
  • Vnoření: "crewName": "crew.0.name".
  • Extrakce hodnot z pole objektů: genres[name] vrátí list hodnot name ze všech objektů v genres.
  • Pokud extractStringList() dostane String, rozseká jej na seznam podle ,/;//.

Scraper moduly nepoužívají „path“ přes JSON, ale přímo vracejí cílové klíče pomocí mapping a selektorového DSL.

Obrázky: poster/backdrop/image URL

URL obrázků se skládají utilitou ImageUtils.buildUrl(...):

  • Pokud je hodnota již absolutní URL, použije se přímo.
  • Jinak se vezme hodnota z endpointu (posterBaseUrl/backdropBaseUrl/imageBaseUrl) nebo z modulu a připojí se relativní cesta.
  • Pro Scraper moduly je logika skládání adres shodná – použije se základna a relativní cesta.

V mapování proto dbejte na to, aby poster/posterPath resp. backdropPath vracely relativní cestu, pokud používáte base URL; nebo absolutní URL, pokud je chcete použít přímo.

Zpracování chyb

Aplikace automaticky zpracovává chybové stavy z API a scraper modulů. Chybové kódy se normalizují a převádějí na uživatelsky přívětivá hlášení.

Pro úplný seznam podporovaných chybových kódů, jejich významů a zobrazení v UI viz Kompletní reference chybových kódů.

Příklad mapování chyb v endpointu

{
    "response": {
        "status": {
            "path": "response.code",
            "states": {
                "ok": "OK",
                "userNotFound": "user_not_found",
                "invalidPassword": "invalid_credentials",
                "serverError": "server_error"
            }
        }
    }
}
            

Aplikace vyhodnotí hodnotu na cestě path a převede ji podle states na standardizovaný chybový kód, který se zobrazí s příslušnou ikonou, barvou a zprávou.

Autentizace API modulů

API moduly mohou vyžadovat autentizaci pro přístup k chráněným zdrojům. Streamlet podporuje dva hlavní způsoby autentizace:

  1. API klíč v URL nebo hlavičce - jednoduchá statická autentizace
  2. Vícekrokový auth proces - složitější autentizace s tokenem (např. login/password)

1. API klíč v konfiguraci

Nejjednodušší způsob autentizace je pomocí API klíče, který uživatel zadá v nastavení modulu. Klíč lze použít dvěma způsoby:

a) API klíč v URL (jako query parametr)

{
    "config": {
        "apiKey": {
            "type": "string",
            "target": "endpoint",
            "label": "{apiKey}",
            "default": "",
            "fullValue": "?api_key={apiKey}",
            "required": true
        }
    }
}
            

Klíč target: "endpoint" říká, že hodnota se připojí přímo k URL endpointu. Parametr fullValue definuje, jak bude klíč vložen (včetně query stringu).

b) API klíč v hlavičce

{
    "headers": {
        "accept": "application/json",
        "Authorization": "Bearer YOUR_API_KEY_HERE"
    },
    "config": {
        "apiKey": {
            "type": "string",
            "label": "{apiKey}",
            "required": false
        }
    }
}
            

API klíč lze přímo zakódovat do headers, nebo ho nechat uživatele zadat v konfiguraci a použít jako placeholder.

2. Vícekrokový autentizační proces

Pro služby vyžadující login a heslo použijte sekci auth s polem steps. Každý krok je API požadavek, který může:

  • Uložit mezivýsledky (např. salt) pro použití v dalším kroku
  • Získat autentizační token pro následné požadavky
  • Kontrolovat chybové stavy a převádět je na srozumitelné kódy

Struktura auth kroku

name
Popisný název kroku (např. "salt", "login")
method
HTTP metoda: GET nebo POST
url
URL endpointu (relativní k baseUrl)
body
Tělo požadavku (objekt klíč=hodnota). Může obsahovat:
  • Placeholdery z config: {login}, {password}
  • Uložené hodnoty z předchozích kroků: {salt}
  • Speciální funkce: sha1(md5_crypt({password}, {salt}))
response
Nastavení zpracování odpovědi:
  • storeAs: název pro uložení mezivýsledku (použitelný v dalších krocích)
  • path: cesta k hodnotě v odpovědi (dot-notace)
  • tokenPath: cesta k autentizačnímu tokenu v odpovědi
  • status: mapování stavových kódů na chyby (viz níže)
storeTokenAs
Název klíče, pod kterým se uloží token pro použití v endpointech (např. "authToken")

Příklad: Webshare.cz autentizace (2 kroky)

{
    "config": {
        "login": {
            "type": "string",
            "label": "{usernameEmail}",
            "required": true
        },
        "password": {
            "type": "password",
            "label": "{password}",
            "required": true
        }
    },
    "auth": {
        "steps": [
            {
                "name": "salt",
                "method": "POST",
                "url": "/salt/",
                "body": {
                    "username_or_email": "{login}"
                },
                "response": {
                    "storeAs": "salt",
                    "path": "response.salt",
                    "status": {
                        "path": "response.code",
                        "states": {
                            "ok": "OK",
                            "userNotFound": "user_not_found"
                        }
                    }
                }
            },
            {
                "name": "login",
                "method": "POST",
                "url": "/login/",
                "body": {
                    "username_or_email": "{login}",
                    "password": "sha1(md5_crypt({password}, {salt}))",
                    "keep_logged_in": "1"
                },
                "response": {
                    "tokenPath": "response.token",
                    "status": {
                        "path": "response.code",
                        "states": {
                            "autherror": "authentication_error"
                        }
                    }
                },
                "storeTokenAs": "authToken"
            }
        ]
    }
}
            

3. Použití tokenů v endpointech

Po úspěšné autentizaci lze uložené tokeny použít v URL i tělech požadavků pomocí placeholderů:

  • {token:authToken} - formát token:názevKlíče
  • {authToken} - přímý název klíče (pokud končí na "Token")

Příklad použití v URL

{
    "type": "stream_search",
    "url": "/api/search?token={token:authToken}&query={what}"
}
            

Příklad použití v těle požadavku

{
    "type": "stream_search",
    "method": "POST",
    "url": "/search/",
    "body": {
        "what": "{title}",
        "wst": "{token:authToken}",
        "limit": "50"
    }
}
            

4. Service ID endpoint (volitelný)

Pro stream moduly, které vyžadují získání service ID před vyhledáváním streamů, lze definovat volitelný endpoint typu serviceId:

{
    "name": "get_service_id",
    "type": "serviceId",
    "method": "GET",
    "url": "/service/tmdb/{tmdbId}",
    "response": {
        "mapping": {
            "serviceId": "response.service_id"
        }
    }
}
            

Pokud tento endpoint existuje, aplikace ho automaticky zavolá před stream_search a získaný serviceId bude dostupný jako placeholder {serviceId} pro další endpointy:

{
    "name": "search",
    "type": "stream_search",
    "method": "POST",
    "url": "/search/",
    "body": {
        "what": "{title}",
        "service_id": "{serviceId}",
        "tmdb_id": "{tmdbId}",
        "year": "{year}",
        "wst": "{token:authToken}"
    }
}
            

Endpoint serviceId je zcela volitelný - pokud není definován, vyhledávání streamů funguje normálně bez něj. Do tohoto endpointu se automaticky předávají všechny dostupné media parametry (tmdbId, imdbId, year, originalTitle, atd.).

5. Stavové kódy a chyby

Každý auth krok i běžný endpoint může definovat response.status pro mapování chybových stavů:

"response": {
    "status": {
        "path": "response.code",
        "states": {
            "ok": "OK",
            "userNotFound": "user_not_found",
            "invalidPassword": "invalid_credentials",
            "autherror": "authentication_error",
            "rateLimited": "rate_limited"
        }
    }
}
            

Aplikace vyhodnotí hodnotu na cestě path a pokud odpovídá některému klíči v states, převede ji na standardní chybový kód.

5. Kryptografické funkce

V body auth kroků lze použít speciální funkce pro hashování:

md5_crypt({password}, {salt})
MD5 hash hesla se solí
sha1(...)
SHA1 hash (může obsahovat vnořené funkce)
Kombinace
"password": "sha1(md5_crypt({password}, {salt}))" - nejprve MD5 se solí, pak SHA1

6. Kontrola přihlašovacích údajů

Pokud uživatel nezadá požadované údaje (označené "required": true), aplikace automaticky vrátí chybu no_credentials se seznamem chybějících položek. Uživatel bude vyzván k zadání údajů v nastavení modulu.

Tip: Pro inspiraci viz modul webshare.json, který demonstruje kompletní 2krokovou autentizaci s hashem hesla.

Podmínky endpointů (condition)

Mechanika: primární endpoint může mít klíč "condition": "typ_podminky". Než se provede hlavní volání, aplikace zavolá endpoint daného typu. Ten musí vracet response.condition objekt s klíči path, alert, states (ok/nok). Pokud hodnota na path odpovídá states.ok, pokračuje se; pokud states.nok, hlavní endpoint se přeskočí a vrátí se chyba s kódem alert.

{
    "name": "check_vip",
    "type": "check_vip",
    "method": "POST",
    "url": "/user_data/",
    "body": { "wst": "{token:authToken}" },
    "response": {
        "condition": {
            "path": "response.vip",
            "alert": "membership_required",
            "states": { "ok": "1", "nok": "0" }
        }
    }
}
// Primární endpoint podmíněný check_vip:
{
    "name": "link",
    "type": "link",
    "condition": "check_vip",
    "method": "POST",
    "url": "/file_link/",
    "body": { "ident": "{id}", "download_type": "video_stream", "wst": "{token:authToken}" }
}
            

Poznámka: vyhněte se řetězení podmínek do cyklu (A závisí na B, B na A).

Dynamické endpoint placeholdery {{endpoint_type}}

V response.mapping lze uvést zástupné hodnoty ve tvaru {{typ}}. Před mapováním aplikace zavolá odpovídající endpoint typ (se stejnými původními parametry) a jeho výsledek (result) vloží do dat pod tímto klíčem.

{
    "type": "movie_detail",
    "url": "/movie/{id}?language={catalogueLanguage}",
    "response": {
        "mapping": {
            "id": "id",
            "title": "title",
            "relatedSearch": "{{search_movies}}"
        }
    }
}
            

Tip: vhodné pro doplnění souvisejících položek (např. nabízet uživateli přímý seznam nalezených filmů souvisejících s detailem). Vyhněte se rekurzi.

Rozšířené mapování

  • episodeMapping: pro kombinované odpovědi (detail seriálu + sezóny + epizody). Aplikace vybere sezónu dle {seasonNumber} a pak mapuje její epizody pomocí episodeMapping.
  • itemsKey: určuje list pro katalogy/vyhledávání (nezměněno).
  • {{endpoint_type}} hodnoty v mappingu umožňují dynamické injektování dat jiného endpointu.
  • Placeholdery v baseUrl a *BaseUrl (image/poster/backdrop) umožňují jazykové/autorizační varianty cest.

Stránkování – sjednocený offset

Starý tvar {page(start,multiplier)} byl nahrazen {page(offset,limit)}. Vrací přímo offset pro danou stránku. Příklad použití: "url": "/api/movies?offset={page(0,20)}&limit=20".

Příklady

1) API: katalog/seek přes TMDB (výřez)

{
    "type": "catalogue_movies",
    "method": "GET",
    "url": "/movie/popular?language={catalogueLanguage}&page={page}",
    "response": {
        "itemsKey": "results",
        "mapping": { "id": "id", "title": "title", "poster": "poster_path", "rating": "vote_average" }
    },
    "imageBaseUrl": "https://image.tmdb.org/t/p/w500"
}
            

2) API: stream provider s autentizací (výřez podle Webshare)

"auth": {
    "steps": [
        {
            "name": "salt",
            "method": "POST",
            "url": "/salt/",
            "body": { "username_or_email": "{login}" },
            "response": { "storeAs": "salt", "path": "response.salt", "status": { "path": "response.code", "states": { "ok": "OK", "userNotFound": "SALT_FATAL_1" } } }
        },
        {
            "name": "login",
            "method": "POST",
            "url": "/login/",
            "body": {
                "username_or_email": "{login}",
                "password": "sha1(md5_crypt({password}, {salt}))",
                "keep_logged_in": "1"
            },
            "response": {
                "tokenPath": "response.token",
                "status": { "path": "response.code", "states": { "autherror": "LOGIN_FATAL_1" } }
            },
            "storeTokenAs": "authToken"
        }
    ]
}
            

Po úspěchu lze token použít v těle/URL: "wst": "{token:authToken}".

3) Scraper: katalog přes ČSFD (schematicky)

{
    "type": "search_movies",
    "url": "/hledat/?q={what}",
    "mapping": {
        "id": "attribute(a, href)",
        "title": "selector(h3 a)",
        "poster": "attribute(img, src)",
        "rating": "regex(selector(.rating), '([0-9]+)', 1)",
        "link": "attribute(a, href)"
    },
    "imageBaseUrl": "https://www.csfd.cz"
}
            

Best practices

  • Stabilní selektory: u Scraperu preferujte selektory odolné vůči změnám layoutu (třídy, data‑atributy). Omezte závislost na pořadí elementů.
  • Relativní vs. absolutní URL: vracejte relativní cesty k obrázkům a nastavte imageBaseUrl/posterBaseUrl/backdropBaseUrl - nebo vraťte přímo absolutní URL.
  • Stránkování: vždy podporujte {page}, pokud to zdroj umožňuje.
  • Jazyk: používejte {catalogueLanguage}, pokud API nabízí lokalizaci.
  • Status kódy: u API definujte response.status, abychom chybové stavy převáděli na srozumitelné chyby v UI.
  • Výkon: omezujte počet položek (limit), používejte specifické selektory a nerozšiřujte extrakci nad rámec potřebných polí.
  • Testování: průběžně ověřujte, že klíče v mapping/mapping korespondují s mappery (viz sekce „Mapování dat“).

Troubleshooting

  • Prázdné výsledky u Scraperu: zkontrolujte, zda heuristika našla správné kontejnery; upravte selektory v mapping tak, aby byly relativní k položce (a, img, span uvnitř jednoho „card“/article).
  • Obrázky se nenačítají: ověřte imageBaseUrl/posterBaseUrl/backdropBaseUrl a to, zda poster/posterPath vrací pouze relativní cestu.
  • Špatné typy (např. size, ratingUp): StreamModelMapper čísla parsuje ze stringu; dbejte na konzistentní formát hodnot v mapping.
  • Chyby autentizace: doplňte response.status do auth kroků i endpointů; ověřte hashovací řetězce a dostupnost {token:...} v tělech.
  • List endpoint vrací pouze jednu položku: přidejte výraznější selektory v mapping (aby se v rámci položky daly najít hodnoty), případně upravte stránku (jiný typ endpointu - search_ vs catalogue_).

Rychlý checklist pro nový modul

  1. Vyberte typ (API/Scraper) a připravte metadata (id, name, baseUrl, headers, config…).
  2. Definujte endpointy dle konvencí (catalogue_*", search_*, movie_detail, series_detail, series_episodes, stream_search, serviceId, link).
  3. Pro list endpointy uveďte response.itemsKey (API) nebo připravte elementové selektory (Scraper).
  4. Nastavte mapping/mapping tak, aby odpovídaly očekávaným klíčům mapperů.
  5. Přidejte imageBaseUrl/posterBaseUrl/backdropBaseUrl podle potřeby.
  6. U API s chybovými stavy doplňte response.status a případně autentizační kroky auth.steps.
  7. U stream modulů zvažte, zda je potřeba volitelný serviceId endpoint pro získání service ID před vyhledáváním.
  8. Ověřte, že vše funguje pro movies i/nebo series dle media.

Tip: Jako referenci používejte existující moduly v modules/ - tmdb.json (API JSON), webshare.json (API XML + auth), csfd.json (Scraper). Ty ukazují praktické použití všech výše popsaných prvků.

Kompletní reference chybových kódů

Následující tabulka obsahuje všechny podporované chybové kódy, které lze vracet z API modulů v response.status.states. Aplikace automaticky zobrazí uživatelsky přívětivou hlášku včetně ikony a barvy.

Seznam všech chybových kódů

Kód Titulek v UI Zpráva Ikona Barva Obnovitelná
unknown Chyba Zobrazí se předaná zpráva nebo "Neznámá chyba" warning grey Ne
network Problém se sítí Zkontrolujte připojení k internetu a zkuste to znovu. wifi_off orange Ano
connection Problém se sítí Zkontrolujte připojení k internetu a zkuste to znovu. wifi_off orange Ano
http_error Chyba Zobrazí se předaná zpráva nebo "Neznámá chyba" warning grey Ne
endpoint_not_found Endpoint nenalezen API endpoint nenalezen. data_saver_off purple Ne
mapping_error Chyba Zobrazí se předaná zpráva nebo "Neznámá chyba" warning grey Ne
authentication Chyba přihlášení Přihlášení se nezdařilo. Zkontrolujte své údaje. lock red Ne
authentication_failed Chyba přihlášení Přihlášení se nezdařilo. Zkontrolujte své údaje. lock red Ne
authentication_error Neplatné přihlašovací údaje Zkontrolujte své uživatelské jméno a heslo. lock red Ne
no_credentials Nezadané přihlašovací údaje Zadejte přihlašovací údaje (zobrazí se seznam chybějících položek). lock red Ne
invalid_credentials Neplatné přihlašovací údaje Zkontrolujte své uživatelské jméno a heslo. lock red Ne
user_not_found Uživatel nenalezen Zadané uživatelské jméno neexistuje. person_off red Ne
forbidden Přístup zamítnut Nemáte oprávnění k této operaci. block red Ne
not_found Nenalezeno Požadovaný obsah nebyl nalezen. search_off blue Ne
server_error Chyba serveru Server právě není dostupný. Zkuste to později. error red Ano
fatal Chyba serveru Server právě není dostupný. Zkuste to později. error red Ano
rate_limited Příliš mnoho požadavků Počkejte chvíli před dalším pokusem. hourglass_empty amber Ano
parsing Chyba zpracování dat Data nelze zpracovat. Zkuste to později. data_saver_off purple Ne
scraping_error Chyba Zobrazí se předaná zpráva nebo "Neznámá chyba" warning grey Ne
stream_error Chyba streamu Stream právě není dostupný. Zkuste to později. error red Ano
unsupported_module Chyba Zobrazí se předaná zpráva nebo "Neznámá chyba" warning grey Ne
unsupported_operation Chyba Zobrazí se předaná zpráva nebo "Neznámá chyba" warning grey Ne

Normalizace chybových kódů

Aplikace automaticky normalizuje běžné varianty názvů chyb:

  • "httperror", "http error"http_error
  • "endpointnotfound", "endpoint-not-found"endpoint_not_found
  • "mappingerror", "mapping-error"mapping_error
  • "autherror", "auth_error"authentication_error
  • "usernotfound", "user_not_found"user_not_found

Příklad použití v modulu

{
    "response": {
        "status": {
            "path": "response.code",
            "states": {
                "ok": "OK",
                "userNotFound": "user_not_found",
                "invalidPassword": "invalid_credentials",
                "rateLimited": "rate_limited",
                "serverError": "server_error"
            }
        }
    }
}
            

Kompletní reference placeholderů

Placeholdery se používají v URL a tělech požadavků pro dynamické nahrazení hodnot. Všechny placeholdery mají formát {názevPlaceholderu}.

Základní placeholdery

Placeholder Popis Příklad hodnoty
{id} Obecný identifikátor (film/seriál/epizoda/soubor) 12345
{page} Číslo stránky pro stránkování 1, 2, 3
{page(offset,limit)} Vrátí offset: page=1 → offset, page>1 → offset + (page-1) * limit. (Dříve {page(start,multiplier)}) {page(0,50)} → 0, 50, 100...
{catalogueLanguage} Jazyk pro katalog (nastavený uživatelem) cs-CZ, en-US
{appLanguage} Jazyk aplikace cs, en
{subtitlesLanguage} Preferovaný jazyk titulků cs, en
{audioLanguage} Preferovaný jazyk zvuku cs, en
{what} Hledaný výraz (pro vyhledávání) Matrix
{title} Název filmu/seriálu The Matrix
{searchTerm} Alternativa pro hledaný výraz Matrix
{movieId} Specifické ID filmu 603
{seriesId} Specifické ID seriálu 1399
{seasonNumber} Číslo sezóny 1, 2

Auth token placeholdery

Po úspěšné autentizaci modulu lze do URL a těl požadavků vkládat tokeny uložené během auth procesu:

Placeholder Popis Příklad
{token:keyName} Nahradí se hodnotou tokenu uloženého pod klíčem keyName {token:authToken}, {token:refreshToken}
{authToken} Přímý přístup k tokenu s názvem authToken {authToken}
{*Token} Libovolný klíč končící na Token se pokusí najít v uložených tokenech {refreshToken}, {apiToken}

Config placeholdery

Hodnoty z konfigurace modulu (uživatelské údaje) lze vkládat pomocí jejich klíčů:

Placeholder Popis
{login} Uživatelské jméno nebo email z konfigurace
{password} Heslo z konfigurace
{apiKey} API klíč z konfigurace
{jakýkolivKlíč} Libovolný klíč definovaný v config sekci modulu

Vlastní placeholdery

Můžete definovat vlastní placeholdery pomocí customPlaceholders (mapa string→string) nebo customParams (libovolné typy, převedou se na string).

Příklady použití

// Základní použití
"/search/movie?query={what}&language={catalogueLanguage}&page={page}"

// Pokročilé stránkování
"/api/movies?offset={page(0,20)}&limit=20"

// Auth token v URL
"/api/user/favorites?token={token:authToken}"

// Auth token v těle
{
    "wst": "{token:authToken}",
    "ident": "{id}"
}

// Config hodnoty
{
    "username": "{login}",
    "password": "{password}",
    "api_key": "{apiKey}"
}
            

Kompletní reference překladů

Aplikace podporuje automatické překlady textových klíčů v závorkách {klíč}. Tyto překlady lze použít v popisech modulů, labelech konfigurace a názvech endpointů. Zobrazený text závisí na jazyce aplikace.

Obecné pojmy

Klíč České zobrazení Použití
media Média Obecný pojem pro obsah
catalogues Katalogy Seznam katalogů
series Seriály TV seriály
movies Filmy Filmy
details Detaily Podrobnosti
library Knihovna Uživatelská knihovna
stream Stream Streamování
modules Moduly Systém modulů
settings Nastavení Konfigurace aplikace
search Vyhledávání Funkce vyhledávání
error Chyba Chybové stavy
authFailed Přihlášení selhalo Chyba autentizace

Nastavení a konfigurace

Klíč České zobrazení
apperance Vzhled
appLanguage Jazyk aplikace
theme Motiv
systemTheme Systémový motiv
darkTheme Tmavý motiv
lightTheme Světlý motiv
defaultCatalogueLanguage Výchozí jazyk katalogů
defaultAudioLanguage Výchozí jazyk zvuku
defaultSubtitleLanguage Výchozí jazyk titulků
playback Přehrávání
autoplayNextEpisode Automaticky přehrát další epizodu
aboutApp O aplikaci

Typy katalogů

Klíč České zobrazení
popularMovies Populární filmy
topRatedMovies Nejlépe hodnocené filmy
popularSeries Populární seriály
topRatedSeries Nejlépe hodnocené seriály
searchMovies Hledat filmy
searchSeries Hledat seriály

Přihlašovací údaje

Klíč České zobrazení
apiKey API klíč
name Jméno
login Přihlašovací jméno / Email
username Uživatelské jméno
usernameEmail Přihlašovací jméno / Email
password Heslo
enterLoginDetails Zadejte přihlašovací údaje

Žánry filmů

Klíč České zobrazení
action Akční
adventure Dobrodružný
animation Animovaný
comedy Komedie
crime Krimi
documentary Dokumentární
drama Drama
family Rodinný
fantasy Fantasy
history Historický
horror Horor
music Hudební
mystery Mysteriózní
romance Romantický
scienceFiction Sci-Fi
tvMovie TV film
thriller Thriller
war Válečný
western Western

Žánry seriálů

Klíč České zobrazení
actionAdventure Akční a dobrodružný
kids Pro děti
news Zprávy
reality Reality show
sciFiFantasy Sci-Fi a Fantasy
soap Mýdlová opera
talk Talk show
warPolitics Válka a politika

Příklady použití v modulech

// V popisu modulu
{
    "name": "TMDB",
    "description": "Katalog {movies} a {series} z {tmdb}"
}

// V názvu endpointu
{
    "name": "{popularMovies}",
    "type": "catalogue_movies"
}

// V konfiguraci
{
    "config": {
        "apiKey": {
            "type": "string",
            "label": "{apiKey}",
            "required": true
        },
        "login": {
            "type": "string",
            "label": "{usernameEmail}",
            "required": true
        }
    }
}
            

Poznámka: Všechny překlady jsou automaticky zobrazeny v jazyce aplikace, který si uživatel zvolil v nastavení.