Commit graph

73 commits

Author SHA1 Message Date
None
e5206545dd fix(dvr): add stream reconnection resilience, fix comskip exit code handling
- Add reconnection loop to DVR streaming: on transient connectivity loss (ReadTimeout, ConnectionError, ChunkedEncodingError), the recording task retries the same TS proxy base up to 5 times with a 2-second delay, appending to the existing file. Counter resets on successful data receipt. TS container format tolerates brief discontinuities; MKV remux normalises timestamps.
- Extract _check_recording_cancelled() helper to consolidate repeated stop/delete DB checks across the streaming and reconnection paths.
- Fix comskip treating exit code 1 (no commercials detected) as a fatal error.
  Use check=False and handle return codes explicitly: 0 = commercials found,
  1 = no commercials (skipped), negative = signal, other = real error.
- Add human-readable reason messages for comskip 'skipped' notifications in
  WebSocket handler.
- Remove redundant conditional Channel import in stream_generator._cleanup() that shadowed the module-level import, causing UnboundLocalError when the conditional branch did not execute.
2026-03-04 10:21:02 -06:00
None
f28530a47b fix(dvr): add recording extend, fix cross-recording interference, artwork race, and keepalive gaps
File changes:

Backend

apps/channels/api_views.py — Added extend() action that uses queryset .update() to bypass signals, letting the running task pick up the new end_time via polling. Moved WS recording_stopped notification to synchronous (before HTTP response). Refactored destroy() to delete DB row first, send WS event immediately, defer cleanup to background thread.

apps/channels/signals.py — Added pre_save guard to skip task revocation when status is "recording". Added post_save reentrancy guard to skip artwork prefetch for internal field-only saves (custom_properties, task_id, end_time).

apps/channels/tasks.py — Added 2-second polling loop in streaming that checks for stop, deletion, and extended end_time. Added refresh_from_db() + merge before metadata save to prevent overwriting concurrent artwork prefetch. Replaced inline PeriodicTask cleanup with revoke_task()/_dvr_task_name(). Consolidated redundant DB queries in error path. Fixed TOCTOU os.path.exists + os.remove. Preserved "stopped" status in final-status logic instead of overwriting with "completed".

core/utils.py — Made send_websocket_update gevent-safe by detecting monkey-patching and offloading async_to_sync to gevent's native threadpool, fixing the event loop deadlock that caused cross-recording interference.

apps/proxy/ts_proxy/client_manager.py — Moved _trigger_stats_update to a background thread so remove_client() returns immediately.

apps/proxy/ts_proxy/stream_generator.py — Added Redis-based health check for non-owner workers in _should_send_keepalive(), so keepalives fire correctly even when stream_manager is None.

Frontend

frontend/src/WebSocket.jsx — Added 400ms debounced scheduleRecordingFetch() replacing all inline fetchRecordings() calls. Added recording_extended and recording_updated event handlers. recording_cancelled now does surgical removeRecording() by ID when available.

frontend/src/api.js — Added extendRecording(id, extraMinutes).

frontend/src/components/cards/RecordingCard.jsx — Added Extend menu (+15m/+30m/+1h) for in-progress recordings. Widened Comskip button to stopped/interrupted statuses.

frontend/src/components/forms/ProgramRecordingModal.jsx — Removed manual fetchRecordings() calls, relying on WS-driven debounced refresh.

frontend/src/components/forms/RecordingDetailsModal.jsx — Added stopped to playable statuses. Widened Comskip button. Removed manual fetchRecordings().

frontend/src/components/forms/RecurringRuleModal.jsx — Removed all manual fetchRecordings() calls, relying on WS events.

frontend/src/pages/Guide.jsx — Removed isLoading subscription that caused loading flash on debounced refresh. Removed manual fetchRecordings() after saving a series rule.

frontend/src/store/channels.jsx — Stripped isLoading/error state from fetchRecordings to prevent full-page loading indicators. Added no-op guards in removeRecording.

frontend/src/utils/cards/RecordingCardUtils.js — Added extendRecordingById wrapper.

Tests

apps/channels/tests/test_recording_extend.py (new) — 14 tests: extend endpoint validation, stacked extensions, signal bypass, pre_save guard behavior.

apps/channels/tests/test_recording_stop_cancel.py (new) — 18 tests: stop endpoint, DVR client teardown, cancel was_in_progress flag, run_recording race guards, signal reentrancy guards.

apps/channels/tests/test_ts_proxy_keepalive.py (new) — 21 tests: keepalive owner/non-owner logic, stats update error handling, client removal non-blocking, timing invariants.

apps/channels/tests/test_recording_scheduling.py — Updated mock assertion to match new _stop_dvr_clients call signature.

Summary:

Adds an Extend action for in-progress recordings that bypasses Django signals and lets the running task dynamically pick up the new end_time via its 2-second DB polling loop. Fixes cross-recording interference caused by send_websocket_update deadlocking the gevent event loop. Fixes an artwork race condition where run_recording overwrote concurrent prefetch data. Adds Redis-based keepalive health checks for non-owner workers to prevent DVR read timeouts during source transitions. Replaces manual fetchRecordings() calls throughout the frontend with a debounced WS-driven refresh. 53 new tests.
2026-03-04 10:21:02 -06:00
None
bd1e060bd2 fix(dvr): fix duplicate recording execution and add manual stop
Fixes #940: Duplicate DVR task executions were caused by ClockedSchedule objects being shared across PeriodicTasks, triggering run_recording multiple
times for the same recording. Added an idempotency guard in run_recording that exits early if status is already 'recording', 'completed', or 'stopped'.

revoke_task() now deletes the PeriodicTask and orphaned ClockedSchedule on execution rather than relying on Celery revocation alone.

Fixes #454: Added POST /api/channels/recordings/{id}/stop/ action that marks the recording as stopped and terminates only the specific DVR proxy client (identified via User-Agent: Dispatcharr-DVR/recording-{id}) without disrupting
simultaneous recordings on the same or other channels. The API returns
immediately; DVR client teardown and task revocation happen in a background thread to avoid 504 timeouts on the recordings list endpoint.

Additional changes:
- destroy() now only calls _stop_dvr_clients() for in-progress recordings, preventing accidental stream termination when deleting completed recordings
- WebSocket events differentiated: recording_stopped, recording_cancelled (in-progress cancel), and recording_cancelled (delete) with was_in_progress flag so the frontend shows distinct "Recording deleted" vs "Recording cancelled" notifications

- Frontend: Stop and Cancel split into separate buttons with confirmation
  modals; stopped recordings move immediately to Previously Recorded via
  optimistic status bucketing; removed dead 'Stopped' badge state

- 27 new unit tests covering scheduling, idempotency, revocation, and DVR client isolation
2026-03-04 10:21:02 -06:00
dekzter
f1d6b86278 refactored frontend usage of 'all channels' to only pull down IDs, query for individual channels as necessary 2026-02-13 11:46:17 -05:00
SergeantPanda
b01eb9585c feat: add system notifications and update checks
Real-time notifications for system events and alerts
Per-user notification management and dismissal
Update check on startup and every 24 hours to notify users of available versions
Notification center UI component
Automatic cleanup of expired notifications
2026-02-03 09:24:02 -06:00
SergeantPanda
e4b312d136 Enhancement: Requery channels and streams after rehashing completes 2026-01-31 14:44:52 -06:00
Jeffrey C
29395f0538
unify StreamsTable refresh with channels requery 2026-01-14 13:07:08 -06:00
SergeantPanda
6b873be3cf Bug Fix: Fixed bulk and manual channel creation not refreshing channel profile memberships in the UI for all connected clients. WebSocket channels_created event now calls fetchChannelProfiles() to ensure profile membership updates are reflected in real-time for all users without requiring a page refresh. 2026-01-11 17:51:00 -06:00
SergeantPanda
3b34fb11ef Fix: Fixes bug where Updated column wouldn't update in the EPG table without a webui refresh. 2025-12-04 15:43:33 -06:00
SergeantPanda
e7700b60f3 Enhancement: Add validation for EPG objects and payloads in updateEPG functions to prevent errors from invalid data 2025-11-21 15:10:54 -06:00
SergeantPanda
e6146e5243 Bug fix: Reduce websocket message size when processing epgs. Also remove unnecessary console logging during epg refresh. Fixes [Bug]: Page goes blank if sending too many requests / responses
Fixes #327
2025-11-04 18:23:45 -06:00
SergeantPanda
22fb0b3bdd Enhancement: Add Custom Dummy EPG with Dynamic Pattern Matching and Name Source Selection
This enhancement introduces a powerful custom dummy EPG system that allows users to generate EPG programs on-demand by parsing channel or stream names using configurable regex patterns.

Key Features:
- Custom Pattern Matching: Define regex patterns to extract information from channel/stream names (teams, leagues, times, dates, etc.)
- Flexible Name Source: Choose to parse either the channel name or a specific stream name (by index)
- Timezone-Aware Scheduling: Automatic DST handling using pytz timezone names (e.g., 'US/Eastern', 'Europe/London')
- Time Format Support: Parse both 12-hour (AM/PM) and 24-hour time formats
- Date Parsing: Extract dates from names with flexible month/day/year patterns
- Custom Templates: Format EPG titles and descriptions using captured groups with {placeholder} syntax
- Upcoming/Ended Customization: Define custom titles and descriptions for programs before and after scheduled events
- Live Preview: Test patterns and templates in real-time with sample input
- Smart Program Generation: Automatically creates "Upcoming" and "Ended" programs around scheduled events

Use Cases:
- Sports channels with event details in stream names (e.g., "NHL 01: Bruins VS Leafs @ 8:00PM ET")
- Movie channels with genre/title/year information
- Racing events with driver/track/series details
- Any scenario where EPG data is embedded in channel/stream naming conventions

Technical Implementation:
- Backend: Pattern matching engine with timezone conversion and program scheduling logic
- Frontend: Interactive form with validation, pattern testing, and visual group preview
- Name Source Options: Parse from channel name or selectable stream index (1-based)
- Fallback Behavior: Uses standard dummy EPG if patterns don't match
- Custom Properties: Stores all configuration in EPGSource.custom_properties JSON field

Configuration Options:
- Title Pattern: Extract primary information (required)
- Time Pattern: Extract hour/minute/AM-PM (optional)
- Date Pattern: Extract month/day/year (optional)
- Timezone: Event timezone with automatic DST support
- Program Duration: Length of generated programs in minutes
- Title Template: Format EPG title using captured groups
- Description Template: Format EPG description using captured groups
- Upcoming Title Template: Custom title for programs before event starts (optional)
- Upcoming Description Template: Custom description for programs before event starts (optional)
- Ended Title Template: Custom title for programs after event ends (optional)
- Ended Description Template: Custom description for programs after event ends (optional)
- Name Source: Channel name or stream name
- Stream Index: Which stream to use when parsing stream names (1, 2, 3, etc.)

Closes #293
2025-10-18 12:08:56 -05:00
SergeantPanda
8794156767 Enhancement: Only fetch playlists and channel profiles after successful m3u refresh not every m3u_refresh status update. This should reduce network traffice and efficiency.
This may fix #327
2025-10-07 10:02:26 -05:00
SergeantPanda
da245c409a Bug fix: Backend now notifies frontend when a new playlist is creating. This should fix where accounts will sometimes only show fetching groups after a new account is added. 2025-10-07 09:55:35 -05:00
SergeantPanda
9ef2aa966d Requery channels when setting channel names from epg. 2025-09-16 19:44:41 -05:00
SergeantPanda
7e13e51198 Update the frontend on logo change. 2025-09-16 17:55:55 -05:00
SergeantPanda
3cb5a061c9 Show progress as notifications. 2025-09-16 17:35:38 -05:00
SergeantPanda
6384f4f56f Add progress notifications for EPG matching process 2025-09-16 13:47:59 -05:00
SergeantPanda
a1d35a8dad Additional check if channel number is in use before creating. 2025-09-14 13:34:03 -05:00
SergeantPanda
05641cfb02 Remove duplicate websocket notification 2025-09-13 20:30:18 -05:00
SergeantPanda
7866eed613 Fetch channels after successful creation of channels. 2025-09-13 20:21:27 -05:00
SergeantPanda
301a162e71 Switch to normal notifications 2025-09-13 20:16:14 -05:00
SergeantPanda
cf7ea09341 Implement asynchronous bulk channel creation from stream IDs with WebSocket progress updates 2025-09-13 19:59:43 -05:00
SergeantPanda
84c752761a Ability to refresh account info from account info modal and provide notification on results. 2025-09-09 18:15:33 -05:00
OkinawaBoss
3fb8e0ebd1
Merge pull request #363 from Dispatcharr/Plugins
Plugins
2025-09-08 09:11:19 -05:00
Dispatcharr
e9a11588c4 Init Plugins 2025-09-05 17:10:11 -05:00
SergeantPanda
f1196bb988 Send websocket update on client disconnect and connect. 2025-09-05 12:04:30 -05:00
Dispatcharr
f652d2b233 Comskip Update 2025-09-04 13:45:25 -05:00
Dispatcharr
00cc83882a DVR update 2025-09-03 21:35:45 -05:00
SergeantPanda
774c80e2a4 Convert a couple more functions to fetch ALL logos. 2025-08-26 16:42:16 -05:00
SergeantPanda
39598b4ff4 Refactor logo handling: Introduce useLogosStore, implement lazy loading for logos, and update components to use new store methods. 2025-08-22 09:56:20 -05:00
SergeantPanda
491b0cea29 Fetch channel profiles on successful m3u refresh. 2025-07-27 19:27:50 -05:00
SergeantPanda
d926d90dd9 Fix websocket message. 2025-07-18 15:14:11 -05:00
SergeantPanda
479826709b Fetch logos when logos are added by filesystem scan. 2025-07-18 15:01:26 -05:00
SergeantPanda
13672919d0 Fetch Playlists on successful m3u update. 2025-07-18 14:26:09 -05:00
SergeantPanda
db10e90801 Enhance rehash_streams task to send WebSocket notifications for blocked rehash attempts.. 2025-07-11 15:51:19 -05:00
SergeantPanda
8ec489d26f Send websocket updates during rehash. 2025-07-11 14:47:12 -05:00
SergeantPanda
0ec5ffff33 Fix status message not updating the frontend during M3U refresh. 2025-06-06 08:00:19 -05:00
SergeantPanda
e7439a074f Enhance WebSocket connection handling based on authentication status 2025-05-13 16:57:39 -05:00
dekzter
9c9e546f80 websockets behind auth, cleaned up errors and bad state handling in websocket.jsx 2025-05-10 08:40:53 -04:00
SergeantPanda
e9c5a719b1 Better handling for notifying of groups needing to be edited. 2025-05-06 10:09:59 -05:00
SergeantPanda
c225edc3ec Fixes updated time not updating the local state. 2025-05-06 08:19:05 -05:00
SergeantPanda
452e2ee213 Fixes status not changing to fetchign and parsing when those operations are occuring. 2025-05-06 08:13:59 -05:00
SergeantPanda
ae93bc2a1f Adds a "Pending Setup" status so the user knows they need to select groups before their streams are imported. 2025-05-05 19:50:20 -05:00
SergeantPanda
30e82fb302 Lots of status message fixes. 2025-05-04 19:33:03 -05:00
SergeantPanda
b713b516b4 Convert m3u accounts to a similar format to epg for status updates. Renamed DB field last_error to last_message so we can use it for more messaging. Migration to change updated_at field to not be updated everytime the m3u changes. It should only update the updated_at when we successfully update the m3u. 2025-05-04 17:51:57 -05:00
SergeantPanda
7418abb31c Attempt to fix websockets for production mode. 2025-05-04 11:56:15 -05:00
SergeantPanda
509f2be3a8 Fixes a lot of "You provided a value prop to a form field without an onChange handler" errors.
Reworks websocket connection to be more robust and notify user of connection errors.

Will retry if websocket connection dies.
2025-05-04 10:58:38 -05:00
SergeantPanda
4595cea400 Status update overhaul for epg files. 2025-05-03 18:39:59 -05:00
SergeantPanda
9f52b22432 Show all HTTP errors to the user during epg update. 2025-05-03 16:26:30 -05:00