import React, { useState, useEffect, useRef } from 'react'; import { Monitor, Play, Square, Camera, Settings, Circle, Maximize2 } from 'lucide-react'; import { WebSocketManager } from '../services/WebSocketManager'; interface StreamingViewerProps { wsManager: WebSocketManager; jobId: string | null; autoConnect?: boolean; } export const StreamingViewer: React.FC = ({ wsManager, jobId, autoConnect = false }) => { const [isConnected, setIsConnected] = useState(false); const [currentFrame, setCurrentFrame] = useState(null); const [streamStats, setStreamStats] = useState({ frameCount: 0, fps: 0 }); const [showStream, setShowStream] = useState(false); const [isFullscreen, setIsFullscreen] = useState(false); const lastFrameTimeRef = useRef(null); useEffect(() => { wsManager.on('stream_connected', () => { setIsConnected(true); }); wsManager.on('stream_disconnected', () => { setIsConnected(false); setStreamStats({ frameCount: 0, fps: 0 }); lastFrameTimeRef.current = null; }); wsManager.on('stream_frame', (data: any) => { setCurrentFrame(data.data); const now = performance.now(); const lastFrame = lastFrameTimeRef.current; const fps = lastFrame ? Math.round(1000 / Math.max(now - lastFrame, 1)) : 0; lastFrameTimeRef.current = now; setStreamStats(prev => ({ frameCount: prev.frameCount + 1, fps: fps || prev.fps })); }); wsManager.on('streaming_info', (data: any) => { if (data.streaming?.enabled) { setShowStream(true); } }); }, [wsManager]); useEffect(() => { if (autoConnect && jobId && !wsManager.isStreamConnected()) { setShowStream(true); wsManager.connectStream(jobId); } else { console.log('Auto-connect conditions not met:', { autoConnect: !!autoConnect, jobId: !!jobId, notConnected: !wsManager.isStreamConnected() }); } if (!jobId) { setCurrentFrame(null); setStreamStats({ frameCount: 0, fps: 0 }); lastFrameTimeRef.current = null; setIsConnected(false); } }, [autoConnect, jobId, wsManager]); const handleConnect = () => { if (jobId) { wsManager.connectStream(jobId); } }; const handleDisconnect = () => { wsManager.disconnectStream(); }; const handleStreamClick = (e: React.MouseEvent) => { if (!isConnected) return; const rect = e.currentTarget.getBoundingClientRect(); const x = Math.round((e.clientX - rect.left) * (1280 / rect.width)); const y = Math.round((e.clientY - rect.top) * (800 / rect.height)); wsManager.sendStreamMessage({ type: 'mouse', eventType: 'mousePressed', x, y, button: 'left', clickCount: 1 }); setTimeout(() => { wsManager.sendStreamMessage({ type: 'mouse', eventType: 'mouseReleased', x, y, button: 'left' }); }, 100); }; if (!showStream) { return (

Live Browser View

Real-time browser streaming with interaction

Browser Streaming

Enable streaming to watch BrowserPilot navigate websites in real-time

); } return (

Live Browser View

Real-time browser streaming with interaction

{isConnected ? 'Live' : 'Offline'}
{streamStats.fps} FPS
{currentFrame ? ( Browser Stream ) : (

Waiting for stream data...

)} {/* Stream Controls Overlay */}
); };