From edf2e360ee8b4255fed52b751deebaaec8ad7cc7 Mon Sep 17 00:00:00 2001 From: dekzter Date: Sun, 23 Mar 2025 17:55:21 -0400 Subject: [PATCH] fixed first m3u channel group load bug, added searchable selection for tvg-id --- frontend/src/WebSocket.jsx | 3 ++ frontend/src/api.js | 12 +++++++ frontend/src/components/forms/Channel.jsx | 35 +++++++++++++------ frontend/src/components/forms/M3U.jsx | 7 +++- .../src/components/forms/M3UGroupFilter.jsx | 5 ++- frontend/src/store/auth.jsx | 1 + frontend/src/store/epgs.jsx | 20 ++++++++--- 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/frontend/src/WebSocket.jsx b/frontend/src/WebSocket.jsx index 4f4838b9..0538887d 100644 --- a/frontend/src/WebSocket.jsx +++ b/frontend/src/WebSocket.jsx @@ -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); } diff --git a/frontend/src/api.js b/frontend/src/api.js index 60403bd0..0590e2d4 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -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. diff --git a/frontend/src/components/forms/Channel.jsx b/frontend/src/components/forms/Channel.jsx index e59c0c2b..3f778032 100644 --- a/frontend/src/components/forms/Channel.jsx +++ b/frontend/src/components/forms/Channel.jsx @@ -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 ( <> @@ -265,7 +269,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 }) => { - { + 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 : ''} /> - { + 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, + }))} /> { - 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(); diff --git a/frontend/src/components/forms/M3UGroupFilter.jsx b/frontend/src/components/forms/M3UGroupFilter.jsx index 5bfe5424..51e0468f 100644 --- a/frontend/src/components/forms/M3UGroupFilter.jsx +++ b/frontend/src/components/forms/M3UGroupFilter.jsx @@ -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, diff --git a/frontend/src/store/auth.jsx b/frontend/src/store/auth.jsx index f5302713..a3b3a2bb 100644 --- a/frontend/src/store/auth.jsx +++ b/frontend/src/store/auth.jsx @@ -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(), ]); diff --git a/frontend/src/store/epgs.jsx b/frontend/src/store/epgs.jsx index 14cfd623..c749c6bb 100644 --- a/frontend/src/store/epgs.jsx +++ b/frontend/src/store/epgs.jsx @@ -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 }); } },