optimized channel bulk from streams, fixed frontend infinite loading

This commit is contained in:
dekzter 2025-04-03 22:47:48 -04:00
parent 0a0b2f49f6
commit c01cb98d31
2 changed files with 84 additions and 49 deletions

View file

@ -291,6 +291,10 @@ class ChannelViewSet(viewsets.ModelViewSet):
used_numbers.add(next_number)
return next_number
logos_to_create = []
channels_to_create = []
streams_map = []
logo_map = []
for item in data_list:
stream_id = item.get('stream_id')
if not all([stream_id]):
@ -340,12 +344,6 @@ class ChannelViewSet(viewsets.ModelViewSet):
"streams": [stream_id],
}
if stream.logo_url:
logo, _ = Logo.objects.get_or_create(url=stream.logo_url, defaults={
"name": stream.name or stream.tvg_id
})
channel_data["logo_id"] = logo.id
# Attempt to find existing EPGs with the same tvg-id
epgs = EPGData.objects.filter(tvg_id=stream.tvg_id)
if epgs:
@ -353,13 +351,47 @@ class ChannelViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(data=channel_data)
if serializer.is_valid():
channel = serializer.save()
channel.streams.add(stream)
created_channels.append(serializer.data)
validated_data = serializer.validated_data
stream_ids = validated_data.pop("streams", None) # Extract stream relation if exists
channel = Channel(**validated_data)
channels_to_create.append(channel)
streams_map.append(stream_ids)
if stream.logo_url:
logos_to_create.append(Logo(
url=stream.logo_url,
name=stream.name or stream.tvg_id,
))
logo_map.append(stream.logo_url)
else:
logo_map.append(None)
# channel = serializer.save()
# channel.streams.add(stream)
# created_channels.append(serializer.data)
else:
errors.append({"item": item, "error": serializer.errors})
response_data = {"created": created_channels}
if logos_to_create:
Logo.objects.bulk_create(logos_to_create, ignore_conflicts=True)
channel_logos = {logo.url: logo for logo in Logo.objects.filter(url__in=[url for url in logo_map if url is not None])}
if channels_to_create:
with transaction.atomic():
created_channels = Channel.objects.bulk_create(channels_to_create)
update = []
for channel, stream_ids, logo_url in zip(created_channels, streams_map, logo_map):
if stream_ids:
channel.streams.set(stream_ids)
if logo_url:
channel.logo = channel_logos[logo_url]
update.append(channel)
Channel.objects.bulk_update(update, ['logo'])
response_data = {"created": ChannelSerializer(created_channels, many=True).data}
if errors:
response_data["errors"] = errors

View file

@ -2,6 +2,8 @@ import { create } from 'zustand';
import api from '../api';
import { notifications } from '@mantine/notifications';
const defaultProfiles = { 0: { name: 'All', channels: [] } };
const useChannelsStore = create((set, get) => ({
channels: [],
channelsByUUID: {},
@ -63,7 +65,7 @@ const useChannelsStore = create((set, get) => ({
profiles: profiles.reduce((acc, profile) => {
acc[profile.id] = profile;
return acc;
}, {}),
}, defaultProfiles),
isLoading: false,
});
} catch (error) {
@ -102,44 +104,45 @@ const useChannelsStore = create((set, get) => ({
});
},
addChannels: (newChannels) => {
get().fetchChannelProfiles();
const channelsByUUID = {};
const logos = {};
const channelsByID = newChannels.reduce((acc, channel) => {
acc[channel.id] = channel;
channelsByUUID[channel.uuid] = channel.id;
if (channel.logo) {
logos[channel.logo.id] = channel.logo;
}
return acc;
}, {});
const profileChannels = newChannels.map((channel) => ({
id: channel.id,
enabled: true,
}));
const profiles = { ...state.profiles };
Object.values(profiles).forEach((item) => {
item.channels.concat(profileChannels); // Append a new channel object
});
return set((state) => ({
channels: {
...state.channels,
...channelsByID,
},
channelsByUUID: {
...state.channelsByUUID,
...channelsByUUID,
},
logos: {
...state.logos,
...logos,
},
profiles,
selectedProfile: profiles[state.selectedProfileId],
selectedProfileChannels: profiles[state.selectedProfileId].channels,
}));
},
addChannels: (newChannels) =>
set((state) => {
const channelsByUUID = {};
const logos = {};
const channelsByID = newChannels.reduce((acc, channel) => {
acc[channel.id] = channel;
channelsByUUID[channel.uuid] = channel.id;
if (channel.logo) {
logos[channel.logo.id] = channel.logo;
}
return acc;
}, {});
const profileChannels = newChannels.map((channel) => ({
id: channel.id,
enabled: true,
}));
const profiles = { ...state.profiles };
Object.values(profiles).forEach((item) => {
item.channels.concat(profileChannels); // Append a new channel object
});
return {
channels: {
...state.channels,
...channelsByID,
},
channelsByUUID: {
...state.channelsByUUID,
...channelsByUUID,
},
logos: {
...state.logos,
...logos,
},
profiles,
selectedProfile: profiles[state.selectedProfileId],
selectedProfileChannels: profiles[state.selectedProfileId].channels,
};
}),
updateChannel: (channel) =>
set((state) => ({