Add end-to-end catch-up support for XC clients and native apps: provider
proxy with failover and per-viewer session pooling, REST session minting
for tokenless playback URLs, catch-up admin stats, combined connection
stats, and Stats UI with dedicated cards plus websocket updates.
Includes Redis namespace consolidation under timeshift:* (dropping legacy
timeshift_ id prefixes), dedicated catch-up stop by session_id, and
cleaner channel/client metadata split for stats keys.
Closes#133
The range-conflict warning classified each channel in the configured range as either this config's own auto-sync output or a real conflict, comparing each occupant against the source group. When a group sets a group_override, auto-sync creates its channels in the override target group, so the config's own channels failed that comparison and were misclassified as a conflict.
- Add effectiveSyncGroupId to resolve the group the sync's channels actually land in (the group_override target when set, otherwise the source group).
- Compare occupants against that effective target, so the config's own output is recognized while genuine conflicts (manual channels, channels from another account, channels in a different group, user-pinned numbers) still warn.
- Add Vitest coverage for the helper, the override case, and an over-suppression guard, plus a backend test asserting the numbers-in-range endpoint reports the override target group.
Implements all four points from the latest review, plus hardening from a
pre-submission audit pass.
1. Access control: timeshift_proxy now enforces
network_access_allowed(request, "STREAMS", user) — same key and placement
as the live XC stream endpoint.
2. Catch-up failover: the proxy walks the channel's catch-up streams in
channelstream order (get_channel_catchup_streams), mirroring live
playback. Each attempt carries its own provider context: account
credentials, provider stream id, reported server_info timezone (the
UTC->provider conversion is recomputed per attempt), user-agent, and the
per-account URL-format cache. The first streamable response wins; if all
providers fail the last failure is returned.
Ban-safety is per account: a decisive auth/ban-class failure (401/403/406)
marks the account and skips its remaining streams (e.g. FHD/HD variants of
the same channel) instead of hammering a banning provider, while other
accounts — different hosts — are still tried. Streams from disabled M3U
accounts are excluded, same as live dispatch. Redirects stay enabled on
purpose (XC providers legitimately 302 to load-balanced streaming nodes);
the 3xx decisive branch is kept as defense-in-depth and documented as such.
3. apps/proxy/live_proxy/views.py restored byte-identical to upstream — the
leftover channel-id wrapper from the removed provider-stream-id fallback
is gone (zero-line diff).
4. Single remaining setting relocated: xmltv_prev_days_override now lives in
proxy_settings (backend default in get_proxy_settings, consumed by the
XMLTV prev_days resolution). The timeshift_settings group,
TIMESHIFT_DEFAULTS, get_timeshift_settings, the Settings → Timeshift form
and tab are all removed; the field appears under Settings → Proxy Settings
(0 = auto-detect, capped at 30).
Audit hardening in the same pass:
- Updated the proxy-settings defaults unit test for the new key (would have
failed CI otherwise).
- Migration backfills use schema_editor.connection instead of the global
connection (multi-database correctness).
- CHANGELOG and module docstring brought in line with the final architecture
(PATH-first cascade, failover, setting under Proxy Settings).
- Tests grown to 69 backend tests: failover success/exhaustion/skip
semantics, decisive-account skip vs soft-failure retry, per-stream
timezone conversion (different zones per provider), 406/connection-error
cascade paths, stream-limit and no-eligible-stream outcomes,
network-gate 403, server_info strict-UTC guarantee, EPG duration window
resolution, and DB-backed coverage of xc_password auth, user_level access
and the failover stream ordering (catch-up-only, active accounts,
channelstream order). The format-cache test now runs on an isolated
locmem cache.
- Introduced a new method `_fetch_sd_countries` in `EPGSourceViewSet` to fetch SD countries directly from the backend, eliminating the need for a separate proxy endpoint.
- Updated the `sd_lineups` action to include the fetched countries in the response.
- Removed the `getSDCountries` method from the API and adjusted the frontend to fetch countries alongside lineups, improving efficiency
- Updated related components to handle the new data structure for countries.
Two coupled fixes that make catch-up play the requested programme:
1. Try the PATH catch-up form (/timeshift/.../{start}/{id}.ts) BEFORE the
timeshift.php query form. Empirical testing showed some XC providers
return the LIVE stream on the query form (HTTP 200, silently ignoring
`start`) — a valid MPEG-TS indistinguishable from a real archive, so the
cascade accepted it and the user always got live content. The PATH form
actually seeks. Candidate ordering now lives in
build_timeshift_candidate_urls() with the full rationale.
2. Strict-UTC XC API surface + single proxy-time timezone conversion:
- xc_get_epg start/end always UTC, server_info.timezone always "UTC",
time_now UTC — the timezone triple is consistently UTC.
- Removed the global default_timezone setting and the
_convert_xmltv_to_local_timezone rewrite entirely.
- The proxy converts the client's UTC timestamp to the SERVING provider's
own zone (server_info.timezone captured on account refresh, read from
the account's default profile) right before building the upstream URL —
DST-correct via ZoneInfo, no-op for UTC/unknown zones. Verified against
a real provider: it interprets the URL timestamp as its LOCAL wall
clock, so pure UTC pass-through seeks 1-2h off.
- EPG duration lookup keeps the ORIGINAL UTC timestamp (programmes are
stored in UTC) — exactly one conversion in the whole chain.
Also per review feedback:
- Removed the debug_logging toggle — verbose timeshift logging now follows
the standard logger DEBUG level (DISPATCHARR_LOG_LEVEL).
- Removed the dead default_language setting (never read anywhere; the EPG
lang field is hardcoded). TIMESHIFT_DEFAULTS is down to
xmltv_prev_days_override, and the Settings UI shows that single field
with accurate help text.
- Validate the timestamp up front (400 on malformed input) instead of
forwarding it verbatim into the upstream URL.
- Redact the upstream URL in the connection-error log (requests exceptions
embed the full URL, which carries XC credentials).
- URL-encode XC credentials in both URL builders.
- Request identity encoding upstream (the TS-sync peek reads raw bytes).
- Poll the stop key on the 5-second heartbeat cadence instead of every 100
chunks (~25 MB), so stream-limit terminations free the provider slot fast.
- New tests: proxy timestamp wiring (converted value reaches the URL
builder, original UTC value reaches the duration lookup), _redact_url,
decisive 3xx break (anti ban), invalid timestamp rejection; deflaked the
format-cache promotion test (django cache persists across runs).
- Improved logging in the Stream model for better debugging of profile evaluations.
- Introduced a new method `_stream_assignment_is_reusable` in the Channel model to determine if existing stream assignments can be reused, enhancing efficiency.
- Updated the release logic in `release_profile_slot` to utilize stored credential keys, reducing unnecessary database lookups.
- Simplified error handling in the `get_stream_info_for_switch` function to ensure proper stream release on exceptions.
- Enhanced tests for connection pool management and error handling in the ServerGroupsTable component to improve reliability and user feedback.
- Increased modal size for better visibility and user experience.
- Adjusted form layout for improved alignment and spacing between elements.
- Removed unused Checkbox component and simplified the account type selection logic.
- Consolidated VOD-related input fields under the Xtream Codes account type for clarity.
- Enhanced overall readability and maintainability of the component by reducing complexity in the form structure.
- Changed the size of the ServerGroupsManagerModal from "lg" to "md" for improved UI consistency.
- Refactored ServerGroupsTable to enhance the layout, including adjustments to column sizes and the addition of minimum sizes for better responsiveness.
- Simplified the RowActions component for better readability and alignment.
- Updated the loading and empty state handling in the table to provide clearer user feedback.
- Removed unused local storage hook from the component, streamlining the codebase.
- Eliminated redundant extraction of provider usernames from stream URLs in both ChannelStatus and VOD stats data functions, simplifying the codebase.
- Updated frontend components to reflect the removal of provider username display, streamlining the UI.
- Enhanced overall readability and maintainability of the code by reducing complexity in handling stream URLs.
- Renamed `_clear_stream_assignment_keys` to `_release_stale_stream_assignment` for clarity and updated its logic to release pool counters.
- Introduced new functions for managing credential slots during profile switches, enhancing the handling of shared connection limits across server groups.
- Removed the `max_streams` field from the `ServerGroup` model and updated related components to reflect this change, simplifying the server group management.
- Updated frontend components to integrate server group management, allowing for dynamic creation and editing of server groups.
- Enhanced error handling in stream URL generation to provide more informative feedback on connection issues.
- Added tests for stale assignment release and credential management during profile switches.
- Moved matching logic to a dedicated module for better organization and testability.
- Made single-channel auto-matching asynchronous, allowing for larger EPG libraries without hitting HTTP timeouts.
- Enhanced memory management and throughput during EPG matching, including optimizations for fuzzy matching and bulk processing.
- Fixed various reliability issues in the auto-matching process, ensuring accurate channel assignments and improved UI feedback.
- Updated API views and frontend components to reflect changes in the matching process and provide real-time notifications.
- Added tests for EPG matching functionality and name normalization.
- Single-channel and selected-channel auto-match always run, even when the channel already has EPG assigned; match-all (no channel IDs) still only processes channels without EPG.
The auto-sync overhaul added a [start, end] range and a shared numbering picker, but each mode's UI exposes only a subset of the persisted fields (Provider's "Start #" writes channel_numbering_fallback; Next Available exposes no Start/End) while the backend read auto_sync_channel_start and auto_sync_channel_end in every mode. Switching modes never resets the others, so a stale or auto-computed value silently changed numbering.
- Provider mode honors the provider-supplied number (stream_chno) verbatim; the group's Start (channel_numbering_fallback) and End bound only the fallback for streams the provider did not number. auto_sync_channel_start is no longer applied in provider mode.
- Next Available ignores End, since its UI exposes no range.
- Range enforcement (the overflow-delete) runs in fixed mode only, the one mode with a user-set [start, end] range.
- Provider mode gains the Start>End guard fixed mode already had, so an inverted fallback range cannot fail every numberless stream.
Includes backend and frontend regression tests.
- Addressed a bug where the EPG channel list did not refresh after a source finished parsing channels due to the `epg_refresh` WebSocket handler using a stale snapshot. The handler now correctly reads the current store state and ensures `fetchEPGData()` is called upon completion of channel parsing.
- Updated tests to verify that the frontend receives the correct parsing completion signals.
Upgrade vitest to version 4.1.8 and add @hookform/resolvers as a new dependency. Update related dependencies for @vitest packages to their latest versions, ensuring compatibility and improved functionality.
Add support for automatically applying channel logos from EPG data during refresh. Introduce a new toggle in the UI for enabling/disabling this feature, and update the backend to handle both channel IDs and EPG source IDs for logo application. Enhance the logo application task to process large libraries efficiently in chunks, improving performance and memory usage. Update changelog to reflect these changes.
Introduce a new poster style selection feature in the EPG settings, allowing users to choose their preferred artwork style. Update the logic for fetching and displaying program artwork from Schedules Direct, ensuring that the selected style is honored with appropriate fallbacks. Set default poster art to 'primary'. Add comprehensive tests to validate the poster selection functionality across various scenarios.
Add a new task to fetch program artwork from Schedules Direct and auto-apply logos to channels based on EPG data. Enhance the existing logic to handle poster backfill and update program records with fetched artwork. Readd the WebSocket handler to manage IP lookup events and adjust the EPGsTable component to display relevant credentials based on the source type.