mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 11:06:16 -08:00
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>
123 lines
5.3 KiB
Markdown
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).
|