Enhancement: Adds ability to specify categories (comma separted) as well as include date and live tags in custom epg dummy output.

This commit is contained in:
SergeantPanda 2025-10-19 10:06:48 -05:00
parent 6e0e646938
commit 6a85475402
2 changed files with 159 additions and 0 deletions

View file

@ -348,6 +348,13 @@ def generate_custom_dummy_programs(channel_id, channel_name, now, num_days, cust
ended_title_template = custom_properties.get('ended_title_template', '')
ended_description_template = custom_properties.get('ended_description_template', '')
# EPG metadata options
category_string = custom_properties.get('category', '')
# Split comma-separated categories and strip whitespace, filter out empty strings
categories = [cat.strip() for cat in category_string.split(',') if cat.strip()] if category_string else []
include_date = custom_properties.get('include_date', True)
include_live = custom_properties.get('include_live', False)
# Parse timezone name
try:
source_tz = pytz.timezone(timezone_value)
@ -656,23 +663,53 @@ def generate_custom_dummy_programs(channel_id, channel_name, now, num_days, cust
else:
upcoming_description = f"Upcoming: {main_event_description}"
# Build custom_properties for upcoming programs (only date, no category/live)
program_custom_properties = {}
# Add date if requested (YYYY-MM-DD format from start time in event timezone)
if include_date:
# Convert UTC time to event timezone for date calculation
local_time = program_start_utc.astimezone(source_tz)
date_str = local_time.strftime('%Y-%m-%d')
program_custom_properties['date'] = date_str
programs.append({
"channel_id": channel_id,
"start_time": program_start_utc,
"end_time": program_end_utc,
"title": upcoming_title,
"description": upcoming_description,
"custom_properties": program_custom_properties,
})
current_time += timedelta(minutes=program_duration)
# Add the MAIN EVENT at the extracted time
# Build custom_properties for main event (includes category and live)
main_event_custom_properties = {}
# Add categories if provided
if categories:
main_event_custom_properties['categories'] = categories
# Add date if requested (YYYY-MM-DD format from start time in event timezone)
if include_date:
# Convert UTC time to event timezone for date calculation
local_time = event_start_utc.astimezone(source_tz)
date_str = local_time.strftime('%Y-%m-%d')
main_event_custom_properties['date'] = date_str
# Add live flag if requested
if include_live:
main_event_custom_properties['live'] = True
programs.append({
"channel_id": channel_id,
"start_time": event_start_utc,
"end_time": event_end_utc,
"title": main_event_title,
"description": main_event_description,
"custom_properties": main_event_custom_properties,
})
event_happened = True
@ -695,12 +732,23 @@ def generate_custom_dummy_programs(channel_id, channel_name, now, num_days, cust
else:
ended_description = f"Ended: {main_event_description}"
# Build custom_properties for ended programs (only date, no category/live)
program_custom_properties = {}
# Add date if requested (YYYY-MM-DD format from start time in event timezone)
if include_date:
# Convert UTC time to event timezone for date calculation
local_time = program_start_utc.astimezone(source_tz)
date_str = local_time.strftime('%Y-%m-%d')
program_custom_properties['date'] = date_str
programs.append({
"channel_id": channel_id,
"start_time": program_start_utc,
"end_time": program_end_utc,
"title": ended_title,
"description": ended_description,
"custom_properties": program_custom_properties,
})
current_time += timedelta(minutes=program_duration)
@ -739,12 +787,23 @@ def generate_custom_dummy_programs(channel_id, channel_name, now, num_days, cust
else:
program_description = f"Upcoming: {main_event_description}"
# Build custom_properties (only date for upcoming/ended filler programs)
program_custom_properties = {}
# Add date if requested (YYYY-MM-DD format from start time in event timezone)
if include_date:
# Convert UTC time to event timezone for date calculation
local_time = program_start_utc.astimezone(source_tz)
date_str = local_time.strftime('%Y-%m-%d')
program_custom_properties['date'] = date_str
programs.append({
"channel_id": channel_id,
"start_time": program_start_utc,
"end_time": program_end_utc,
"title": program_title,
"description": program_description,
"custom_properties": program_custom_properties,
})
current_time += timedelta(minutes=program_duration)
@ -774,12 +833,31 @@ def generate_custom_dummy_programs(channel_id, channel_name, now, num_days, cust
else:
description = title
# Build custom_properties for this program
program_custom_properties = {}
# Add categories if provided
if categories:
program_custom_properties['categories'] = categories
# Add date if requested (YYYY-MM-DD format from start time in event timezone)
if include_date:
# Convert UTC time to event timezone for date calculation
local_time = program_start_utc.astimezone(source_tz)
date_str = local_time.strftime('%Y-%m-%d')
program_custom_properties['date'] = date_str
# Add live flag if requested
if include_live:
program_custom_properties['live'] = True
programs.append({
"channel_id": channel_id,
"start_time": program_start_utc,
"end_time": program_end_utc,
"title": title,
"description": description,
"custom_properties": program_custom_properties,
})
logger.info(f"Generated {len(programs)} custom dummy programs for {channel_name}")
@ -817,6 +895,23 @@ def generate_dummy_epg(
)
xml_lines.append(f" <title>{html.escape(program['title'])}</title>")
xml_lines.append(f" <desc>{html.escape(program['description'])}</desc>")
# Add custom_properties if present
custom_data = program.get('custom_properties', {})
# Categories
if 'categories' in custom_data:
for cat in custom_data['categories']:
xml_lines.append(f" <category>{html.escape(cat)}</category>")
# Date tag
if 'date' in custom_data:
xml_lines.append(f" <date>{html.escape(custom_data['date'])}</date>")
# Live tag
if custom_data.get('live', False):
xml_lines.append(f" <live />")
xml_lines.append(f" </programme>")
return xml_lines
@ -999,6 +1094,23 @@ def generate_epg(request, profile_name=None, user=None):
yield f' <programme start="{start_str}" stop="{stop_str}" channel="{channel_id}">\n'
yield f" <title>{html.escape(program['title'])}</title>\n"
yield f" <desc>{html.escape(program['description'])}</desc>\n"
# Add custom_properties if present
custom_data = program.get('custom_properties', {})
# Categories
if 'categories' in custom_data:
for cat in custom_data['categories']:
yield f" <category>{html.escape(cat)}</category>\n"
# Date tag
if 'date' in custom_data:
yield f" <date>{html.escape(custom_data['date'])}</date>\n"
# Live tag
if custom_data.get('live', False):
yield f" <live />\n"
yield f" </programme>\n"
else:
@ -1023,6 +1135,23 @@ def generate_epg(request, profile_name=None, user=None):
yield f' <programme start="{start_str}" stop="{stop_str}" channel="{channel_id}">\n'
yield f" <title>{html.escape(program['title'])}</title>\n"
yield f" <desc>{html.escape(program['description'])}</desc>\n"
# Add custom_properties if present
custom_data = program.get('custom_properties', {})
# Categories
if 'categories' in custom_data:
for cat in custom_data['categories']:
yield f" <category>{html.escape(cat)}</category>\n"
# Date tag
if 'date' in custom_data:
yield f" <date>{html.escape(custom_data['date'])}</date>\n"
# Live tag
if custom_data.get('live', False):
yield f" <live />\n"
yield f" </programme>\n"
continue # Skip to next channel

View file

@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import {
Box,
Button,
Checkbox,
Divider,
Group,
Modal,
@ -60,6 +61,9 @@ const DummyEPGForm = ({ epg, isOpen, onClose }) => {
ended_description_template: '',
name_source: 'channel',
stream_index: 1,
category: '',
include_date: true,
include_live: false,
},
},
validate: {
@ -345,6 +349,9 @@ const DummyEPGForm = ({ epg, isOpen, onClose }) => {
ended_description_template: custom.ended_description_template || '',
name_source: custom.name_source || 'channel',
stream_index: custom.stream_index || 1,
category: custom.category || '',
include_date: custom.include_date ?? true,
include_live: custom.include_live ?? false,
},
});
@ -689,6 +696,29 @@ const DummyEPGForm = ({ epg, isOpen, onClose }) => {
{...form.getInputProps('custom_properties.program_duration')}
/>
<TextInput
label="Categories (Optional)"
description="EPG categories for these programs. Use commas to separate multiple (e.g., Sports, Live, HD). Note: Only added to the main event, not upcoming/ended filler programs."
placeholder="Sports, Live"
{...form.getInputProps('custom_properties.category')}
/>
<Checkbox
label="Include Date Tag"
description="Include the <date> tag in EPG output with the program's start date (YYYY-MM-DD format). Added to all programs."
{...form.getInputProps('custom_properties.include_date', {
type: 'checkbox',
})}
/>
<Checkbox
label="Include Live Tag"
description="Mark programs as live content with the <live /> tag in EPG output. Note: Only added to the main event, not upcoming/ended filler programs."
{...form.getInputProps('custom_properties.include_live', {
type: 'checkbox',
})}
/>
{/* Testing & Preview */}
<Divider label="Test Your Configuration" labelPosition="center" />