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 / c4.py

resources/lib/c4.py — Channel 4 resolver (live + VOD)

Path /resources/lib/c4.py Lines 124 Type playback resolver (DASH + Widevine via Redbee) ← called by default.py:_resolve_channel, default.py:_resolve_vod → calls channel4.com simulcast + VOD stream endpoints, Redbeemedia widevine license proxy, setup_dash_item

Role

Resolves both live channels (Channel 4, E4, More4, Film4, 4seven) and on-demand programme episodes. Channel 4 wraps every stream's manifest URL with an AES-CBC-encrypted token that you decrypt client-side; the decrypted token goes into a JSON license-acquisition payload POSTed to Redbee's Widevine proxy.

Constants

URL_LICENSE = "https://c4.eme.lp.aws.redbeemedia.com/wvlicenceproxy-service/widevine/acquire" · line 12

AWS-hosted Redbee Media license proxy. Same endpoint for live and VOD.

VOD_PROFILES = {"bigscreendashwv-dyn-stream-1", "dashwv-dyn-stream-1"} · line 14

Two acceptable VOD profile names returned in videoProfiles. We try the first one (the bigscreendash — TV-optimized), fall back to dashwv-, finally to anything containing "dash".

AUTH_TOKEN_HEADERS = {"authorization": "Basic MzZVVUN0OThWTVF2QkFnUTI3QXU4ekdIbDMxTjlMUTE6Sllzd3lIdkdlNjJWbGlrVw=="} · line 16

A static Basic-Auth credential — same as the one Channel 4's web app uses for its token request. Unused by the resolver today (because _get_access_token() always returns None at line 32); here for the future path where the addon supports authenticated C4 content (some shows require sign-in). The base64 blob decodes to a client_id:client_secret string for the C4 OAuth flow.

KEYS = {"amazonfire-dash": {"key": "K2C8Q09D7HJ385AB", "iv": "B3LKVU05F3IDLVME"}, "web": {"key": "n9cLieYkqwzNCqvi", "iv": "odzcU3WdUiXLucVd"}} · lines 18–21

Two AES-CBC key/IV pairs — different per C4 "client" persona (amazonfire-dash = the Fire TV app's keys, web = the channel4.com web keys). Hard-coded (reverse-engineered from the C4 player JS). When C4 rotate these, all C4 playback breaks and the addon needs a key bump.

_get_access_token() → None · line 31

Always returns None. There's an OAuth flow scaffolded but not wired — for now C4 content (UK-IP geofenced) plays anonymous as the "web" client. When you authenticate in the future, this is the hook point.

Live resolver

resolve(item_id, listitem) · line 35

Steps:

  1. If a non-None access token exists, use the amazonfire-dash client + the live-API URL; otherwise use client="web" + the live-WEB URL (https://www.channel4.com/simulcast/channels/).
  2. Fetch the JSON. Read channelInfo.videoProfiles (the modern shape) or the bare data.videoProfiles (the legacy shape — line 48's data.get("channelInfo", data)).
  3. Look for a profile with name "dashwv-live-stream-iso-dash-sp-tl" — the standard C4 live DASH+Widevine profile. Fall back to anything with "dash" in the name verbatim.
  4. Pick streams[0].token (encrypted) and streams[0].uri (manifest URL).
  5. Decrypt the token with the right client's AES key+IV via PyCryptodome (line 65). The decrypted form is either …&t= (regex match) or …||… (split on |) — the resolver handles both.
  6. Build the JSON license payload:
  7. {"token": , "video": {"type": "simulcast", "url": }, "message": "b{SSM}"}
  8. The "b{SSM}" message tells Redbee to expect a binary-prefixed Widevine challenge; IA will substitute {SSM} with the actual challenge at license time.
  9. Hand to setup_dash_item() with license_payload=payload — this triggers the "JBlicense" terminal token (vs the usual "R{SSM}") because we're sending the payload verbatim.
Manifest URL is the manifest_path

The stream_url passed to setup_dash_item as setPath() at the same time is the unmodified URL C4 returned. That URL contains query-string params tying the manifest to this token, so it can't be reused for any other request — Kodi will only load it once.

VOD resolver

resolve_vod(programme_id, asset_id, listitem) · line 85

Same shape as live but against the VOD endpoint https://www.channel4.com/vod/stream/. The decrypted token is just split |[1] (VOD tokens don't use the &t= form). The license payload uses "type": "ondemand" and includes "request_id": asset_id or programme_id so Redbee can correlate the request.

asset_id optional, programme_id required

If asset_id isn't supplied, the payload falls back to programme_id as the request_id. In practice this happens for C4 movies (single-asset programmes) where the caller didn't fetch the asset id. Multi-asset programmes (series with multiple versions — signed, audio-described) need the asset_id for Redbee to find the right license.