feat: restream starting notification duration

This commit is contained in:
antebrl
2024-12-20 21:02:22 +00:00
parent 2ce5fd2ca4
commit 3701d5bd43
4 changed files with 55 additions and 26 deletions

View File

@@ -5,8 +5,9 @@ let currentFFmpegProcess = null;
const STORAGE_PATH = process.env.STORAGE_PATH;
function startFFmpeg(nextChannel) {
console.log('Starting FFmpeg process...');
if (currentFFmpegProcess) {
console.log('Terminate previous ffmpeg-Prozess...');
console.log('Gracefully terminate previous ffmpeg-Prozess...');
currentFFmpegProcess.kill('SIGTERM');
}
@@ -37,6 +38,9 @@ function startFFmpeg(nextChannel) {
currentFFmpegProcess.on('close', (code) => {
console.log(`ffmpeg-Process terminated with code: ${code}`);
currentFFmpegProcess = null;
//Restart if crashed
if (code && code !== 255) {
console.log(`Restarting FFmpeg process...`);
startFFmpeg(nextChannel);
@@ -46,7 +50,7 @@ function startFFmpeg(nextChannel) {
function stopFFmpeg() {
if (currentFFmpegProcess) {
console.log('Terminate ffmpeg-Process...');
console.log('Gracefully terminate ffmpeg-Process...');
currentFFmpegProcess.kill('SIGTERM');
currentFFmpegProcess = null;
}

View File

@@ -11,7 +11,7 @@ interface VideoPlayerProps {
function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const hlsRef = useRef<Hls | null>(null);
const { addToast, removeToast } = useContext(ToastContext);
const { addToast, removeToast, clearToasts, editToast } = useContext(ToastContext);
useEffect(() => {
if (!videoRef.current || !channel?.url) return;
@@ -22,15 +22,14 @@ function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
hlsRef.current.destroy();
}
clearToasts();
let toastStartId = null;
if (channel.restream) {
toastStartId = addToast({
type: 'loading',
title: 'Starting Restream',
message: 'This may take a few moments...',
duration: 0,
});
}
toastStartId = addToast({
type: 'loading',
title: channel.restream ? 'Starting Restream': 'Starting Stream',
message: 'This might take a few moments...',
duration: 0,
});
const hls = new Hls({
autoStartLoad: syncEnabled ? false : true,
@@ -75,7 +74,7 @@ function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
const tolerance = import.meta.env.VITE_SYNCHRONIZATION_TOLERANCE || 0.8;
const maxDeviation = import.meta.env.VITE_SYNCHRONIZATION_MAX_DEVIATION || 4;
var toastDurationSet = false;
hls.on(Hls.Events.MANIFEST_PARSED, (_event, _data) => {
if (channel.restream) {
const now = new Date().getTime();
@@ -89,20 +88,26 @@ function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
const timeDiff = (now - lastFragment.programDateTime) / 1000;
const videoLength = fragments.reduce((acc, fragment) => acc + fragment.duration, 0);
const targetDelay = import.meta.env.VITE_STREAM_DELAY;
const targetDelay : number = Number(import.meta.env.VITE_STREAM_DELAY);
//Load stream if it is close to the target delay
const timeTolerance = tolerance + 1;
if (videoLength + timeDiff + timeTolerance >= targetDelay) {
const delay : number = videoLength + timeDiff + timeTolerance;
if (delay >= targetDelay) {
hls.startLoad();
video.play();
console.log("Starting stream");
if (toastStartId) {
if (!toastDurationSet && toastStartId) {
removeToast(toastStartId);
}
} else {
console.log("Waiting for stream to load: ", videoLength + timeDiff + timeTolerance, " < ", targetDelay);
console.log("Waiting for stream to load: ", delay, " < ", targetDelay);
if(!toastDurationSet && toastStartId) {
editToast(toastStartId, {duration: (1 + targetDelay - delay) * 1000});
toastDurationSet = true;
}
// Reload manifest
setTimeout(() => {
@@ -112,6 +117,10 @@ function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
} else {
hls.startLoad();
video.play();
if (toastStartId) {
removeToast(toastStartId);
}
}
});
@@ -153,12 +162,11 @@ function VideoPlayer({ channel, syncEnabled }: VideoPlayerProps) {
removeToast(toastStartId);
}
const is403 = data.response?.code === 403;
addToast({
type: 'error',
title: 'Stream Error',
message: is403 && !channel.restream
? 'Access denied. Try with restream option for this channel.'
message: !channel.restream
? 'The stream is not working. Try with restream option enabled for this channel.'
: `The stream is not working. Check the source. ${data.response?.text}`,
duration: 5000,
});

View File

@@ -42,7 +42,7 @@ function ToastContainer() {
</div>
{/* Progress Bar */}
{toast.type !== 'loading' && (
{toast.duration != 0 && (
<div className="h-1 bg-gray-700 relative">
<div
className="absolute top-0 right-0 h-full"

View File

@@ -4,22 +4,22 @@ import { ToastNotification } from '../../types';
interface ToastContextType {
addToast: (toast: Omit<ToastNotification, 'id'>) => string;
removeToast: (id: string) => void;
clearToasts: () => void;
editToast: (id: string, newToast: Partial<Omit<ToastNotification, 'id'>>) => void;
toasts: ToastNotification[];
}
export const ToastContext = createContext<ToastContextType>({
addToast: () => '',
removeToast: () => {},
clearToasts: () => {},
editToast: () => {},
toasts: [],
});
export function ToastProvider({ children }: { children: React.ReactNode }) {
const [toasts, setToasts] = useState<ToastNotification[]>([]);
const removeToast = useCallback((id: string) => {
setToasts((prevToasts) => prevToasts.filter((toast) => toast.id !== id));
}, []);
const addToast = useCallback(
({ type, title, message, duration = 5000 }: Omit<ToastNotification, 'id'>) => {
const id = Math.random().toString(36).substring(2, 9);
@@ -38,8 +38,25 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
[]
);
const editToast = useCallback(
(id: string, newToast: Partial<Omit<ToastNotification, 'id'>>) => {
setToasts((prevToasts) =>
prevToasts.map((toast) => (toast.id === id ? { ...toast, ...newToast } : toast))
);
},
[]
);
const removeToast = useCallback((id: string) => {
setToasts((prevToasts) => prevToasts.filter((toast) => toast.id !== id));
}, []);
const clearToasts = useCallback(() => {
setToasts([]);
}, []);
return (
<ToastContext.Provider value={{ addToast, removeToast, toasts }}>
<ToastContext.Provider value={{ addToast, removeToast, clearToasts, editToast, toasts }}>
{children}
</ToastContext.Provider>
);