diff --git a/frontend/src/App.js b/frontend/src/App.js
index a16c72d1..def311ff 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -22,6 +22,7 @@ import useAuthStore from './store/auth';
import Alert from './components/Alert';
import FloatingVideo from './components/FloatingVideo';
import SuperuserForm from './components/forms/SuperuserForm';
+import { WebsocketProvider } from './WebSocket';
const drawerWidth = 240;
const miniDrawerWidth = 60;
@@ -79,60 +80,65 @@ const App = () => {
return (
-
-
+
+
+
-
-
- {isAuthenticated ? (
- <>
- } />
- } />
- } />
- } />
- } />
- } />
- >
- ) : (
- } />
- )}
-
- }
- />
-
+
+
+ {isAuthenticated ? (
+ <>
+ } />
+ } />
+ } />
+ }
+ />
+ } />
+ } />
+ >
+ ) : (
+ } />
+ )}
+
+ }
+ />
+
+
-
-
-
-
+
+
+
+
);
};
diff --git a/frontend/src/WebSocket.js b/frontend/src/WebSocket.js
new file mode 100644
index 00000000..a1fa1aaa
--- /dev/null
+++ b/frontend/src/WebSocket.js
@@ -0,0 +1,78 @@
+import React, {
+ useState,
+ useEffect,
+ useRef,
+ createContext,
+ useContext,
+} from 'react';
+import useStreamsStore from './store/streams';
+import useAlertStore from './store/alerts';
+
+export const WebsocketContext = createContext(false, null, () => {});
+
+export const WebsocketProvider = ({ children }) => {
+ const [isReady, setIsReady] = useState(false);
+ const [val, setVal] = useState(null);
+
+ const { showAlert } = useAlertStore();
+
+ const ws = useRef(null);
+
+ useEffect(() => {
+ let wsUrl = `ws://${window.location.host}/ws/`;
+ if (process.env.REACT_APP_ENV_MODE == 'dev') {
+ wsUrl = `ws://${window.location.hostname}:8001/ws/`;
+ }
+
+ const socket = new WebSocket(wsUrl);
+
+ socket.onopen = () => {
+ console.log('websocket connected');
+ setIsReady(true);
+ };
+
+ // Reconnection logic
+ socket.onclose = () => {
+ setIsReady(false);
+ setTimeout(() => {
+ const reconnectWs = new WebSocket(wsUrl);
+ reconnectWs.onopen = () => setIsReady(true);
+ }, 3000); // Attempt to reconnect every 3 seconds
+ };
+
+ socket.onmessage = async (event) => {
+ event = JSON.parse(event.data);
+ switch (event.type) {
+ case 'm3u_refresh':
+ if (event.message?.success) {
+ useStreamsStore.getState().fetchStreams();
+ showAlert(event.message.message, 'success');
+ }
+ break;
+
+ default:
+ console.error(`Unknown websocket event type: ${event.type}`);
+ break;
+ }
+ };
+
+ ws.current = socket;
+
+ return () => {
+ socket.close();
+ };
+ }, []);
+
+ const ret = [isReady, val, ws.current?.send.bind(ws.current)];
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useWebSocket = () => {
+ const socket = useContext(WebsocketContext);
+ return socket;
+};
diff --git a/frontend/src/components/Sidebar.js b/frontend/src/components/Sidebar.js
index abe9db7a..8b99d601 100644
--- a/frontend/src/components/Sidebar.js
+++ b/frontend/src/components/Sidebar.js
@@ -100,7 +100,7 @@ const Sidebar = ({ open, miniDrawerWidth, drawerWidth, toggleDrawer }) => {
{isAuthenticated && (
-
+
diff --git a/frontend/src/components/forms/LoginForm.js b/frontend/src/components/forms/LoginForm.js
index 2272d6f4..f7b4445e 100644
--- a/frontend/src/components/forms/LoginForm.js
+++ b/frontend/src/components/forms/LoginForm.js
@@ -66,7 +66,7 @@ const LoginForm = () => {
justifyContent="center"
direction="column"
>
-
+
{
size="small"
/>
-
+
{
size="small"
/>
-
+