Commit graph

103 commits

Author SHA1 Message Date
SergeantPanda
a83b9fdf62 Enhancement: EPG channel scanning now automatically removes stale EPGData entries. 2026-04-12 15:37:28 -05:00
SergeantPanda
10582a3741 Enhancement: Improved the EPG BOM fix from v0.22.1: replaced the lstrip(b'\xef\xbb\xbf') / startswith approach with start.find(b'<?xml'), which locates the XML declaration regardless of any leading bytes BOM, whitespace, or other encoding markers without needing to know what those bytes are.
Some checks are pending
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
2026-04-09 11:16:04 -05:00
dwot
b01ec466f1
Fix for #1173 ErsatzTV EPG not populating / fix for UTF-8 BOM processing 2026-04-04 22:15:28 -04:00
SergeantPanda
70e229a433 Refactor HTML entity handling in XMLTV files: replace regex-based entity resolution with lxml's html.entities for improved accuracy and performance. Inject DOCTYPE declaration to ensure proper parsing of HTML entities, avoiding silent drops during recovery mode. 2026-03-29 20:43:27 -05:00
SergeantPanda
d4ecf45bc2 Bug Fix/Enhancement:
- EPG refresh tasks (`refresh_epg_data`) were being killed mid-transaction on large EPG sources. The `soft_time_limit=1700s` introduced in v0.21.0 raised `SoftTimeLimitExceeded`, a subclass of `Exception`, which was swallowed by the existing `except Exception` handler in `parse_programs_for_source`, leaving the database in a partial state with no logged error. The underlying cause is that the HTML entity preprocessing step added in v0.21.0 adds 2–10+ minutes on multi-gigabyte EPG files, pushing total task duration past the 1700s limit for large sources. `soft_time_limit` has been removed from `refresh_epg_data` and `time_limit` raised to 14400s (4 hours) as a true last-resort ceiling; the existing `TaskLockRenewer` daemon thread continues to renew the Redis lock every 120s for legitimately long-running tasks.
- HTML entity preprocessing (`_resolve_html_entities`) now performs a fast binary pre-scan before any file read or write. The pre-scan reads the file in 4 MB chunks without text decoding and exits immediately on the first non-XML named entity found. For EPG sources that contain no HTML entities — the common case — the full line-by-line read+rewrite pass (which takes 2–10+ minutes on a 2.5 GB file) is skipped entirely.
2026-03-29 19:51:57 -05:00
SergeantPanda
dd97b642c7 Bug Fix: preserve original file mtime during HTML entity resolution to prevent infinite refresh loop 2026-03-28 14:21:37 -05:00
None
01a214851d fix: catch all exceptions in entity resolution to avoid breaking EPG refresh
Previously only UnicodeDecodeError/UnicodeEncodeError were caught. Unexpected errors like disk full or permission denied would propagate
and crash the EPG refresh, which would have succeeded before the preprocessing step existed. Now all exceptions are caught and logged, leaving the original file untouched for lxml to handle as before.
2026-03-15 01:11:29 -05:00
None
1f97143bf8 fix: resolve HTML named entities in XMLTV files before parsing
lxml 6.0.2 with recover=True silently drops HTML named entities (e.g. &eacute;, &icirc;) that are not valid XML, causing channel names and program data to lose characters during EPG ingestion.

- Add preprocessing step in fetch_xmltv() that converts HTML named entities to Unicode while preserving XML-predefined entities
- Detect encoding from XML declaration, fall back to UTF-8 for unknown codecs, skip files that fail to decode cleanly
- Guard against entities resolving to XML-special characters and html.unescape partial matching edge cases
- Add 28 unit tests covering entity resolution, encoding detection, and file-level processing
2026-03-15 00:59:58 -05:00
SergeantPanda
216dd7fc40
Merge pull request #1072 from CodeBormen/feat/1065-Add-Subtitle-and-Season-Episode-to-Guide
feat: Add subtitle and season/episode to TV Guide (#1065)
2026-03-13 16:48:20 -05:00
SergeantPanda
284aafcf5e Bug Fix: EPG programme parsing crash when an XMLTV source contains programme titles exceeding 255 characters. Previously, a single oversized title would cause the entire bulk_create batch to fail with a database truncation error, silently dropping all programmes in that batch. Titles are now truncated to 255 characters before being saved. (Fixes #1039)
Some checks are pending
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
2026-03-13 15:35:43 -05:00
SergeantPanda
1f50217dbe perf(epg): speed up TV guide grid load 2k channels from 18s to ~8s
Replace DRF ModelSerializer with .values() + plain dict construction in
EPGGridAPIView, eliminating per-row serializer instantiation, field
object creation, and OrderedDict overhead across ~12k programs.

Pre-compute season/episode at import time instead of on every API request:
- Extract S/E from onscreen episode-num inline in extract_custom_properties()
  immediately after storing the raw value, rather than in a separate pass
- Add missing description-based S/E fallback to parse_programs_for_tvg_id(),
  bringing it in line with parse_programs_for_source()

Remove runtime extract_season_episode() call from ProgramDataSerializer and
EPGGridAPIView — values are now guaranteed to be in custom_properties after
import, so season/episode resolution is a plain dict lookup at request time.

Also remove unnecessary select_related("epg") JOIN and .count() query from
the grid endpoint.
2026-03-13 12:16:10 -05:00
None
b72a9a870e feat(guide): redesign guide with detail modal, progress bars, and season/episode display
Replace expanded inline cards with a ProgramDetailModal for viewing full program
details. Add real-time progress bars to currently-airing programs using direct DOM manipulation. Extract and display season/episode info from EPG data with a 3-tier fallback (custom_properties → onscreen_episode → description text).

Backend:
- Add ProgramDetailSerializer for rich EPG data (categories, credits, ratings, images, external IDs) served on the detail endpoint
- Add infer_is_live() for status badges (live, new, premiere, finale)
- Add shared S/E extraction utilities in apps/epg/utils.py
- Optimize querysets with select_related("epg")

Frontend:
- ProgramDetailModal with conditional field rendering and image fallback chain
- Progress bars via scaleX transform updated every second
- Parallel data fetching with Promise.all for channels + programs
- Browser tab visibility recovery for progress bars
- Now-line with triangle marker and sub-millisecond precision
- Card layout: title, season/episode + subtitle, time + badges
- Shared formatSeasonEpisode() and external URL helpers
2026-03-10 10:53:19 -05:00
None
c841cfc8fc Fix #861: Prevent M3U endless downloading caused by Redis lock expiry
Large M3U downloads that exceed the 300s Redis lock TTL caused Celery Beat
to re-queue duplicate tasks, creating overlapping downloads that never complete.

Files changed:

- core/utils.py: Add TaskLockRenewer class — a daemon thread that periodically renews Redis lock TTL (every 120s) to prevent expiry during long-running tasks.

- apps/m3u/tasks.py: Apply TaskLockRenewer to refresh_single_m3u_account and refresh_m3u_groups; add HTTP timeout (30s connect, 60s read) to M3U download (the only download path missing one); stream M3U download to disk instead of accumulating in memory; add Celery task time limits (1 hour hard limit).

- apps/epg/tasks.py: Apply TaskLockRenewer to refresh_epg_data and parse_programs_for_tvg_id; add Celery task time limits (30 min / 1 hour).

Verified with a throttled test server: locks renewed at T+120s, T+240s, T+360s; 50,000 streams processed with no duplicate tasks.
2026-02-23 00:34:28 -06:00
SergeantPanda
36967c10ce Refactor CoreSettings to use JSONField for value storage and update related logic for proper type handling. Adjusted serializers and forms to accommodate new data structure, ensuring seamless integration across the application. 2026-01-13 12:18:34 -06:00
SergeantPanda
c03ddf60a0 Fixed verbiage for epg parsing status. 2025-12-07 21:28:04 -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
5693ee7f9e perf: optimize EPG program parsing and implement atomic database updates to reduce I/O overhead and prevent partial data visibility 2025-12-04 14:57:57 -06:00
SergeantPanda
256ac2f55a Enhancement: Clean up orphaned programs for unmapped EPG entries 2025-12-04 14:25:44 -06:00
SergeantPanda
2a8ba9125c perf: optimize EPG program parsing for multi-channel sources
Dramatically improve EPG refresh performance by parsing the XML file once
per source instead of once per channel. The new implementation:

- Pre-filters to only process EPG entries mapped to actual channels
- Parses the entire XML file in a single pass
- Uses O(1) set lookups to skip unmapped channel programmes
- Skips non-mapped channels entirely with minimal overhead

For EPG sources with many channels but few mapped (e.g., 10,000 channels
with 100 mapped to channels), this provides approximately:
- 99% reduction in file open operations
- 99% reduction in XML file scans
- Proportional reduction in CPU and I/O overhead

The parse_programs_for_tvg_id() function is retained for single-channel
use cases (e.g., when a new channel is mapped via signals).

Fixes inefficient repeated file parsing that was occurring with large
EPG sources.
2025-12-04 14:07:28 -06:00
SergeantPanda
89a23164ff Enhancement: Add system event logging and viewer with M3U/EPG endpoint caching
System Event Logging:
- Add SystemEvent model with 15 event types tracking channel operations, client connections, M3U/EPG activities, and buffering events
- Log detailed metrics for M3U/EPG refresh operations (streams/programs created/updated/deleted)
- Track M3U/EPG downloads with client information (IP address, user agent, profile, channel count)
- Record channel lifecycle events (start, stop, reconnect) with stream and client details
- Monitor client connections/disconnections and buffering events with stream metadata

Event Viewer UI:
- Add SystemEvents component with real-time updates via WebSocket
- Implement pagination, filtering by event type, and configurable auto-refresh
- Display events with color-coded badges and type-specific icons
- Integrate event viewer into Stats page with modal display
- Add event management settings (retention period, refresh rate)

M3U/EPG Endpoint Optimizations:
- Implement content caching with 5-minute TTL to reduce duplicate processing
- Add client-based event deduplication (2-second window) using IP and user agent hashing
- Support HEAD requests for efficient preflight checks
- Cache streamed EPG responses while maintaining streaming behavior for first request
2025-11-20 17:41:06 -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
29ee837b24 Add recover=True to iterparse for parse_programs_for_tvg_id as well to fix cloudflare script injection. 2025-10-04 16:36:49 -05:00
SergeantPanda
94f966e027 Reverted to old method for parsing xml. Still will not break if Cloudflare adds a new root element. 2025-10-04 16:25:35 -05:00
SergeantPanda
0a15e09805 Refactor XMLTV parsing to use iterparse for <tv> element. This fixes issues where Cloudflare is adding a root element and breaking the xml.
Fixes #497: Cloudflare hosted EPG not supported in dispatcharr
2025-10-03 13:30:20 -05:00
SergeantPanda
d06c5bfdf3 Add recover to xmltv parser if there are errors. 2025-10-03 10:15:24 -05:00
SergeantPanda
6f79845b21 Enhancement: Only grab first display name for a channel during epg scanning. 2025-09-21 12:40:20 -05:00
SergeantPanda
99122cac7c Bug fix: If URL for Channel element in EPG is longer than 500 characters parsing would fail. Added validation during scanning. 2025-09-21 12:23:48 -05:00
SergeantPanda
f4f29a0e27 Break out of channel child elements once required data is acquired. 2025-09-18 10:34:51 -05:00
SergeantPanda
d2d1984797 Switch bulk epg name and logo to backend celery tasks for efficiency and scrape epg channel logo during epg scanning. 2025-09-16 17:17:07 -05:00
Dispatcharr
00cc83882a DVR update 2025-09-03 21:35:45 -05:00
SergeantPanda
6f6c28ca7c Convert custom_properties to jsonb in the backend. 2025-09-02 09:41:51 -05:00
Jordan
72fee02ec4
ensure chunk is either null or empty to exit loop 2025-08-12 11:26:50 +01:00
Jordan
429b01b569
prevent memory issues by implementing a chunked extractor 2025-08-11 16:28:23 +01:00
SergeantPanda
d24520d3d8 Enhance EPG XML generation with additional metadata extraction and improved handling for keywords, languages, ratings, and credits. 2025-07-10 13:22:42 -05:00
SergeantPanda
e7bf8cbede Added support for LIVE tag and dd_progrid numbering systems for epg. 2025-06-03 22:00:17 -05:00
SergeantPanda
67663e2946 Add remove_blank_text=True to lxml parser. Fixes crashes related to poorly formatted xmltv files. 2025-05-30 10:25:47 -05:00
SergeantPanda
906fbef9c2 Output errors from parser if found. 2025-05-29 13:56:20 -05:00
SergeantPanda
4dbb363211 Removed display-name from logging as it may not exist. 2025-05-27 18:00:35 -05:00
SergeantPanda
3fa5301894 If cached file doesn't exist for compressed mapped file, properly re-exctract. 2025-05-27 09:54:28 -05:00
SergeantPanda
5d2c604a4a Peak inside gz files to see if they contain xml files. Check file list for zip files to see if they contain xml files. 2025-05-26 15:49:51 -05:00
SergeantPanda
8f4e05b0b8 Add extracted_file_path to EPGSource model and update extraction logic 2025-05-26 15:10:54 -05:00
SergeantPanda
182a009d69 Track extracted files for mapped epg files. 2025-05-25 18:14:27 -05:00
SergeantPanda
7dbd41afa8 Extract compressed files after downloading and delete original. 2025-05-25 17:39:41 -05:00
SergeantPanda
d270e988bd Greatly improve filetype detection. 2025-05-25 16:50:03 -05:00
SergeantPanda
0322a5c904 Smarter logging for file type. 2025-05-25 15:47:22 -05:00
SergeantPanda
c1eb3a6ecf Add Zip file support for EPG. 2025-05-25 14:05:59 -05:00
SergeantPanda
391a1d9707 A little more cleanup. 2025-05-25 13:29:39 -05:00
SergeantPanda
d7023bcdac Some more code cleanup 2025-05-25 13:19:49 -05:00
SergeantPanda
6c3102a60c Removed sleep from debugging. 2025-05-24 17:46:17 -05:00