XC (Xtream Codes) clients require integer channel numbers and fail to parse
float values (e.g., 100.5). This change implements collision-free mapping
that converts floats to integers while preserving existing integer channel
numbers where possible.
Changes:
- Implemented two-pass collision detection algorithm that assigns integers
to float channel numbers by incrementing until an unused number is found
- Applied mapping to all XC client interfaces: live streams API, EPG API,
and XMLTV endpoint
- Detection: XC clients identified by authenticated user (user is not None)
- Regular M3U/EPG clients (user is None) continue to receive float channel
numbers without modification
Example: Channels 100, 100.5, 100.9, 101 become 100, 101, 102, 103 for XC
clients, ensuring no duplicate channel numbers and full compatibility.
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
The ChannelSerializer.to_representation() method was not respecting the
ChannelStream.order field when serializing PATCH/PUT responses. This
caused streams to be returned in an arbitrary order rather than the
order specified in the request.
The update() method correctly saves the stream order to the database
using the ChannelStream.order field, and GET requests (with
include_streams=True) correctly return ordered streams via
get_streams(). However, standard PATCH/PUT responses were using
PrimaryKeyRelatedField which doesn't respect the ordering.
This fix ensures that all representations (GET, PATCH, PUT) return
streams ordered by the channelstream__order field.
Impact:
- PATCH/PUT responses now correctly reflect the stream order saved
- Clients can trust the response data without needing a follow-up GET
- No breaking changes - only fixes inconsistent behavior
Tested with:
- PATCH request with ordered stream IDs
- Verified response matches request order
- Verified GET request confirms order persisted to database
- Created VODLogo model for movies/series, separate from Logo (channels only)
- Added database migration to create vodlogo table and migrate existing VOD logos
- Implemented VODLogoViewSet with pagination, filtering (used/unused/movies/series), and bulk operations
- Built VODLogosTable component with server-side pagination matching channel logos styling
- Added VOD logos tab with on-demand loading to Logos page
- Fixed orphaned VOD content cleanup to always remove unused entries
- Removed redundant channel_assignable filtering from channel logos
I moved on to LXC install on PVE. The x-tvg-url defaults back to 9191 port whilst in reality the port is defined as :80, therefore this obviously brakes this functionality.
Check request.META.get("SERVER_PORT") before falling back to defaults. This should capture the actual server port from the request.
Use the 'regex' package instead of Python's standard 're' module for pattern
compilation in custom dummy EPG generation. This enables variable-width
lookbehind support, matching JavaScript regex behavior and removing the
fixed-width limitation of the standard library.
This fixes issues where patterns like (?<=\d{1,2}...) would fail with
"look-behind requires fixed-width pattern" errors.