Disclaimer: This documentation is provided for convenience and may contain errors. Always verify information against the official Kodi and provider documentation. Report issues.
Fastmail
Home / Files / stv_vod.py

easyplaytv-service/…/providers/stv_vod.py — STV catalogue

Also ships in the video addon — this page documents the runtime copy

The full catalogue scraper ships in the shared runtime at easyplaytv-service/src/easyplaytv_service/vod_sync/providers/stv_vod.py (and the vendored copy inside service.easyplaytv). The video addon keeps only the playback half (resources/lib/stv_vod.py: resolve_vod + _get_brightcove_credentials); the Brightcove bundle/playback constants live there now. Functions and line numbers below refer to the runtime copy.

Path easyplaytv-service/src/easyplaytv_service/vod_sync/providers/stv_vod.py Lines 275 Type catalogue scraper (JSON API) ← called by library_sync.py via _provider_module("stv_vod"), providers/__init__.py → calls player.api.stv.tv JSON endpoints; optional STV cache dir under cookies path

Role

STV's catalogue sits behind a clean JSON API at player.api.stv.tv/v1. This module wraps it — pure catalogue scraping. Playback (Brightcove account/player/policy-key resolution via bundle.js, resolve_vod) lives in the video addon's resources/lib/stv_vod.py.

Constants

API_BASE = "https://player.api.stv.tv/v1" · URL_PROGRAMMES · URL_CATEGORIES · URL_EPISODES · lines 19-22

STV's API roots.

GENRE_MAP = {"dramas":"drama", "entertainment":"entertainment", "crime-punishment":"true-crime", "documentaries":"documentaries", ...} · lines 28-46

STV-specific genre slugs (keys) → addon unified genres (values). STV has more finely-sliced genres than any other provider (soaps, history-hit, wonder, real-stories, real-life, real-crime, crime-drama, legal-drama, thrillers, comedy-drama, daytime) — most map onto the same unified buckets per the genres.py:UNIFIED_GENRES mapping.

UNIFIED_GENRE_MAP · lines 48-49

The reverse map — given an addon unified genre, find the STV API genre slug. Used by list_shows to translate the user's UI tap into an STV-API-friendly slug.

API helpers

_api_get(url, params=None, timeout=20) · line 50

gzip-aware JSON fetch, with the STV-standard "stv-drm: true" header so the API yields DASH+DRM streams. Same header as stv.py:HEADERS for live.

_img_url(image_id, width=300, height=400) · line 62

STV's image API redirects to a sized rendition. Default 300x400 portrait poster is the addon's standard size.

_thumbnail(images) · line 66

Reaches into the images array on a programme/episode — handles two formats: modern (with id) and legacy (with _filepath placeholders for width/height interpolation).

Listing functions

list_categories() · line 78

Fetches /categories and filters out a list of categories we don't expose in the UI (line 90's set: top-picks, radio-podcasts, audio-described, visually-signed, archive, new-talent, so-real, paranormal) — they're either internally-curated collections rather than genres (top-picks) or radio/metadata we don't have UI for.

list_shows(category_guid, offset=0, limit=200) · line 90

Per-category programme listing. Uses a large limit (200) so most STV genres return in one page; if a genre has more, the caller paginates. Returns a tuple (shows, total_entries). Each show dict has guid (programme GUID), f_name, title, description, image, standalone (single-episode flag).

list_shows_all() · line 99

Iterates every STV category and accumulates all shows — used by library_sync.py when the caller passes the genre-bypass / "show all STV shows" route. Dedupes by f_name across the multiple genres a programme may appear in.

list_seasons(programme_guid) · line 139

Per-programme seasons. Returns a list with each season's guid, season_number, and title.

list_episodes(programme_guid, series_guid=None, offset=0, limit=50) · line 199

Per-programme episode listing. If series_guid is set, filters to that single season. Returns 50-per-page (parameter chosen to keep responses under ~3MB on big soaps like Emmerdale).

episodes with episode_number=0 are real

STV returns episodes with episode_number=0 when playerSeries is null — single-episode documentaries AND entire programmes without per-episode index info (Coronation Street, Emmerdale daily strips). library_sync drops episode_number=0 via its if en_int < 1: continue guard, which would otherwise drop hundreds of valid episodes per sync. The pre-pass in _sync_series (lines 1090-1115) renumbers them sequentially from 1 within their season block before the insert loop runs. The cataloguer doesn't lie about the episode numbers — STV's metadata is incomplete; the renumber is the addon's workaround.

STV cache

This module caches per-show episode JSON responses in a stv_cache/ directory (under the runtime cookie path) — listing every STV catalogue page every sync used to cost hundreds of HTTP calls which is wasteful since the catalogue only changes weekly. The cache is managed by _ep_cache_path, _load_ep_cache and _save_ep_cache (lines 171-190), with a 6-hour (21600s) TTL before a cached response is refetched.