mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-04 05:01:37 +02:00
Improved camera window stream management
This commit is contained in:
@@ -46,39 +46,36 @@ export function CameraPage() {
|
||||
}, [printer]);
|
||||
|
||||
// Cleanup on unmount - stop the camera stream
|
||||
// Track if we've already sent the stop signal to avoid duplicate calls
|
||||
const stopSentRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const stopUrl = `/api/v1/printers/${id}/camera/stop`;
|
||||
stopSentRef.current = false;
|
||||
|
||||
const sendStopOnce = () => {
|
||||
if (id > 0 && !stopSentRef.current) {
|
||||
stopSentRef.current = true;
|
||||
navigator.sendBeacon(stopUrl);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle page unload/close with sendBeacon (more reliable than fetch on unload)
|
||||
const handleBeforeUnload = () => {
|
||||
if (id > 0) {
|
||||
navigator.sendBeacon(stopUrl);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle visibility change (tab hidden/closed)
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'hidden' && id > 0) {
|
||||
navigator.sendBeacon(stopUrl);
|
||||
}
|
||||
sendStopOnce();
|
||||
};
|
||||
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
// Clear the image source
|
||||
// Clear the image source first to stop the stream
|
||||
if (imgRef.current) {
|
||||
imgRef.current.src = '';
|
||||
}
|
||||
// Call the stop endpoint to terminate ffmpeg processes
|
||||
if (id > 0) {
|
||||
// Use sendBeacon for reliability during unmount
|
||||
navigator.sendBeacon(stopUrl);
|
||||
}
|
||||
// Send stop signal only once
|
||||
sendStopOnce();
|
||||
};
|
||||
}, [id]);
|
||||
|
||||
@@ -93,19 +90,31 @@ export function CameraPage() {
|
||||
}
|
||||
}, [streamMode, streamLoading, imageKey, transitioning]);
|
||||
|
||||
// Fullscreen change listener
|
||||
// Fullscreen change listener - refresh stream after fullscreen transition
|
||||
useEffect(() => {
|
||||
const handleFullscreenChange = () => {
|
||||
setIsFullscreen(!!document.fullscreenElement);
|
||||
const nowFullscreen = !!document.fullscreenElement;
|
||||
setIsFullscreen(nowFullscreen);
|
||||
|
||||
// Refresh stream after fullscreen transition to prevent stall
|
||||
if (streamMode === 'stream' && !transitioning) {
|
||||
// Clear image src first, then set new key after delay
|
||||
if (imgRef.current) {
|
||||
imgRef.current.src = '';
|
||||
}
|
||||
setTimeout(() => {
|
||||
setStreamLoading(true);
|
||||
setImageKey(Date.now());
|
||||
}, 200);
|
||||
}
|
||||
};
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
||||
return () => document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
||||
}, []);
|
||||
}, [streamMode, transitioning]);
|
||||
|
||||
// Save window size and position when user resizes or moves (only for popup windows)
|
||||
// Save window size and position when user resizes or moves
|
||||
// Works for both popup windows and standalone camera pages
|
||||
useEffect(() => {
|
||||
if (!window.opener) return;
|
||||
|
||||
let saveTimeout: NodeJS.Timeout;
|
||||
const saveWindowState = () => {
|
||||
// Debounce to avoid saving during drag
|
||||
@@ -121,20 +130,9 @@ export function CameraPage() {
|
||||
};
|
||||
|
||||
window.addEventListener('resize', saveWindowState);
|
||||
// Use interval to detect position changes (no native 'move' event)
|
||||
const positionInterval = setInterval(() => {
|
||||
const saved = localStorage.getItem('cameraWindowState');
|
||||
if (saved) {
|
||||
const state = JSON.parse(saved);
|
||||
if (state.left !== window.screenX || state.top !== window.screenY) {
|
||||
saveWindowState();
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(saveTimeout);
|
||||
clearInterval(positionInterval);
|
||||
window.removeEventListener('resize', saveWindowState);
|
||||
};
|
||||
}, []);
|
||||
@@ -263,8 +261,8 @@ export function CameraPage() {
|
||||
clearInterval(countdownIntervalRef.current);
|
||||
}
|
||||
|
||||
// Auto-resize popup window to fit video content (only if no saved preference)
|
||||
if (window.opener && imgRef.current && !localStorage.getItem('cameraWindowState')) {
|
||||
// Auto-resize window to fit video content (only if no saved preference)
|
||||
if (imgRef.current && !localStorage.getItem('cameraWindowState')) {
|
||||
const img = imgRef.current;
|
||||
const videoWidth = img.naturalWidth;
|
||||
const videoHeight = img.naturalHeight;
|
||||
@@ -281,7 +279,11 @@ export function CameraPage() {
|
||||
const targetWidth = videoWidth + padding + chromeWidth;
|
||||
const targetHeight = videoHeight + headerHeight + padding + chromeHeight;
|
||||
|
||||
window.resizeTo(targetWidth, targetHeight);
|
||||
try {
|
||||
window.resizeTo(targetWidth, targetHeight);
|
||||
} catch {
|
||||
// resizeTo may not be allowed in all contexts
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2370,7 +2370,7 @@ function PrinterCard({
|
||||
`height=${state.height}`,
|
||||
state.left !== undefined ? `left=${state.left}` : '',
|
||||
state.top !== undefined ? `top=${state.top}` : '',
|
||||
'menubar=no,toolbar=no,location=no,status=no',
|
||||
'menubar=no,toolbar=no,location=no,status=no,noopener',
|
||||
].filter(Boolean).join(',');
|
||||
window.open(`/camera/${printer.id}`, `camera-${printer.id}`, features);
|
||||
}}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-BqcFmQ1s.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BuRs1RuZ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DgCUmTZF.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user