fix: remove frontend session management

This commit is contained in:
antebrl
2025-01-07 17:02:02 +00:00
parent 3932b0cc33
commit 5820a8b40a
5 changed files with 5 additions and 165 deletions

View File

@@ -10,8 +10,6 @@ import apiService from './services/ApiService';
import SettingsModal from './components/SettingsModal';
import { ToastProvider } from './components/notifications/ToastContext';
import ToastContainer from './components/notifications/ToastContainer';
import SessionFactory from './services/session/SessionFactory';
import { SessionHandler } from './services/session/SessionHandler';
function App() {
const [channels, setChannels] = useState<Channel[]>([]);
@@ -25,9 +23,6 @@ function App() {
const [searchQuery, setSearchQuery] = useState('');
const [editChannel, setEditChannel] = useState<Channel | null>(null);
const [sessionProvider, setSessionProvider] = useState<SessionHandler | null>(null);
const [sessionQuery, setSessionQuery] = useState<string | undefined>(undefined);
const [selectedPlaylist, setSelectedPlaylist] = useState<string>('All Channels');
const [selectedGroup, setSelectedGroup] = useState<string>('Category');
@@ -84,7 +79,6 @@ function App() {
};
const channelSelectedListener = (nextChannel: Channel) => {
checkSession(nextChannel, selectedChannel?.url != nextChannel.url);
setSelectedChannel(nextChannel);
};
@@ -126,24 +120,6 @@ function App() {
socketService.connect();
const checkSession = (channel : Channel, urlHasChanged : boolean | undefined) => {
const newProvider = SessionFactory.getSessionProvider(channel.url, setSessionQuery);
if(!newProvider || channel.mode === 'restream') {
sessionProvider?.destroySession();
setSessionProvider(null);
return;
}
if(newProvider?.type() != sessionProvider?.type() || urlHasChanged) {
sessionProvider?.destroySession();
setSessionProvider(null);
setSessionProvider(newProvider);
sessionProvider?.createSession();
}
};
return () => {
socketService.unsubscribeFromEvent('channel-added', channelAddedListener);
socketService.unsubscribeFromEvent('channel-selected', channelSelectedListener);
@@ -305,7 +281,7 @@ function App() {
/>
</div>
<VideoPlayer channel={selectedChannel} sessionQuery={sessionQuery} syncEnabled={syncEnabled} />
<VideoPlayer channel={selectedChannel} syncEnabled={syncEnabled} />
</div>
<div className="col-span-12 lg:col-span-4">

View File

@@ -5,11 +5,10 @@ import { ToastContext } from './notifications/ToastContext';
interface VideoPlayerProps {
channel: Channel | null;
sessionQuery: string | undefined;
syncEnabled: boolean;
}
function VideoPlayer({ channel, sessionQuery, syncEnabled }: VideoPlayerProps) {
function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const hlsRef = useRef<Hls | null>(null);
const { addToast, removeToast, clearToasts, editToast } = useContext(ToastContext);
@@ -51,11 +50,10 @@ function VideoPlayer({ channel, sessionQuery, syncEnabled }: VideoPlayerProps) {
},
});
const querySeparator = channel.url.includes('?') ? '&' : '?';
const sourceLinks: Record<ChannelMode, string> = {
direct: sessionQuery ? channel.url + querySeparator + sessionQuery : channel.url,
direct: channel.url,
//TODO: needs update for multi-channel streaming
proxy: sessionQuery ? import.meta.env.VITE_BACKEND_URL + '/proxy/channel?' + sessionQuery : import.meta.env.VITE_BACKEND_URL + '/proxy/channel',
proxy: import.meta.env.VITE_BACKEND_URL + '/proxy/channel',
restream: import.meta.env.VITE_BACKEND_URL + '/streams/' + channel.id + "/" + channel.id + ".m3u8", //e.g. http://backend:3000/streams/1/1.m3u8
};
@@ -218,7 +216,7 @@ function VideoPlayer({ channel, sessionQuery, syncEnabled }: VideoPlayerProps) {
}
};
}, [channel?.url, channel?.mode, syncEnabled, sessionQuery]);
}, [channel?.url, channel?.mode, syncEnabled]);
const handleVideoClick = (event: React.MouseEvent<HTMLVideoElement>) => {
if (videoRef.current?.muted) {

View File

@@ -1,15 +0,0 @@
import { SessionHandler } from "./SessionHandler";
import { StreamedSuSession } from "./StreamedSuSession";
class SessionFactory {
static getSessionProvider(channelUrl: string, setSessionQuery: React.Dispatch<React.SetStateAction<string | undefined>>): SessionHandler | null {
switch (true) {
case channelUrl.includes('vipstreams.in'): //StreamedSU
return new StreamedSuSession(channelUrl, 'https://secure.embedme.top', setSessionQuery);
default:
return null;
}
}
}
export default SessionFactory;

View File

@@ -1,9 +0,0 @@
//Implement this interface for your specific session provider
interface SessionHandler {
createSession(interval?: number): Promise<void>;
destroySession(): boolean;
//getSessionQuery(): string;
type(): string;
}
export type { SessionHandler };

View File

@@ -1,110 +0,0 @@
import { SessionHandler } from "./SessionHandler";
class StreamedSuSession implements SessionHandler {
private baseUrl: string;
private channelUrl: string;
private checkInterval: number | null;
private sessionId: string | null;
private setSessionQuery: React.Dispatch<React.SetStateAction<string | undefined>>;
constructor(channelUrl: string, baseUrl: string, setSessionQuery: React.Dispatch<React.SetStateAction<string | undefined>>) {
this.channelUrl = channelUrl;
this.baseUrl = baseUrl;
this.checkInterval = null;
this.sessionId = null;
this.setSessionQuery = setSessionQuery;
}
private async initSession(): Promise<any> {
console.log('Creating session:', this.channelUrl);
try {
const response = await fetch(`${this.baseUrl}/init-session`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
path: new URL(this.channelUrl).pathname,
})
});
if (!response.ok) {
throw new Error('Failed to initialize session');
}
const sessionData = await response.json();
this.sessionId = sessionData.id;
this.setSessionQuery(`id=${this.sessionId}`);
return sessionData.id;
} catch (error) {
console.error('Session initialization failed:', error);
throw error;
}
}
private async checkSession(): Promise<boolean> {
if (!this.sessionId) {
return false;
}
console.log('Checking session:', this.sessionId);
try {
const response = await fetch(`${this.baseUrl}/check/${this.sessionId}`);
return response.status === 200;
} catch (error) {
console.error('Session check failed:', error);
return false;
}
}
private startAutoCheck(interval: number = 15000): void {
if (this.checkInterval) {
this.stopAutoCheck();
}
this.checkInterval = window.setInterval(async () => {
const isValid = await this.checkSession();
if (!isValid) {
console.log('Session aborted');
this.initSession();
}
}, interval);
}
private stopAutoCheck(): void {
if (this.checkInterval) {
window.clearInterval(this.checkInterval);
this.checkInterval = null;
}
}
// Public Methods
async createSession(interval: number = 15000): Promise<void> {
if (!this.sessionId) {
await this.initSession();
this.startAutoCheck(interval);
}
}
destroySession(): boolean {
console.log('Destroying session:', this.sessionId);
this.stopAutoCheck();
this.sessionId = null;
this.setSessionQuery(undefined);
return true;
}
// getSessionQuery(): string {
// console.log('Session ID:', this.sessionId);
// if (!this.sessionId) {
// return '';
// }
// return `id=${this.sessionId}`;
// }
type(): string {
return 'streamed-su';
}
}
export { StreamedSuSession };