Commit Graph
19 Commits
Author SHA1 Message Date
d35875e3d1 fix hls close revision file at reader deadline (#907)
* fix hls close revision file at reader deadline

Move the progressive revision reader onto its own task and feed the
response stream through a bounded channel. At the deadline the watchdog
aborts the reader, so the file handle and revision pin are released
even if a stalled client never polls the stream again.

Each open revision file now holds its own pin, so GC cannot retire a
revision while a handle is open, including one held by an in-flight
blocking read.

* fix hls close revision file at reader deadline

Move the progressive revision reader onto its own task and feed the
response stream through a bounded channel. At the deadline the watchdog
aborts the reader, so the file handle and revision pin are released
even if a stalled client never polls the stream again.

Each open revision file now holds its own pin, so GC cannot retire a
revision while a handle is open, including one held by an in-flight
blocking read.

---------

Co-authored-by: euzu <euzu@proton.me>
2026-10-09 17:41:39 +02:00
euzuandGitHub 91433fe37f Fix/dvr recording (#903)
* fix(dvr): correct source resolution, HLS headers and proxy routing

* fix(dvr): support concurrent live recordings within provider capacity
2026-10-07 15:41:19 +02:00
euzuandGitHub 8b4d27b79f fix(m3u): use alias token for Flussonic catch-up archives (#902)
* fix(m3u): use alias token for Flussonic catch-up archives

Catch-up archive URLs are built from the main account's live URL. On an
alias allocation the M3U URL index only knows live URLs, so the lookup
missed and the archive manifest was fetched with the main stream token.
DVR segments inherited it, and the provider attributed the playback to
the main account.

On an index miss for a Flussonic archive file, resolve the live file in
the same directory through the alias index (one lookup pass for all
candidates) and keep the requested archive file name with the alias
query.

Query-based catch-up templates (append mode) are not covered.

* fix(dvr): retry ffmpeg spawn while executable is busy

Spawning a just-written executable can fail with ETXTBSY when a
concurrently forked process still holds an inherited write descriptor
before its exec. This made run_recording_preempts_fake_ffmpeg_and_
preserves_window_semantics flaky on CI.

Retry the spawn up to five times with a short backoff on
ExecutableFileBusy; other errors fail immediately as before.

* fix(hls): resolve single-variant archive master in shared cache

Archive URLs that return a master playlist with one #EXT-X-STREA
child failed with segment_uri_without_extinf. The variant's media
playlist is now fetched and fed to the cache timeline.

- skip masters with several variants or separate #EXT-X-MEDIA tr
- send entry credentials only to the entry origin
- send master cookies only to the master origin
- merge master and variant session cookies by name
- keep the recovery binding on the entry URL
2026-10-06 19:28:11 +02:00
euzuandGitHub 91f6c57159 Fix/merge live and vod recording (#876)
feat(dvr)!: unify live and VOD/series recording into one recoverable DVR

Merge fix/merge_live_and_vod_recording into develop.

- One recording queue for scheduled live captures and VOD/series transfers,
  with a shared transition graph, provider-slot scheduling, resumable HTTP
  transfers (strong ETag / Last-Modified validation) and ffmpeg live capture.
- Crash-recoverable persistence: B+Tree repository with a journal-first
  recovery history; one file can be shared by several library entries.
- Admission checks quota and disk on request, at transfer start (real size)
  and before an entry attaches to a finished file; idempotent requests.
- REST is command-only; state reaches clients via owner-filtered WebSocket
  snapshots.
- Deleting a recording removes the file once no entry holds it; removing an
  entry keeps a finished file and cleans up orphaned partials.
- User ids derive from the configured username (web:/api:); the identity
  registry is gone.
- Spanish locale added; ru/ar completed; locale parity test.

BREAKING CHANGE: `video.download` is now `video.recording` (nested
`recording` keys move up, `download_priority`/`recording_priority` become
`priority`); old configs fail to load with a migration hint.
BREAKING CHANGE: `/api/v1/file/download*` and `/file/record` are removed in
favour of `/api/v1/recording/*`.
BREAKING CHANGE: `download.*` and `recording.write` permissions are replaced
by `recording.read|create|manage|delete`; tokens from before the change must
re-authenticate.
BREAKING CHANGE: the old recording queue does not migrate; existing
`identity_registry.json` is ignored.
2026-10-04 16:02:55 +02:00
euzuandGitHub 3b656f56b5 fix(hls): return upstream status for HLS resources (#896)
* fix(hls): return upstream status for HLS resources

- no TS fallback for failed segments, init and keys
- bounded capacity wait on pinned account (manifest 5s, media 2s)
- reject waiting requests after session end or account switch
- per-origin provider cookie jar, read at send time
- opt-in flussonic_hls_audio_tracks input option

* fix(hls): return upstream status for HLS resources

- no TS fallback for failed segments, init and keys
- bounded capacity wait on pinned account (manifest 5s, media 2s)
- reject waiting requests after session end or account switch
- per-origin provider cookie jar, read at send time
- opt-in flussonic_hls_audio_tracks input option

* fix(hls): return upstream status for HLS resources

- no TS fallback for failed segments, init and keys
- bounded capacity wait on pinned account (manifest 5s, media 2s)
- reject waiting requests after session end or account switch
- per-origin provider cookie jar, read at send time
- opt-in flussonic_hls_audio_tracks input option
2026-10-03 18:07:59 +02:00
a4feb08c48 fix(hls): keep provider account across client IP changes (#895)
* fix(hls): keep provider account across client IP changes

Wrap live HLS media playlists in a single-variant master whose variant
URI is a sealed owner token, so playlist refreshes from changing client
IPs keep their owner, lease and provider affinity. Expired sessions are
recreated from the token with the same access and admission checks.

- Classify HLS resources by playlist tag, not by .m3u8 extension
- Answer non-HLS 200 bodies as failed manifests (entry: unavailable,
  refresh: 502)
- Pin child manifests and media URIs to the resolving provider account
- Add reverse_proxy.stream.hls_wrap_media_playlist (default true)
- Split AppState into app_state/ containers; move HTTP clients to core

* fix(hls): keep provider account across client IP changes

Wrap live HLS media playlists in a single-variant master whose variant
URI is a sealed owner token, so playlist refreshes from changing client
IPs keep their owner, lease and provider affinity. Expired sessions are
recreated from the token with the same access and admission checks.

- Classify HLS resources by playlist tag, not by .m3u8 extension
- Answer non-HLS 200 bodies as failed manifests (entry: unavailable,
  refresh: 502)
- Pin child manifests and media URIs to the resolving provider account
- Add reverse_proxy.stream.hls_wrap_media_playlist (default true)
- Split AppState into app_state/ containers; move HTTP clients to core

* fix(hls): keep provider account across client IP changes

Wrap live HLS media playlists in a single-variant master whose variant
URI is a sealed owner token, so playlist refreshes from changing client
IPs keep their owner, lease and provider affinity. Expired sessions are
recreated from the token with the same access and admission checks.

- Classify HLS resources by playlist tag, not by .m3u8 extension
- Answer non-HLS 200 bodies as failed manifests (entry: unavailable,
  refresh: 502)
- Pin child manifests and media URIs to the resolving provider account
- Add reverse_proxy.stream.hls_wrap_media_playlist (default true)
- Split AppState into app_state/ containers; move HTTP clients to core

* fix(hls): keep provider account across client IP changes

Wrap live HLS media playlists in a single-variant master whose variant
URI is a sealed owner token, so playlist refreshes from changing client
IPs keep their owner, lease and provider affinity. Expired sessions are
recreated from the token with the same access and admission checks.

- Classify HLS resources by playlist tag, not by .m3u8 extension
- Answer non-HLS 200 bodies as failed manifests (entry: unavailable,
  refresh: 502)
- Pin child manifests and media URIs to the resolving provider account
- Add reverse_proxy.stream.hls_wrap_media_playlist (default true)
- Split AppState into app_state/ containers; move HTTP clients to core

* fix(hls): keep provider account across client IP changes

Wrap live HLS media playlists in a single-variant master whose variant
URI is a sealed owner token, so playlist refreshes from changing client
IPs keep their owner, lease and provider affinity. Expired sessions are
recreated from the token with the same access and admission checks.

- Classify HLS resources by playlist tag, not by .m3u8 extension
- Answer non-HLS 200 bodies as failed manifests (entry: unavailable,
  refresh: 502)
- Pin child manifests and media URIs to the resolving provider account
- Add reverse_proxy.stream.hls_wrap_media_playlist (default true)
- Split AppState into app_state/ containers; move HTTP clients to core

---------

Co-authored-by: euzu <euzu@proton.me>
2026-10-02 20:16:20 +02:00
euzuandGitHub d280a5484f fix(hls): reuse stable provider lease owners across playback retries (#890)
* fix(hls): reuse stable provider lease owners across playback retries

Keep public HLS tokens unique while sharing provider leases by
client/user/channel fingerprint. Preserve request ID and binding
generation guards and scope socket cleanup to the original session.

Add regression tests for repeated retries, stale cleanup, reused
sockets and M3U alias fallback with an A=2/B=4 provider pool.

* fix(hls): reuse stable provider lease owners across playback retries
- Keep public HLS tokens unique while sharing provider leases by
client/user/channel fingerprint. Preserve request ID and binding
generation guards and scope socket cleanup to the original session.

- Add regression tests for repeated retries, stale cleanup, reused
sockets and M3U alias fallback with an A=2/B=4 provider pool.

fix: proxy external Xtream VOD sources in M3U reverse mode
- Resolve stored VOD URLs using the existing input identity.
- Use canonical movie URLs for alias accounts with the original stream ID.
- Keep redirects internal and stop forwarding upstream Referer headers.
- Add regression tests for CDN URLs, aliases, ranges, and URL leakage

* fix(hls): reuse stable provider lease owners across playback retries
- Keep public HLS tokens unique while sharing provider leases by
client/user/channel fingerprint. Preserve request ID and binding
generation guards and scope socket cleanup to the original session.

- Add regression tests for repeated retries, stale cleanup, reused
sockets and M3U alias fallback with an A=2/B=4 provider pool.

fix: proxy external Xtream VOD sources in M3U reverse mode
- Resolve stored VOD URLs using the existing input identity.
- Use canonical movie URLs for alias accounts with the original stream ID.
- Keep redirects internal and stop forwarding upstream Referer headers.
- Add regression tests for CDN URLs, aliases, ranges, and URL leakage
2026-10-01 08:16:56 +02:00
euzuandGitHub 305587f40b fix: retry unstarted streams on an available provider alias (#885)
* **Bug Fixes**
  * Playback retries can use another available provider when playback has not started, helping requests proceed if the initially selected provider is unavailable.
  * Once playback has started, retries continue using the same eligible provider to preserve playback continuity.
  * Provider selection follows the same rules for regular playback and forced reopens, reducing unnecessary provider pinning before media begins.
  * Series episode URLs can resolve to the correct account-specific playback address.
2026-09-27 10:23:35 +02:00
725917f12b Fix/policy trusted destinations (#883)
* fixing resource url problem

* fix(resources): classify resource destinations per hop and keep the proxy in the fetch path
A resource URL is classified (public / non-public / local) before it reaches a client, and every
redirect hop is classified and fetched again: non-public hops connect directly, public hops go
through the configured proxy, local hops are refused. Adds the public no-redirect resource client,
a process-wide destination memo, and regression tests for the redirect and Web UI paths.

* fix(resources): classify resource destinations per hop and keep the proxy in the fetch path
A resource URL is classified (public / non-public / local) before it reaches a client, and every
redirect hop is classified and fetched again: non-public hops connect directly, public hops go
through the configured proxy, local hops are refused. Adds the public no-redirect resource client,
a process-wide destination memo, and regression tests for the redirect and Web UI paths.

---------

Co-authored-by: euzu <euzu@proton.me>
2026-09-26 17:03:09 +02:00
euzuandGitHub 2c07d52b93 Fixed max user connection screen when grace granted (#880)
* **Bug Fixes**
  * Improved live-stream session handling during instant grace periods, including when a session has not yet been created.
  * Corrected connection-limit and eviction tracking so active streams remain eligible for eviction even when their session record is unavailable.
  * Improved reliability when switching between live channels under connection limits.
* **Improvements**
  * Updated staged M3U overlays for Xtream providers: staged groups determine selected categories and channels, while unmatched categories remain available. Provider categories with no usable staged channels are retained.
* **Documentation**
  * Clarified how staged Xtream and M3U playlists affect provider categories and channels.
2026-09-25 08:22:11 +02:00
euzuandGitHub 2adc18adbc resource policy trusted destinations (#875)
* **New Features**
  * Added a Resource Policy editor for each input, supporting trusted hostnames and private network ranges.
  * Resource URLs now retain their source input and use authenticated links where supported.
  * Resource caching is scoped to the policy authorizing access.

* **Bug Fixes**
  * Invalid or unsupported resource values are safely discarded.
  * Redirects and destination addresses are rechecked against the applicable policy.

* **Breaking Changes**
  * Private DNS destinations require approved hosts and networks; private IP literals require an approved network.
  * Input and alias names must be non-empty and globally unique.
2026-09-22 15:02:22 +02:00
euzuandGitHub 6ffddc259a Provider pinned failover (#873)
- **New Features**
  - Added assertions for verifying which provider account handled the latest request.
  - Enabled provider-affine playback to fall back to another available provider when the pinned provider is unavailable.

- **Bug Fixes**
  - Improved provider fallback handling, origin request tracking, and session updates.
  - Preserved session headers when fallback stream setup fails and refreshed them after successful fallback.

- **Tests**
  - Added coverage for provider-pool failover, account reuse, limits, rejection handling, and eviction behavior.
2026-09-22 12:21:52 +02:00
euzuandGitHub 6a567d264e Feature/connection handling (#869)
* **New Features**
  * Added an opt-in runtime liveness watchdog with diagnostics, health status, and optional automatic restart.
  * Added configurable stream cleanup capacity and eviction re-entry protection.
  * Expanded configuration and UI access for users with playlist or user permissions, with safer data sanitization.
  * Added testkit scenarios and reporting for playback, admission, provider limits, sharing, and VOD behavior.
  * Added support for experimental-branch Docker builds.

* **Bug Fixes**
  * Improved provider prioritization, shared playback capacity, cleanup, reconnect handling, and concurrent client behavior.
  * Fixed playlist parsing for declared media types.
  * Release links now use the configured destination.
2026-09-19 10:17:23 +02:00
806dd574d3 User Agent (#861)
New Features

    Added an option to append a stable, numeric stream index to upstream User-Agent headers.
    Stream indexes remain consistent throughout a playback session, including manifests, segments, reconnects, seeks, and provider failover.
    Added a configuration checkbox for enabling the feature.

Documentation

    Documented the new configuration option, including session behavior and restart handling.
    Added English, Arabic, and Russian translations for the setting.



Co-authored-by: euzu <euzu@proton.me>
2026-09-05 17:14:49 +02:00
euzuandGitHub 70daecb9a3 epg programme id (#858)
New Features

    Programme icons are now captured when importing XMLTV electronic programme guides.
    Programme icons are preserved when combining programme data from multiple sources.
    Exported XMLTV guides now include programme icon information when available.
    Icon URLs are rewritten consistently when URL rewriting is enabled.

Bug Fixes

    Public resource requests now avoid following redirects and validate destinations before fetching.
    Resource caching behavior is now correctly applied according to the request type.

Compatibility

    Existing guides and legacy programme data remain supported when no icon is provided.
2026-09-05 10:18:32 +02:00
euzuandGitHub d116b7d51e Feature/bouquet editor (#854)
New Features

    Added target-specific bouquet filtering with whitelist and blacklist modes for Live, VOD, and Series groups.
    Added an in-context bouquet editor with search, selection controls, status indicators, reset, and streaming previews.
    Targets are managed by name, with saved selections available through the Source Editor.
    Improved stream alias resolution and provider failover behavior.

Bug Fixes

    Existing playlists are preserved when refreshes produce no usable items.
    Empty playlists are no longer published.
    Configuration changes now recover more safely from persistence failures.

Documentation

    Updated feature and configuration documentation and added translations.
2026-09-03 17:59:54 +02:00
euzuandGitHub 331a869859 Fix M3U alias credential rewriting on provider fallback (#852)
* Fix M3U alias credential rewriting on provider fallback

  Rewrite opaque authentication query parameters when stream allocation
  switches from the primary M3U provider to an alias.

  Support unambiguous cross-key mappings such as token to api_key while
  preserving unrelated query parameters and rejecting ambiguous mappings.

  Add regression coverage for URL rewriting and provider allocation.
2026-09-01 15:35:57 +02:00
euzuandGitHub 696060bca6 Fix M3U alias credential rewriting on provider fallback (#851)
* Fix M3U alias credential rewriting on provider fallback

  Rewrite opaque authentication query parameters when stream allocation
  switches from the primary M3U provider to an alias.

  Support unambiguous cross-key mappings such as token to api_key while
  preserving unrelated query parameters and rejecting ambiguous mappings.

  Add regression coverage for URL rewriting and provider allocation.
2026-09-01 09:32:58 +02:00
euzuandGitHub 99e5044599 Feature/refactor (#848)
* **New Features**
  * Added HLS live and catch-up playback for archived streams, manifests, segments, and provider failover.
  * Improved playlist processing with filtering, renaming, mapping, EPG handling, favourites, watch groups, staged overlays, and disk-based processing.
* **Documentation**
  * Added guidance for environment variables, credentials, password hashes, and authentication secrets.
* **Changes**
  * Removed target editing from the target menu; refresh and delete remain available.
* **Bug Fixes**
  * Improved recovery when cached playlist data is unreadable and strengthened archive stream URL handling.
2026-08-31 01:20:31 +02:00