Repository navigation
Technical The service
StremioK's service (service/index.js) does on the TV what a web page can't do on its own:
YouTube, USB drive listings, subtitle files and downloads, the phone page, AIOManager, and
repacking a live channel's choppy sound.
- One file, Node core modules only, ES5 (the 2017 TV's Node is 4.x).
-
Sideloaded app: a bundled
<tizen:service>on127.0.0.1:8099, which the app (js/ytplay.js) starts when it needs it. -
TizenBrew: TizenBrew runs the same file inside its own Node service, on
127.0.0.1:8098, and starts it when it launches StremioK. Since it then shares TizenBrew's process, every request is fenced off: a failure ends that one request, never the service. Separate ports let both installs live on one TV. - The phone page listens on a second port, the service's plus 10 (8109, or 8108 under TizenBrew), on the TV's home-network address only, and only while a page is open.
- The home bar preview is a separate small service,
service/preview.js(the sideloaded app only; see Home bar preview).
These checks keep web pages out (any page running in the TV's browser engine can reach a local port). They are restrictions on requests, not proof of who is calling.
-
Every endpoint but
/health: the request must name the service by its local address (127.0.0.1orlocalhostwith its port, so a page reaching it through a DNS-rebound name is refused) and carry noOriginheader. StremioK's pages and the TV's player send none, while a web page's request always does. Under TizenBrew, TizenBrew's own pages (http://127.0.0.1:8081) may send theirs, and every TizenBrew module shares that address. A browser's pre-check (preflight) carries anOrigin, so it's refused too. GET only. -
USB, files and downloads (
/fs…,/fsdl/…) also need a token. The service keeps it in StremioK's private folder (wgt-private), and the app reads it and sends it. Where the app can't read it (on Tizen 6 the service keeps it in a folder of its own), anX-StremioKheader is accepted instead, which a web page can't add without a pre-check. Under TizenBrew there's no private folder and so no token: these endpoints stay closed. Their answers carry no CORS header. -
The phone page's controls, AIOManager and opening a live relay (
/entry/…,/aiom/addons,/live/open) need the token or theX-StremioKheader. Under TizenBrew, where there's no token, the header is what's sent. The app sends the header only when it has no token: on the 2017 TV's engine an extra header might make it send anOrigin.
Each endpoint's parameters are described at the top of service/index.js.
| Family | Endpoints | What it does | Needs |
|---|---|---|---|
| Health | /health |
"ok": the app waits for it before playing | nothing |
| YouTube |
/yt, /ytinfo, /ytsubs, /ytsb, /ytlist
|
A video's HLS master; its audio languages, end screen, cards and chapters; its captions as WebVTT; SponsorBlock sections and DeArrow; searches, channels and playlists | local address, no Origin
|
| USB drives |
/fslist, /fswalk, /fssub, /fshash, /fsfile
|
A folder's listing; every video and subtitle file under a folder (the index); a subtitle file as UTF-8; a video's OpenSubtitles hash; a file served with ranges | + token or header |
| Downloads |
/fsdl/add, list, cancel, clear, space
|
Downloads to a USB drive, and a drive's free space | + token or header |
| Phone page |
/entry/open, poll, close
|
Opens, polls and closes the one-time page | + token or header |
| AIOManager | /aiom/addons |
Reads an account's addons | + token or header |
| Xtream films and series |
/xtvod/list, /xtvod/find
|
An account's newest titles and Search; a title's copies | + token or header |
| Stalker |
/stalker/list, /stalker/link, /stalker/genres, /stalker/vod, /stalker/play
|
A portal's channels as an M3U playlist; a channel's link to play; its genres; its films and series; a film's or episode's link, redirected to | + token or header (play: or the guide ticket) |
| TV guide |
/epg/load, /epg/get
|
Reads a playlist's guide for your channels; their programs | + token or header |
| DRM |
/drm/license (a POST) |
Posts a Widevine channel's license request to its license server | + token or the guide ticket |
| Live relay |
/live/open, then /live/<id>/…
|
Checks a channel's sound and captions; relays it repacked, captions as subtitles | open: + token or header |
-
Resolving: a YouTube page is resolved through YouTube's InnerTube API, from the TV, as the
YouTube website does (no key, no account), and its HLS master served at
/yt. - Quality: playback first asks for 1080p when that resolution is available (in a wider picture, like a 2:1 trailer's 1920×960, the rung at or below it). The complete master is loaded separately to fill the Video quality menu, each quality named by its class, wide pictures too (1920×960 is 1080p, 3840×1920 2160p). Picking a quality reopens the stream with a fresh YouTube session and a single-resolution master; Auto restores the full ladder. The player is stopped and given a moment before it reopens, since the TV's player often fails an open straight after closing a playing stream; if that first open still fails, it's retried once quietly ("Switching to 720p…"), then steps down a rung, then goes to Auto.
- Tizen 6 headers: YouTube's watch page often comes with more headers than a Tizen 6 TV's Node reads (an experiment's 7 KB header, 12 KB in all, over its 8 KB). The service then reads that answer itself, straight off the connection, and asks again for anything else it can't read (twice at most). That reader accepts only a complete answer: every chunk and its end, or its declared length.
-
Audio: many videos carry AI-dubbed audio (every dub listed, none marked default, a dub
often first), and switching tracks on such a stream right after it starts hangs the 2017 TV's
player. The service keeps only the original audio, as the default (a stream with no track
marked original is passed on as it is), and the app doesn't switch a YouTube video's audio on
its own. Another language is another stream:
&lang=<code>keeps that dub instead. -
/ytinfogives the video's audio languages, the links on its end screen and cards (links to videos only) and its chapters, all read from the page already fetched./ytsubsgives a caption track as WebVTT. -
/ytlistlists a search (src=search:<words>,{term}filled fromq;kindvideos / channels / auto / live,sortrelevance / date / views / rating), a channel (@handle, link orUC…ID) or a playlist (link orPL…ID), about 20–30 items a page, with anexttoken forpage=. Shorts are left out.meta=1adds the channel's or playlist's name, description and picture (and, for a channel, what it's streaming now) and joins up to 4 pages (120 videos).orig=1gives titles in their own language: the same request is made again in Zulu (YouTube doesn't translate titles into it) and only the titles are taken from it.brand=1adds DeArrow's titles, asked per listed video, in parallel, waiting at most 4 seconds (the rest come next time). -
/ytsbaskssponsor.ajay.appfor a video's SponsorBlock sections and DeArrow title and thumbnail time by the first 4 characters of its id's SHA-256, as SponsorBlock's own extensions do: the answer covers every video sharing them, so the server isn't told which one. -
Hosts: YouTube's pages and API and
googlevideo.com(the masters), over HTTPS, with every redirect checked against those hosts;sponsor.ajay.appfor SponsorBlock and DeArrow. An answer other than 200 is an error. - Limits: these YouTube and SponsorBlock requests go through one gate: 6 at a time, 40 waiting (more are told it's busy), at most 600 started a minute, identical ones sharing one download (up to 16 waiting on it), each given 30 seconds from start to finish (and 15 s of silence). Answers are capped at 8 MB downloaded and 10 MB unpacked (no gzip bombs). Resolving a page: at most 2 at a time, a few waiting, 30 fresh a minute, kept 4 minutes. Lists: 60 fresh a minute, kept 10 minutes. SponsorBlock: 300 a minute, kept an hour. A request given up (screen left, player closed) drops its waiting work and a shared download nobody else waits for; a lookup already running finishes and is kept.
- Only folders under
/opt/media/<drive>/: a path is resolved to where it really is and must stay inside the drive it was asked under. Links in a folder are listed as links and never followed or walked, and subtitle files, hashes and/fsfile's files are read only through that check (a file is opened once, and served only if it's a regular file). - A drive must be mounted (listed in
/proc/mounts). Its free space is read withdf, run directly with the drive as its argument, never through a shell, and without holding up the service. -
/fssubreads subtitle files up to 5 MB: SRT and WebVTT as they are, ASS / SSA turned into SRT, Windows-1252 and UTF-16 converted./fshashreads a video's size and its first and last 64 KB./fsfileserves a file with ranges, for the 2017 TV's player, which can't read past 2 GB of a file straight from the drive. - Bounded: 12 file lookups at a time for the whole service, 4 listings at once, and one drive walk at a time (the same drive asked again shares it; another is told the service is busy). A walk covers up to 5,000 folders and 20,000 files, 12 levels deep, and starts nothing new after 90 s.
- One at a time, up to 50 in the list, into a
….partfile renamed when complete. - A dropped connection (or 60 s of silence) is picked up where it stopped, with a range request where the server allows it, up to 5 times, waiting 5 s, 15 s, 30 s, 1 min, then 2 min.
- A resumed answer must start exactly where the partial file ends (its
Content-Range), for the same file (If-Range, with the ETag or date the download began with); otherwise it starts over. The finished file must be the declared size. - That ETag or date is kept in StremioK's own folder (the last 64 downloads), never on the drive, where a prepared file could lead elsewhere. The partial file's size is read only from a regular file, not through a link.
- Checked before it starts: the drive's free space (with 50 MB to spare) and, on a FAT32 drive, the 4 GB file limit. The partial file and the finished one must be regular files, not links.
- A streamed playlist (HLS or DASH, by its type or its first bytes) isn't a file: refused.
- Links over HTTP(S) only, never to the TV itself: loopback, unspecified and link-local addresses
however they're written (
localhost,127.…,2130706433,0x7f…,::1,::ffff:127.0.0.1,169.254.…), checked again on the address a name resolves to when connecting. Home-network addresses (a NAS) are allowed. HTTPS checked against the bundledservice/cacert.pem. - The list is kept in the service's memory; the app keeps its own copy and adds again what the service no longer knows after a restart. One that had already finished (its file on the drive at its size, no partial file left) is taken as done, not downloaded a second time.
The TV asks the service to open a page (/entry/open?what=…), polls it (/entry/poll?t=…) and
closes it (/entry/close?t=…). At most 2 pages are open at a time (another closes the oldest)
and 12 opened a minute. Each page has a random 128-bit code in its address, takes one entry (8 KB
at most), and closes after 5 minutes, or 30 seconds without the TV polling it. Its port takes at
most 8 connections, and each visit is given 20 seconds (10 s of silence). See
Typing, or sending from your phone.
/aiom/addons reads an account's addons with AIOManager's Hydra API (GET <address>/hydra/addons,
the API key sent as X-API-Key), up to 2 MB, within 20 seconds in all, and keeps at most 500.
It follows up to 4 redirects on the same server only (HTTP to HTTPS allowed, never the other
way): the key never goes anywhere else. One cancel stops the whole chain. It then registers StremioK (POST <address>/hydra/register, best effort),
which is its card in AIOManager's Connections. Nothing else is written to AIOManager. It's done
in the service because an instance only answers the web addresses it's set to. The same host
rule as downloads applies.
/live/open looks at the start of one of a channel's segments (up to 1.5 MB) to see whether its
AAC sound is cut mid-frame. If it is, it returns a relay link that passes the picture as it is
and repacks the sound into whole frames, each with its own time. At most 4 relays at a time,
each dropped after 5 minutes unused; playlists up to 1 MB and segments up to 32 MB, 20 seconds
each. The channel's User-Agent, Referer and Cookie are passed on, and the same host rule as
downloads applies.
HLS through StremioK's service (Settings › Playback › Seeking & buffering, or hold OK on a
source › Play through StremioK's service): an HLS source opens the relay without the look
(&force=1&fix=0), so every playlist and piece is fetched with its headers. Sources that need
headers: those with their own User-Agent, Referer or Cookie; All HLS sources: any .m3u8.
Not YouTube, DRM or USB files. A film's (&film=1) keeps every link it named (a live channel's
keeps its last 400), relays its keys, init sections and encrypted pieces too, asks a byte range
as one, and is dropped after 3 hours unused. If the service doesn't answer, the source plays as
it is.
Closed captions (CEA-608 in H.264, HEVC or MPEG-2 pictures) at a segment's start: the look reads
the whole segment, up to 8 MB. Asked for (&cc=CC1-en; &fix=0: sound as it is), the relay adds
a WebVTT subtitle track per channel; a plain playlist goes under a quality list of its own.
- One download per segment for picture and captions (kept 30 s for the other, two at a time, up to 8 MB); captions kept for the latest 30 segments.
- Cues in showing order: a pop-on caption from when it shows; roll-up, one per finished line with the lines above; one still on at a segment's end goes on in the next.
-
Timing: the picture's own clock (
X-TIMESTAMP-MAP).
- An answer within 60 seconds (504 otherwise), except the USB and download endpoints, which have bounds of their own.
- At most 64 connections at once.
- A request line up to 2 KB (8 KB for adding a download, whose link can be long).
- Answers say
Cache-Control: no-storeandX-Content-Type-Options: nosniff.
User guide
- Getting started
- Getting around
- Finding something to watch
- Title pages
- Choosing a source
- While it plays
- Subtitles and audio
- IPTV and radio
- YouTube
- Your USB drive
- Your media server
- Trakt
- Other apps (where to watch)
Settings reference
Troubleshooting
- Where to look
- Installing
- Addons
- No sources, or none that play
- A source doesn't start
- Playback
- Audio and subtitles
- Skip prompts
- YouTube and trailers
- Home
- IPTV
- Trakt
- USB drive
- Media servers
- Other apps
- Storage
- Home bar preview
Technical reference
- Starting up and Home rows
- Calendar
- Discover and Search
- Title pages
- Sources
- Playback
- Subtitles
- Audio
- Formats
- IPTV
- Addons
- Trakt
- USB drives
- Media servers
- Storage
- Home bar preview
- YouTube
- Limits on what's downloaded
- The service
Also