Commit graph

3902 commits

Author SHA1 Message Date
SergeantPanda
f9a2968ec5 feat(range): add full restart range detection and enhance plain reconnect logic
Some checks are pending
Backend Tests / Plan test groups (push) Waiting to run
Backend Tests / (push) Blocked by required conditions
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run
This update introduces a new helper function `_is_full_restart_range` to determine when a request indicates a full restart from byte 0. The existing `_should_preempt_plain_reconnect` function has been modified to utilize this new logic, ensuring that plain GET requests and open-ended byte ranges are handled correctly. Additionally, new tests have been added to validate the behavior of these functions, confirming that they correctly identify restart scenarios and preempt playback as expected.
2026-07-18 00:43:09 +00:00
SergeantPanda
0aed30253b refactor(stats): simplify channel logo handling in stats data
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.
2026-07-17 23:21:44 +00:00
SergeantPanda
b24f39d9f8 fix(timestamps): enhance timestamp parsing to support mixed separators
This update modifies the timestamp parsing logic to accommodate various formats, including those using both dash and colon as separators for hours, minutes, and seconds. The changes ensure that timestamps like "HH-MM-SS" and mixed formats such as "HH-MM:SS" are correctly parsed and normalized. Additional tests have been added to validate these new parsing capabilities.
2026-07-17 22:53:21 +00:00
SergeantPanda
a40ac78ffd fix(live): resolve Redis state latching issue during buffering-timeout failover (Fixes #1449)
This update ensures that the Redis state for live channels is correctly cleared when a buffering-timeout failover occurs. Previously, the in-memory buffering flag could be cleared without updating Redis, leading to incorrect state reporting. The fix modifies the logic to clear the Redis state to 'active' when the buffering flag is reset, preventing stale 'buffering' states from persisting after recovery. Tests have been updated to validate this behavior.
2026-07-17 22:31:42 +00:00
SergeantPanda
8303ce27ee fix(plugins): improve plugin discovery in multi-worker setups (Fixes #1452)
This change ensures that plugin discovery does not force-reload on every connect event in multi-worker environments. By allowing local reloads in response to a newer `.reload_token`, the update prevents stale token issues that previously led to degraded worker performance. The explicit `force_reload=True` option is retained for installations, updates, or reloads, ensuring better resource management and stability. Tests have been updated to reflect this behavior.
2026-07-17 22:16:47 +00:00
SergeantPanda
692f2d27c1 fix(channels): update "Copy URL" functionality to exclude web player parameters
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.
2026-07-17 21:52:47 +00:00
SergeantPanda
84d2aedae5 fix(vod): prevent stale profile connection reservations in Redis-backed VOD sessions (Fixes #1426)
This update introduces atomic mutations for active_streams using Redis Lua scripts, ensuring that concurrent byte-range requests do not leave stale session metadata. The changes also include improvements to the session state saving mechanism, preventing the recreation of zombie sessions after idle cleanup. Additionally, tests have been added to cover the new atomic behavior and ensure reliability across various scenarios.
2026-07-17 21:35:32 +00:00
SergeantPanda
a78bc7aa48 changelog: Link issue. 2026-07-17 18:56:42 +00:00
SergeantPanda
02268bbd9e
Merge pull request #1445 from nagelm/fix/db-session-timezone-startup-packet
fix(db): pin session timezone to UTC via libpq startup packet (#651)
2026-07-17 13:34:15 -05:00
SergeantPanda
31f448c673 changelog: add clarity. 2026-07-17 18:33:42 +00:00
SergeantPanda
fc8b955b36 changelog: Update for pr 1445. 2026-07-17 16:46:39 +00:00
SergeantPanda
5714cf23cf Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into pr/nagelm/1445 2026-07-17 16:00:11 +00:00
SergeantPanda
097e7118ef Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into dev
Some checks are pending
Backend Tests / Plan test groups (push) Waiting to run
Backend Tests / (push) Blocked by required conditions
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run
2026-07-17 15:45:34 +00:00
SergeantPanda
52c97120fb
Merge pull request #1442 from nagelm/fix/machine-independent-date-tests
test(frontend): make date assertions machine-independent
2026-07-17 10:45:02 -05:00
SergeantPanda
9da83d76fa changelog: Update for pr 1442 2026-07-17 15:44:25 +00:00
SergeantPanda
b91385aacb Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into pr/nagelm/1442 2026-07-17 15:40:28 +00:00
SergeantPanda
1f30e2076d
Merge pull request #1441 from nagelm/fix/toast-html-error-bodies
fix(ui): stop rendering raw HTML error pages in toast notifications (#1261, item 1)
2026-07-17 10:33:36 -05:00
SergeantPanda
5263e18ed9 fix(api): improve error handling for API responses
- 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.
2026-07-17 15:31:56 +00:00
SergeantPanda
9ee5ba2535 Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into pr/nagelm/1441 2026-07-17 15:19:35 +00:00
SergeantPanda
6157bc1177 changelog: update for url validation pr. 2026-07-17 14:04:03 +00:00
SergeantPanda
42248743fa
Merge pull request #1381 from recurst/patch-1
Allow underscores in non-FQDN hostnames
2026-07-17 09:01:13 -05:00
SergeantPanda
540f3d9bed Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into dev 2026-07-17 13:57:34 +00:00
SergeantPanda
61df45c895 changelog: Update for frontend test/refactor pr. 2026-07-17 13:56:26 +00:00
SergeantPanda
1b99f105c4
Merge pull request #1444 from nick4810/tests/frontend-unit-tests
Tests/frontend unit tests
2026-07-17 08:52:42 -05:00
SergeantPanda
8bcc7c9ebe feat(timeshift): enhance catch-up programme handling and UI updates
Some checks are pending
Backend Tests / Plan test groups (push) Waiting to run
Backend Tests / (push) Blocked by required conditions
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run
- 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.
2026-07-16 23:10:06 +00:00
SergeantPanda
6f62d807f4 feat(timeshift): add position reporting for catch-up sessions
- 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.
2026-07-16 22:06:27 +00:00
SergeantPanda
14bfd25d9a feat(timeshift): enhance catch-up session handling with optional duration support
- Introduced an optional `duration` parameter for catch-up sessions, allowing clients to specify the programme length in minutes. This value is preferred over EPG-derived durations and includes a buffer for provider lag.
- Updated the API views and serializers to accept and process the new `duration` field.
- Enhanced the catch-up proxy implementation to utilize the client-supplied duration, improving playback accuracy.
- Added tests to validate the new duration handling and ensure proper integration with existing functionality.
2026-07-16 21:26:06 +00:00
SergeantPanda
d3d51780dd fix(schema): enhance Swagger/OpenAPI schema generation for concurrent requests 2026-07-16 19:24:46 +00:00
SergeantPanda
cdfe16ae5d fix(schema): resolve Swagger/OpenAPI schema generation issues under concurrent requests
- 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.
2026-07-16 18:57:57 +00:00
SergeantPanda
388c4bd28d Enhancement: update catch-up features and enhance stream ordering logic
Some checks are pending
Backend Tests / Plan test groups (push) Waiting to run
Backend Tests / (push) Blocked by required conditions
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run
- 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.
2026-07-16 15:33:34 +00:00
SergeantPanda
6bd42c83f4
Merge pull request #1440 from dillardblom/fix/catchup-incoming-query-url-style
Some checks are pending
Backend Tests / Plan test groups (push) Waiting to run
Backend Tests / (push) Blocked by required conditions
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
fix(timeshift): accept QUERY-style incoming catch-up requests (streaming/timeshift.php)
2026-07-15 17:22:51 -05:00
SergeantPanda
e6244adc0b docs: Remove mentions of specific clients as they could change and isn't fully inclusive anyway. 2026-07-15 22:16:00 +00:00
SergeantPanda
b475bbc07b changelog: add support for QUERY-style catch-up requests 2026-07-15 22:08:35 +00:00
SergeantPanda
23dc7c0a92 Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into fix/catchup-incoming-query-url-style 2026-07-15 22:05:35 +00:00
SergeantPanda
33ada59dba fix(timeshift): refine catch-up timestamp handling and enhance EOF probe logic
Updated the catch-up timestamp normalization to reflect XC client specifications. Introduced a new mechanism to handle near-EOF duration probes, ensuring that playback statistics are preserved without reanchoring to the end of the file. Additionally, improved the handling of presentation lengths in the timeshift proxy to align with XC behavior. Updated tests to validate these changes and ensure robust playback functionality.
2026-07-15 21:26:25 +00:00
nagelm
49189465d2 fix(db): pin session timezone to UTC via libpq startup packet
DB sessions were never actually pinned to UTC. Three stacked failures:

1. The connection_created receiver (_force_utc0 in core/apps.py) was a
   nested closure connected with Django's default weak reference. It was
   garbage-collected as soon as CoreConfig.ready() returned, so
   SET TIME ZONE 'UTC0' fired into a dead weakref and never executed -
   in any version since it landed (verified: the signal's receivers list
   on a live 0.27.2 shows a dead weakref).

2. Sessions were UTC on older stacks anyway because Django's own
   init_connection_state configured the timezone. Since native
   psycopg-pool support (Django 5.1+), that path is gated on
   `not self.pool` - and the geventpool mixin's `pool` property is
   always truthy, so Django silently skips timezone (and role)
   configuration for this backend on every connection. This is what
   actually regressed at the psycopg2->3 / Django upgrade: the masking
   layer disappeared, not the (already dead) signal.

3. psycopg3 logs "unknown PostgreSQL timezone: 'UTC0'" because the
   POSIX spec is unresolvable in Python zoneinfo (cosmetic, but it
   means 'UTC0' buys nothing on psycopg3).

Net effect: every session ran at the server-default timezone (verified
live: SHOW TimeZone through the pool returns 'Etc/UTC'). Deployments
whose Postgres default is non-UTC (e.g. /etc/localtime bind-mounts,
the original issue 651 report) get the EPG offset corruption back.

Fix: pin the GUC in the libpq startup packet in the pool backend's
get_connection_params():

- covers every connection the gevent pool creates; no signal, GC, or
  Django-flow dependency (same pattern as the client_encoding pin the
  pool already applies)
- startup-packet GUCs are the session default: they survive ROLLBACK,
  and RESET TimeZone returns to UTC rather than the server default
- 'UTC' resolves cleanly in psycopg3's zoneinfo lookup, and PostgreSQL
  resolves it against its own bundled tzdata, not host-mounted files

The dead signal is removed. Regression tests exercise the session
timezone through the real pool backend explicitly (the test runner's
default engine is the vanilla Django backend), and assert the
RESET-returns-to-UTC session-default property.

Tested: live 0.27.2 AIO (psycopg 3.3.4, PostgreSQL 17) - unpatched
backend+pool session shows 'Etc/UTC'; patched shows 'UTC' incl. after
RESET and ROLLBACK. Full A/B against the dev image with the server
default forced to Europe/Zurich: stock renders a 12:00Z source
programme as start="20260715140000 +0000" in /output/epg; patched
renders it correctly; the regression tests fail on stock and pass
when patched.
2026-07-15 10:20:38 +12:00
Nick Sandstrom
817ebf21a9 Added tests for components 2026-07-14 14:21:54 -07:00
Nick Sandstrom
07d17a5ffc Extracted ManageReposModal from PluginBrowse 2026-07-14 14:21:53 -07:00
Nick Sandstrom
99fc71de99 Slight refactoring of components 2026-07-14 14:21:53 -07:00
Nick Sandstrom
f6ad115a1f Added tests for utils 2026-07-14 14:21:53 -07:00
Nick Sandstrom
6d5a5a549a Extracted utils 2026-07-14 14:21:53 -07:00
nagelm
8cb1dab5ce test(frontend): make date assertions machine-independent
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.
2026-07-14 23:00:04 +12:00
nagelm
ed1c449234 fix(ui): stop rendering raw HTML error pages in toast notifications (#1261)
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
2026-07-14 20:37:58 +12:00
SergeantPanda
d1344adb4f chore(uwsgi): update configuration for worker reload mechanism
Added a new file entry to .gitignore for .uwsgi-reload and modified uwsgi.debug.ini to implement a touch-based worker reload mechanism, replacing the previous py-autoreload setting. This change enhances the management of API worker reloads during development.
2026-07-14 00:53:03 +00:00
SergeantPanda
ab8e3f93c6 tests: Fix backend timeshift test.
Some checks failed
Backend Tests / Plan test groups (push) Has been cancelled
CI Pipeline / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
Backend Tests / (push) Has been cancelled
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Has been cancelled
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
CI Pipeline / create-manifest (push) Has been cancelled
2026-07-13 23:31:31 +00:00
Dillard Blom
e5d33861e6 Accept QUERY-style incoming catch-up requests (streaming/timeshift.php)
Clients that build catch-up requests in QUERY layout (e.g. Open-TV /
Fred TV: /streaming/timeshift.php?username=...&stream=...&start=...)
had no matching urlpattern, so the request silently fell through to
the frontend's <path:unused_path> catch-all and got served index.html
(200 OK, wrong content) instead of reaching the proxy — no error, no
log line, the client just fails to play.

The PATH-style layout (timeshift/<user>/<pass>/<stream_id>/<ts>/<dur>)
already worked; QUERY-style autodetection already existed for outgoing
provider requests (helpers.build_timeshift_url_format_a/_b) but was
never mirrored to the incoming route.

Split timeshift_proxy into a shared _timeshift_proxy_impl plus two thin
entry points (PATH-style timeshift_proxy, new QUERY-style
timeshift_proxy_query) so both incoming layouts are recognized.

Reported against the predecessor plugin as dispatcharr_timeshift#10;
reproduced identically against dispatcharr:dev (confirmed via nginx
access log: a QUERY-style request returned 200 with a response body
exactly matching the size of frontend/dist/index.html).
2026-07-13 22:13:42 +02:00
SergeantPanda
ea9eaf4d0c fix(timeshift): enhance session handling and playback logic
Some checks failed
Backend Tests / Plan test groups (push) Has been cancelled
CI Pipeline / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
Frontend Tests / test (push) Has been cancelled
Backend Tests / (push) Has been cancelled
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Has been cancelled
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
CI Pipeline / create-manifest (push) Has been cancelled
Updated the session handling mechanism to improve user experience during reconnects. The first request without a `session_id` now receives a `301` redirect with a minted `session_id`, while reconnects that omit `session_id` but match an existing pool entry are served immediately without a redirect. Additionally, refined playback logic for plain GET requests to restart from byte 0, aligning with provider behavior. Updated tests to reflect these changes and ensure proper session reuse and playback anchoring.
2026-07-12 21:09:40 +00:00
SergeantPanda
58d60bf733 chore(changelog): update CHANGELOG.md to reflect recent enhancements in unit tests and Backup Manager functionality
- 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.
2026-07-12 14:35:05 +00:00
SergeantPanda
d56680cad8
Merge pull request #1424 from nick4810:tests/frontend-unit-tests
Tests/frontend unit tests
2026-07-12 09:27:26 -05:00
SergeantPanda
2f60dc91ae fix(proxy): enhance stream switching logic and error handling
Some checks failed
Backend Tests / Plan test groups (push) Has been cancelled
CI Pipeline / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
Frontend Tests / test (push) Has been cancelled
Backend Tests / (push) Has been cancelled
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Has been cancelled
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
CI Pipeline / create-manifest (push) Has been cancelled
Updated the stream switching mechanism in the proxy server to ensure that the `stream_id` is persisted correctly and that the requesting worker waits for confirmation from the owning worker in multi-worker deployments. Improved error handling for stream switch failures, returning appropriate HTTP status codes (502/504) based on the confirmation status. Additionally, refined the metadata update process to handle cases where the requested URL is already in use, ensuring a successful response without unnecessary operations. This change addresses issues with stale metadata and enhances the robustness of the stream switching feature. (Fixes #1412)
2026-07-11 18:21:48 +00:00