Add option to force dummy epg.

This commit is contained in:
SergeantPanda 2025-07-17 16:54:37 -05:00
parent 6afd5a38c9
commit a5f7a88ba0
3 changed files with 96 additions and 19 deletions

View file

@ -302,13 +302,34 @@ class ChannelGroupM3UAccountSerializer(serializers.ModelSerializer):
enabled = serializers.BooleanField()
auto_channel_sync = serializers.BooleanField(default=False)
auto_sync_channel_start = serializers.FloatField(allow_null=True, required=False)
custom_properties = serializers.JSONField(required=False)
class Meta:
model = ChannelGroupM3UAccount
fields = ["id", "channel_group", "enabled", "auto_channel_sync", "auto_sync_channel_start"]
fields = ["id", "channel_group", "enabled", "auto_channel_sync", "auto_sync_channel_start", "custom_properties"]
# Optionally, if you only need the id of the ChannelGroup, you can customize it like this:
# channel_group = serializers.PrimaryKeyRelatedField(queryset=ChannelGroup.objects.all())
def to_representation(self, instance):
ret = super().to_representation(instance)
# Ensure custom_properties is always a dict or None
val = ret.get("custom_properties")
if isinstance(val, str):
import json
try:
ret["custom_properties"] = json.loads(val)
except Exception:
ret["custom_properties"] = None
return ret
def to_internal_value(self, data):
# Accept both dict and JSON string for custom_properties
val = data.get("custom_properties")
if isinstance(val, str):
import json
try:
data["custom_properties"] = json.loads(val)
except Exception:
pass
return super().to_internal_value(data)
class RecordingSerializer(serializers.ModelSerializer):

View file

@ -15,6 +15,7 @@ import os
from rest_framework.decorators import action
from django.conf import settings
from .tasks import refresh_m3u_groups
import json
from .models import M3UAccount, M3UFilter, ServerGroup, M3UAccountProfile
from core.models import UserAgent
@ -154,6 +155,7 @@ class M3UAccountViewSet(viewsets.ModelViewSet):
enabled = setting.get("enabled", True)
auto_sync = setting.get("auto_channel_sync", False)
sync_start = setting.get("auto_sync_channel_start")
custom_properties = setting.get("custom_properties", {})
if group_id:
ChannelGroupM3UAccount.objects.update_or_create(
@ -163,6 +165,11 @@ class M3UAccountViewSet(viewsets.ModelViewSet):
"enabled": enabled,
"auto_channel_sync": auto_sync,
"auto_sync_channel_start": sync_start,
"custom_properties": (
custom_properties
if isinstance(custom_properties, str)
else json.dumps(custom_properties)
),
},
)

View file

@ -43,12 +43,26 @@ const M3UGroupFilter = ({ playlist = null, isOpen, onClose }) => {
}
setGroupStates(
playlist.channel_groups.map((group) => ({
...group,
name: channelGroups[group.channel_group].name,
auto_channel_sync: group.auto_channel_sync || false,
auto_sync_channel_start: group.auto_sync_channel_start || 1.0,
}))
playlist.channel_groups.map((group) => {
// Parse custom_properties if present
let customProps = {};
if (group.custom_properties) {
try {
customProps = typeof group.custom_properties === 'string'
? JSON.parse(group.custom_properties)
: group.custom_properties;
} catch (e) {
customProps = {};
}
}
return {
...group,
name: channelGroups[group.channel_group].name,
auto_channel_sync: group.auto_channel_sync || false,
auto_sync_channel_start: group.auto_sync_channel_start || 1.0,
custom_properties: customProps,
};
})
);
}, [playlist, channelGroups]);
@ -79,11 +93,36 @@ const M3UGroupFilter = ({ playlist = null, isOpen, onClose }) => {
);
};
// Toggle force_dummy_epg in custom_properties for a group
const toggleForceDummyEPG = (id) => {
setGroupStates(
groupStates.map((state) => {
if (state.channel_group == id) {
const customProps = { ...(state.custom_properties || {}) };
customProps.force_dummy_epg = !customProps.force_dummy_epg;
return {
...state,
custom_properties: customProps,
};
}
return state;
})
);
};
const submit = async () => {
setIsLoading(true);
try {
// Prepare groupStates for API: custom_properties must be stringified
const payload = groupStates.map((state) => ({
...state,
custom_properties: state.custom_properties
? JSON.stringify(state.custom_properties)
: undefined,
}));
// Update group settings via API endpoint
await API.updateM3UGroupSettings(playlist.id, groupStates);
await API.updateM3UGroupSettings(playlist.id, payload);
// Show notification about the refresh process
notifications.show({
@ -224,15 +263,25 @@ const M3UGroupFilter = ({ playlist = null, isOpen, onClose }) => {
/>
{group.auto_channel_sync && group.enabled && (
<NumberInput
label="Start Channel #"
value={group.auto_sync_channel_start}
onChange={(value) => updateChannelStart(group.channel_group, value)}
min={1}
step={1}
size="xs"
precision={1}
/>
<>
<NumberInput
label="Start Channel #"
value={group.auto_sync_channel_start}
onChange={(value) => updateChannelStart(group.channel_group, value)}
min={1}
step={1}
size="xs"
precision={1}
/>
{/* Force Dummy EPG Checkbox */}
<Checkbox
label="Force Dummy EPG"
checked={!!(group.custom_properties && group.custom_properties.force_dummy_epg)}
onChange={() => toggleForceDummyEPG(group.channel_group)}
size="xs"
/>
</>
)}
</Stack>
</Group>