fixed first m3u channel group load bug, added searchable selection for tvg-id

This commit is contained in:
dekzter 2025-03-23 17:55:21 -04:00
parent b9cae416ec
commit edf2e360ee
7 changed files with 66 additions and 17 deletions

View file

@ -9,6 +9,7 @@ import useStreamsStore from './store/streams';
import { notifications } from '@mantine/notifications';
import useChannelsStore from './store/channels';
import usePlaylistsStore from './store/playlists';
import useEPGsStore from './store/epgs';
export const WebsocketContext = createContext(false, null, () => {});
@ -19,6 +20,7 @@ export const WebsocketProvider = ({ children }) => {
const { fetchStreams } = useStreamsStore();
const { setChannelStats, fetchChannelGroups } = useChannelsStore();
const { setRefreshProgress } = usePlaylistsStore();
const { fetchEPGData } = useEPGsStore();
const ws = useRef(null);
@ -65,6 +67,7 @@ export const WebsocketProvider = ({ children }) => {
if (event.data.progress == 100) {
fetchStreams();
fetchChannelGroups();
fetchEPGData();
}
setRefreshProgress(event.data.account, event.data.progress);
}

View file

@ -581,6 +581,18 @@ export default class API {
return retval;
}
static async getEPGData() {
const response = await fetch(`${host}/api/epg/epgdata/`, {
headers: {
Authorization: `Bearer ${await API.getAuthToken()}`,
'Content-Type': 'application/json',
},
});
const retval = await response.json();
return retval;
}
// Notice there's a duplicated "refreshPlaylist" method above;
// you might want to rename or remove one if it's not needed.

View file

@ -21,14 +21,17 @@ import {
Center,
Grid,
Flex,
Select,
} from '@mantine/core';
import { SquarePlus } from 'lucide-react';
import useEPGsStore from '../../store/epgs';
const Channel = ({ channel = null, isOpen, onClose }) => {
const channelGroups = useChannelsStore((state) => state.channelGroups);
const streams = useStreamsStore((state) => state.streams);
const { profiles: streamProfiles } = useStreamProfilesStore();
const { playlists } = usePlaylistsStore();
const { tvgs } = useEPGsStore();
const [logoFile, setLogoFile] = useState(null);
const [logoPreview, setLogoPreview] = useState(logo);
@ -60,7 +63,7 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
name: '',
channel_number: '',
channel_group_id: '',
stream_profile_id: null,
stream_profile_id: '0',
tvg_id: '',
tvg_name: '',
},
@ -74,7 +77,6 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
values.stream_profile_id = null;
}
console.log(values);
if (channel?.id) {
await API.updateChannel({
id: channel.id,
@ -104,7 +106,7 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
name: channel.name,
channel_number: channel.channel_number,
channel_group_id: channel.channel_group?.id,
stream_profile_id: channel.stream_profile_id,
stream_profile_id: channel.stream_profile_id || '0',
tvg_id: channel.tvg_id,
tvg_name: channel.tvg_name,
});
@ -248,6 +250,8 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
return <></>;
}
console.log(streamProfiles);
return (
<>
<Modal opened={isOpen} onClose={onClose} size={800} title="Channel">
@ -265,7 +269,7 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
<Grid>
<Grid.Col span={11}>
<NativeSelect
<Select
id="channel_group_id"
name="channel_group_id"
label="Channel Group"
@ -276,7 +280,7 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
? formik.touched.channel_group_id
: ''
}
data={channelGroups.map((option, index) => ({
data={Object.values(channelGroups).map((option, index) => ({
value: `${option.id}`,
label: option.name,
}))}
@ -296,18 +300,20 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
</Grid.Col>
</Grid>
<NativeSelect
<Select
id="stream_profile_id"
label="Stream Profile"
name="stream_profile_id"
value={formik.values.stream_profile_id}
onChange={formik.handleChange}
onChange={(value) => {
formik.setFieldValue('stream_profile_id', value); // Update Formik's state with the new value
}}
error={
formik.errors.stream_profile_id
? formik.touched.stream_profile_id
: ''
}
data={[{ value: null, label: '(use default)' }].concat(
data={[{ value: '0', label: '(use default)' }].concat(
streamProfiles.map((option) => ({
value: `${option.id}`,
label: option.name,
@ -339,13 +345,20 @@ const Channel = ({ channel = null, isOpen, onClose }) => {
error={formik.errors.tvg_name ? formik.touched.tvg_name : ''}
/>
<TextInput
<Select
id="tvg_id"
name="tvg_id"
label="TVG ID"
searchable
value={formik.values.tvg_id}
onChange={formik.handleChange}
error={formik.errors.tvg_id ? formik.touched.tvg_id : ''}
onChange={(value) => {
formik.setFieldValue('tvg_id', value); // Update Formik's state with the new value
}}
error={formik.errors.tvg_id}
data={tvgs.map((tvg) => ({
value: tvg.name,
label: tvg.tvg_id,
}))}
/>
<TextInput

View file

@ -18,9 +18,12 @@ import {
Space,
} from '@mantine/core';
import M3UGroupFilter from './M3UGroupFilter';
import useChannelsStore from '../../store/channels';
const M3U = ({ playlist = null, isOpen, onClose, playlistCreated = false }) => {
const userAgents = useUserAgentsStore((state) => state.userAgents);
const { userAgents } = useUserAgentsStore();
const { fetchChannelGroups } = useChannelsStore();
const [file, setFile] = useState(null);
const [profileModalOpen, setProfileModalOpen] = useState(false);
const [groupFilterModalOpen, setGroupFilterModalOpen] = useState(false);
@ -59,6 +62,8 @@ const M3U = ({ playlist = null, isOpen, onClose, playlistCreated = false }) => {
...values,
uploaded_file: file,
});
await fetchChannelGroups();
}
resetForm();

View file

@ -31,7 +31,10 @@ const M3UGroupFilter = ({ playlist = null, isOpen, onClose }) => {
const [groupFilter, setGroupFilter] = useState('');
useEffect(() => {
console.log(playlist.channel_groups);
if (Object.keys(channelGroups).length === 0) {
return;
}
setGroupStates(
playlist.channel_groups.map((group) => ({
...group,

View file

@ -37,6 +37,7 @@ const useAuthStore = create((set, get) => ({
useUserAgentsStore.getState().fetchUserAgents(),
usePlaylistsStore.getState().fetchPlaylists(),
useEPGsStore.getState().fetchEPGs(),
useEPGsStore.getState().fetchEPGData(),
useStreamProfilesStore.getState().fetchProfiles(),
useSettingsStore.getState().fetchSettings(),
]);

View file

@ -1,8 +1,9 @@
import { create } from "zustand";
import api from "../api";
import { create } from 'zustand';
import api from '../api';
const useEPGsStore = create((set) => ({
epgs: [],
tvgs: [],
isLoading: false,
error: null,
@ -12,8 +13,19 @@ const useEPGsStore = create((set) => ({
const epgs = await api.getEPGs();
set({ epgs: epgs, isLoading: false });
} catch (error) {
console.error("Failed to fetch epgs:", error);
set({ error: "Failed to load epgs.", isLoading: false });
console.error('Failed to fetch epgs:', error);
set({ error: 'Failed to load epgs.', isLoading: false });
}
},
fetchEPGData: async () => {
set({ isLoading: true, error: null });
try {
const tvgs = await api.getEPGData();
set({ tvgs: tvgs, isLoading: false });
} catch (error) {
console.error('Failed to fetch tvgs:', error);
set({ error: 'Failed to load tvgs.', isLoading: false });
}
},