This update refactors the logic for building timeshift statistics by removing unnecessary `select_related` calls and the `logo_url` field from the connections. The changes streamline the data retrieval process and ensure that only the `logo_id` is exposed in the session data. Corresponding tests have been updated to reflect these modifications.
This change modifies the "Copy URL" action in the Channels table to generate a plain proxy URL without including web player output profile parameters. The update ensures that copied links are suitable for external players, enhancing usability. Additionally, tests have been updated to verify the new behavior of the "Copy URL" feature.
- Enhanced the `formatApiError` function to better format failed API responses, preventing raw HTML error pages from being displayed in toasts. JSON error bodies are now prioritized for user-friendly messages, while HTML and empty bodies are collapsed to a concise status line. Long plain-text bodies are truncated for readability.
- Updated tests to cover new error formatting behavior, ensuring accurate extraction of error messages from various JSON structures.
- Updated the catch-up stats UI to advance to the next EPG programme when playback continues past the original programme's end, improving user experience.
- Enhanced the `get_programme_info` function to resolve the guide entry based on the playhead position, ensuring accurate display of the current programme.
- Introduced new utility functions for computing catch-up playback position and checking if the playhead is outside the displayed programme window, optimizing session management.
- Added tests to validate the new functionality and ensure correct behaviour of the catch-up features.
- Introduced a new endpoint `POST /api/catchup/sessions/<session_id>/position/` for native clients to report their playhead position and pause state during catch-up sessions.
- Updated the catch-up session handling to include a `paused` flag, allowing accurate tracking of playback state without seeking the provider stream.
- Enhanced the Redis storage mechanism to accommodate the new position and pause data, ensuring real-time updates for admin stats.
- Added tests to validate the new position reporting functionality and its integration with existing catch-up features.
- Implemented a new `LockedSpectacularAPIView` to handle schema generation, ensuring it no longer fails due to concurrent gevent requests. The schema builds are now single-flight per process and cached in Django's cache, allowing all workers to share the result.
- Updated the `urls.py` to use the new view for schema generation, enhancing stability and performance.
- Improved multi-provider failover by preferring streams with sufficient catch-up days.
- Added new helper functions for calculating programme age and ordering catch-up streams.
- Removed deprecated XMLTV settings from the frontend and backend.
- Updated tests to validate new stream ordering logic and catch-up functionality.
Three tests encoded the machine's timezone or locale into their
expectations and fail on any box east of UTC (observed on UTC+12/13;
CI's UTC and US-locale dev machines never see it):
- dateTimeUtils isSame: compared 10:00Z/11:00Z on the 15th as 'same
day', but isSame works on local calendar days and no UTC instant
falls on the same date in every timezone (at UTC+13 those are 23:00
on the 15th and 00:00 on the 16th). Use timezone-less datetimes,
which mean the same calendar day everywhere.
- RecordingUtils toDateString: formatted a UTC-noon instant and
expected the UTC date, but toDateString renders local time (UTC+12
renders the next day). Construct the Date with local components.
- SeriesModalUtils getEpisodeAirdate: the code renders the viewer's
locale via toLocaleDateString() by design, but the test hardcoded
the en-US shape (it tolerated the timezone day-shift with /1[4|5]/
yet not the day/month order). Compute the expectation with the same
API so the test asserts the wiring, not a specific locale.
No production code changes.
Failed API responses whose body is not JSON - Django's HTML "Server
Error (500)" page, nginx's HTML 502/504 pages when the backend is down
or timing out - were interpolated verbatim into the error toast,
showing users a wall of markup.
request() deliberately keeps the raw text when JSON.parse fails, and
errorNotification() rendered `${status} - ${body}` unconditionally.
Route the body through a new formatApiError() helper (in utils.js so it
is unit-testable without importing the store-heavy api module):
- JSON object bodies keep their existing pretty-printed formatting
- markup and empty bodies collapse to the response's own status line:
the declared Content-Type decides what counts as markup (body
sniffing only as fallback when the header is missing), and the label
comes from the fetch Response's statusText - the protocol's reason
phrase, defined for every status code, rather than a hardcoded status
map. HTTP/2+ transmits no reason phrase, so an empty statusText falls
back to a generic label. request() already attaches the Response to
the error, so no call-site changes are needed.
- the full suppressed body goes to console.debug so the markup stays
available for troubleshooting (deliberate, not a leftover debug
statement)
- plain-text bodies are truncated at 200 chars as a backstop
- errors without a status keep the error.message fallback
- Added entry for extended frontend unit tests covering plugin, backup, and settings components.
- Updated Backup Manager to ensure the "Created" column refreshes when date/time format preferences change.
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