Merge pull request #518 from Dispatcharr/Assign-tvg-id-from-epg

This commit is contained in:
SergeantPanda 2025-10-04 17:24:49 -05:00 committed by GitHub
commit 18dc73cbcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 237 additions and 2 deletions

View file

@ -555,6 +555,37 @@ class ChannelViewSet(viewsets.ModelViewSet):
"channel_count": len(channel_ids)
})
@action(detail=False, methods=["post"], url_path="set-tvg-ids-from-epg")
def set_tvg_ids_from_epg(self, request):
"""
Trigger a Celery task to set channel TVG-IDs from EPG data
"""
from .tasks import set_channels_tvg_ids_from_epg
data = request.data
channel_ids = data.get("channel_ids", [])
if not channel_ids:
return Response(
{"error": "channel_ids is required"},
status=status.HTTP_400_BAD_REQUEST,
)
if not isinstance(channel_ids, list):
return Response(
{"error": "channel_ids must be a list"},
status=status.HTTP_400_BAD_REQUEST,
)
# Start the Celery task
task = set_channels_tvg_ids_from_epg.delay(channel_ids)
return Response({
"message": f"Started EPG TVG-ID setting task for {len(channel_ids)} channels",
"task_id": task.id,
"channel_count": len(channel_ids)
})
@action(detail=False, methods=["get"], url_path="ids")
def get_ids(self, request, *args, **kwargs):
# Get the filtered queryset

View file

@ -2711,3 +2711,98 @@ def set_channels_logos_from_epg(self, channel_ids):
'error': str(e)
})
raise
@shared_task(bind=True)
def set_channels_tvg_ids_from_epg(self, channel_ids):
"""
Celery task to set channel TVG-IDs from EPG data for multiple channels
"""
from core.utils import send_websocket_update
task_id = self.request.id
total_channels = len(channel_ids)
updated_count = 0
errors = []
try:
logger.info(f"Starting EPG TVG-ID setting task for {total_channels} channels")
# Send initial progress
send_websocket_update('updates', 'update', {
'type': 'epg_tvg_id_setting_progress',
'task_id': task_id,
'progress': 0,
'total': total_channels,
'status': 'running',
'message': 'Starting EPG TVG-ID setting...'
})
batch_size = 100
for i in range(0, total_channels, batch_size):
batch_ids = channel_ids[i:i + batch_size]
batch_updates = []
# Get channels and their EPG data
channels = Channel.objects.filter(id__in=batch_ids).select_related('epg_data')
for channel in channels:
try:
if channel.epg_data and channel.epg_data.tvg_id:
if channel.tvg_id != channel.epg_data.tvg_id:
channel.tvg_id = channel.epg_data.tvg_id
batch_updates.append(channel)
updated_count += 1
except Exception as e:
errors.append(f"Channel {channel.id}: {str(e)}")
logger.error(f"Error processing channel {channel.id}: {e}")
# Bulk update the batch
if batch_updates:
Channel.objects.bulk_update(batch_updates, ['tvg_id'])
# Send progress update
progress = min(i + batch_size, total_channels)
send_websocket_update('updates', 'update', {
'type': 'epg_tvg_id_setting_progress',
'task_id': task_id,
'progress': progress,
'total': total_channels,
'status': 'running',
'message': f'Updated {updated_count} channel TVG-IDs...',
'updated_count': updated_count
})
# Send completion notification
send_websocket_update('updates', 'update', {
'type': 'epg_tvg_id_setting_progress',
'task_id': task_id,
'progress': total_channels,
'total': total_channels,
'status': 'completed',
'message': f'Successfully updated {updated_count} channel TVG-IDs from EPG data',
'updated_count': updated_count,
'error_count': len(errors),
'errors': errors
})
logger.info(f"EPG TVG-ID setting task completed. Updated {updated_count} channels")
return {
'status': 'completed',
'updated_count': updated_count,
'error_count': len(errors),
'errors': errors
}
except Exception as e:
logger.error(f"EPG TVG-ID setting task failed: {e}")
send_websocket_update('updates', 'update', {
'type': 'epg_tvg_id_setting_progress',
'task_id': task_id,
'progress': 0,
'total': total_channels,
'status': 'failed',
'message': f'Task failed: {str(e)}',
'error': str(e)
})
raise

View file

@ -562,6 +562,29 @@ export default class API {
}
}
static async setChannelTvgIdsFromEpg(channelIds) {
try {
const response = await request(
`${host}/api/channels/channels/set-tvg-ids-from-epg/`,
{
method: 'POST',
body: { channel_ids: channelIds },
}
);
notifications.show({
title: 'Task Started',
message: response.message,
color: 'blue',
});
return response;
} catch (e) {
errorNotification('Failed to start EPG TVG-ID setting task', e);
throw e;
}
}
static async assignChannelNumbers(channelIds, startingNum = 1) {
try {
const response = await request(`${host}/api/channels/channels/assign/`, {

View file

@ -263,6 +263,34 @@ const ChannelForm = ({ channel = null, isOpen, onClose }) => {
}
};
const handleSetTvgIdFromEpg = () => {
const epgDataId = formik.values.epg_data_id;
if (!epgDataId) {
notifications.show({
title: 'No EPG Selected',
message: 'Please select an EPG source first.',
color: 'orange',
});
return;
}
const tvg = tvgsById[epgDataId];
if (tvg && tvg.tvg_id) {
formik.setFieldValue('tvg_id', tvg.tvg_id);
notifications.show({
title: 'Success',
message: `TVG-ID set to "${tvg.tvg_id}"`,
color: 'green',
});
} else {
notifications.show({
title: 'No TVG-ID Available',
message: 'No TVG-ID found in the selected EPG data.',
color: 'orange',
});
}
};
const formik = useFormik({
initialValues: {
name: '',
@ -823,7 +851,23 @@ const ChannelForm = ({ channel = null, isOpen, onClose }) => {
<TextInput
id="tvg_id"
name="tvg_id"
label="TVG-ID"
label={
<Group gap="xs">
<span>TVG-ID</span>
{formik.values.epg_data_id && (
<Button
size="xs"
variant="transparent"
onClick={handleSetTvgIdFromEpg}
title="Set TVG-ID from EPG data"
p={0}
h="auto"
>
Use EPG TVG-ID
</Button>
)}
</Group>
}
value={formik.values.tvg_id}
onChange={formik.handleChange}
error={formik.errors.tvg_id ? formik.touched.tvg_id : ''}

View file

@ -202,6 +202,40 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
}
};
const handleSetTvgIdsFromEpg = async () => {
if (!channelIds || channelIds.length === 0) {
notifications.show({
title: 'No Channels Selected',
message: 'No channels to update.',
color: 'orange',
});
return;
}
try {
// Start the backend task
await API.setChannelTvgIdsFromEpg(channelIds);
// The task will send WebSocket updates for progress
// Just show that it started successfully
notifications.show({
title: 'Task Started',
message: `Started setting TVG-IDs from EPG for ${channelIds.length} channels. Progress will be shown in notifications.`,
color: 'blue',
});
// Close the modal since the task is now running in background
onClose();
} catch (error) {
console.error('Failed to start EPG TVG-ID setting task:', error);
notifications.show({
title: 'Error',
message: 'Failed to start EPG TVG-ID setting task.',
color: 'red',
});
}
};
// useEffect(() => {
// // const sameStreamProfile = channels.every(
// // (channel) => channel.stream_profile_id == channels[0].stream_profile_id
@ -317,9 +351,17 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
>
Set Logos from EPG
</Button>
<Button
size="xs"
variant="light"
onClick={handleSetTvgIdsFromEpg}
style={{ flex: 1 }}
>
Set TVG-IDs from EPG
</Button>
</Group>
<Text size="xs" c="dimmed" mt="xs">
Updates channel names and logos based on their assigned EPG
Updates channel names, logos, and TVG-IDs based on their assigned EPG
data
</Text>
</Paper>