mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 11:06:16 -08:00
fix(playlist): bound playlist downloads and isolate startup auto-update
Playlist downloads in the main process ran without an axios timeout, so a host that accepted the connection and then went silent kept the request pending forever. The startup auto-update refreshed playlists sequentially, so that one unresponsive source also withheld every playlist that did refresh, and the URL import dialog could spin with no way out. - Add PLAYLIST_FETCH_TIMEOUT_MS (30s) to the main-process fetch and reuse it in the refresh worker instead of its duplicated literal. Redirects are followed one hop at a time, so each hop is bounded separately. - Move auto-update into playlist-auto-update.ts and refresh at most AUTO_UPDATE_CONCURRENCY (3) playlists at once, isolating each failure while preserving the requested order. An unbounded fan-out would download and parse arbitrarily many large M3U files in the main process at once. - Redact refresh log URLs, which routinely carry Xtream username/password query parameters. The existing auto-update spec handed out fixtures by call order, which no longer holds once refreshes overlap; it now keys them by source type. Fixes #931 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b4c0cce741
commit
f83a50b2c0
7 files changed
+422
-73
No files matched your search
@@ -55,6 +55,37 @@ There is intentionally **no URL validation** (upstream removed it in 0.15.0): an
|
||||
|
||||
The behavioral contract is guarded by `apps/web/src/app/iptv-playlist-parser.contract.spec.ts` (jest maps the module to the real parser source) and by the fork's own test suite.
|
||||
|
||||
## Playlist Refresh And Startup Auto-Update (Electron)
|
||||
|
||||
Two paths re-download an M3U playlist from its original source:
|
||||
|
||||
- **Explicit refresh** — `PLAYLIST_REFRESH` runs in `playlist-refresh.worker.ts`, reports
|
||||
progress through `PLAYLIST_REFRESH_EVENT`, and is cancellable via
|
||||
`PLAYLIST_CANCEL_REFRESH`.
|
||||
- **Startup auto-update** — after `loadPlaylistsSuccess`, `AppComponent` sends
|
||||
`AUTO_UPDATE_PLAYLISTS` for every playlist with `autoRefresh === true`. The main
|
||||
process fulfils it in `playlist-auto-update.ts` on top of `playlist-source.ts`.
|
||||
|
||||
Both share one download contract, because this path is unattended and a hostile or
|
||||
dead source must never stall startup (issue #931):
|
||||
|
||||
- Every HTTP hop uses the idle timeout `PLAYLIST_FETCH_TIMEOUT_MS` (30s, exported by
|
||||
`playlist-source.ts`). Without it a host that accepts the connection and then goes
|
||||
silent keeps the request pending forever. Redirects are followed one hop at a time,
|
||||
so each hop is bounded separately.
|
||||
- Auto-update refreshes at most `AUTO_UPDATE_CONCURRENCY` (3) playlists at a time.
|
||||
Sequential refreshes let one slow host delay every remaining playlist; an unbounded
|
||||
fan-out would download and parse arbitrarily many large M3U files in the main
|
||||
process at once.
|
||||
- Each playlist's failure is isolated and logged; the successful ones are still
|
||||
returned, in the order they were requested. Playlists with neither a URL nor a file
|
||||
path are skipped with a warning.
|
||||
- `preserveAutoUpdatedPlaylistFields()` re-applies the user-owned fields (`_id`,
|
||||
`autoRefresh`, `favorites`, `userAgent`) onto the freshly parsed playlist.
|
||||
- Playlist URLs frequently carry Xtream-style `username`/`password` query parameters,
|
||||
so refresh logging goes through `redactSensitiveData()` from
|
||||
`@iptvnator/shared/logging`.
|
||||
|
||||
## State Management (libs/m3u-state/)
|
||||
|
||||
### State Structure
|
||||
@@ -283,7 +314,7 @@ per-tab EPG logic:
|
||||
|
||||
The programme guide under the player renders in one of **two interchangeable
|
||||
views**, chosen by the **`epgViewMode`** setting (`'timeline'` default, or
|
||||
`'list'`; Settings → EPG → *Guide view*):
|
||||
`'list'`; Settings → EPG → _Guide view_):
|
||||
|
||||
- **Timeline** — a horizontal **ribbon** (`app-epg-timeline`,
|
||||
`libs/ui/epg/src/lib/epg-timeline/`).
|
||||
@@ -679,7 +710,7 @@ class EpgService {
|
||||
|
||||
### DASH + ClearKey Playback
|
||||
|
||||
MPEG-DASH (`.mpd`) channels play through a Shaka Player *source engine* inside
|
||||
MPEG-DASH (`.mpd`) channels play through a Shaka Player _source engine_ inside
|
||||
the existing built-in players — exactly like hls.js/mpegts.js. There is no new
|
||||
player in settings.
|
||||
|
||||
@@ -687,7 +718,7 @@ player in settings.
|
||||
|
||||
1. The playlist parser fork does not understand `#KODIPROP:` lines, but keeps
|
||||
every unknown line between `#EXTINF` and the stream URL in `item.raw` (the
|
||||
dominant Kodi/TiviMate layout; `#KODIPROP` lines *before* `#EXTINF` are
|
||||
dominant Kodi/TiviMate layout; `#KODIPROP` lines _before_ `#EXTINF` are
|
||||
dropped by the parser — fixing that requires a parser-fork patch and is
|
||||
deferred).
|
||||
2. `extractDrmFromRaw()` (`libs/shared/m3u-utils/src/lib/kodiprop.utils.ts`)
|
||||
|
||||
Reference in new issue
Block a user