Files
iptvnator/docs/architecture/xtream-portal-compatibility.md
T
StefanandClaude 2f8aee72df feat(xtream): add catch-up playback to favorites and recent tabs (#1166)
Enables Xtream catch-up/timeshift from the Favorites and Recent surfaces (per-playlist and global), not just Live TV, and adds start-over replay of the currently-airing programme. Carries tv_archive/tv_archive_duration through the favorites and recently-viewed DB projections and maps them onto UnifiedCollectionItem; tv_archive_duration is interpreted as days, matching live-stream-layout.controlledArchiveDays.

Closes #1138.

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-19 06:38:19 +02:00

123 lines
5.3 KiB
Markdown

# Xtream Portal Compatibility
This document captures the Xtream Codes compatibility rules shared by the
Electron and PWA paths.
## Connection Input
Xtream server URLs are normalized through
`normalizeXtreamServerUrl` from `@iptvnator/shared/interfaces`.
Rules:
1. Only `http` and `https` URLs are accepted.
2. URL username/password credentials are rejected.
3. Leading and trailing whitespace is ignored.
4. Trailing slashes are removed.
5. Full API or playlist URLs ending in `/player_api.php` or `/get.php` are
reduced to the portal base URL.
6. Provider subpaths are preserved. For example,
`https://example.test/panel/player_api.php?...` becomes
`https://example.test/panel`.
The Xtream import form may extract `username` and `password` from full
`get.php` or `player_api.php` URLs, but stored playlist metadata should keep
the normalized `serverUrl` plus trimmed credentials.
## Account Status
Account status handling uses `resolveXtreamPortalStatus`.
Compatibility rules:
1. Status text is case-insensitive, so `Active`, `active`, and `ACTIVE` are
treated the same.
2. `auth` values `1`, `'1'`, and `true` can mark a response as active when no
status text is present.
3. `auth` values `0`, `'0'`, and `false` mark the response inactive.
4. `exp_date` values `0`, negative numbers, missing values, or invalid values
are treated as no expiry.
5. A past positive `exp_date` marks the account expired even when status is
active.
Status probes try account-info-compatible Xtream variants in this order:
1. `action=get_account_info`
2. no `action`
3. `action=get_profile`
This fallback exists because real panels differ even when they advertise
Xtream Codes compatibility.
## Request Construction
Electron IPC and the PWA backend both construct API requests by appending
`/player_api.php` to the normalized portal base URL. They must not append
`player_api.php` to an already full `player_api.php` or `get.php` URL.
Credentials sent to the API are trimmed before serialization.
The PWA backend only proxies Xtream requests through registered provider
targets. Those targets are validated when registered and revalidated before the
`/xtream` proxy request, including protocol, URL credentials, DNS resolution,
and private-network checks.
## User-Agent
Electron's `XTREAM_REQUEST` and `XTREAM_PROBE_URL` handlers
(`apps/electron-backend/src/app/events/xtream.events.ts`) send a shared
`XTREAM_CLIENT_USER_AGENT` constant on every outgoing request. Some Xtream
panels sit behind a WAF (e.g. Cloudflare) configured to challenge
generic/incomplete browser-looking User-Agents while allowlisting known IPTV
player clients; a player-style User-Agent (currently a VLC signature) avoids
that challenge page, whereas a browser-looking but non-browser TLS/HTTP client
(axios/curl with a Chrome or empty User-Agent) can be blocked even though a
real browser or a VLC-style client passes. Keep all three request sites using
the shared constant instead of inlining the string again.
## Playback URL Formats
When account info includes `user_info.allowed_output_formats`, the current
Xtream playlist keeps those formats for the active session. The default
application format is `auto`: live stream URL construction chooses `m3u8` when
the provider allows HLS, falls back to `ts` when MPEG-TS is the only known
standard format, and otherwise uses the first provider-advertised format. If
the provider does not advertise output formats, `auto` falls back to `m3u8`.
Manual `ts` and `m3u8` settings remain supported; when a manual setting is not
allowed by the portal, URL construction falls back to the first
provider-allowed format.
If stored Xtream playback credentials contain an invalid server URL or blank
username/password, stream URL construction returns an empty URL instead of
throwing during playback.
## Catch-Up Playback URLs
Xtream-compatible portals differ on archive playback URL shape. IPTVnator
supports these catch-up variants:
1. REST-style `/timeshift/{username}/{password}/{duration}/{start}/{streamId}.ts`
and `.m3u8`.
2. Legacy `/streaming/timeshift.php?username=...&password=...&stream=...&start=...&duration=...`
with optional `extension=ts` or `extension=m3u8`.
Electron probes concrete catch-up variants before caching a playlist-level
choice. The cache key includes the playlist id and the normalized
`allowed_output_formats` advertised by the provider, so a catch-up variant
detected before account capabilities are known cannot force stale MPEG-TS URLs
after the portal later reports HLS-only playback. The probe uses a short range
`GET`, follows only validated redirects, and accepts only `200` or `206` as
playable. MPEG-TS is preferred before HLS when the provider allows it because
some portals return a valid HLS manifest while the first media segment fails in
Chromium/video.js. PWA fallback keeps the REST MPEG-TS URL when no Electron
probe API is available.
Catch-up is offered from the Xtream Live TV tab and from the unified
collection surfaces (per-playlist and global Favorites and Recent). The
`tv_archive` / `tv_archive_duration` columns are carried through the
favorites and recently-viewed DB projections and mapped onto
`UnifiedCollectionItem.tvArchive` / `tvArchiveDuration` so the shared live
tab can gate the timeline's archive window. `tv_archive_duration` is
interpreted as **days** everywhere, matching
`live-stream-layout.controlledArchiveDays` (issue #1138).