first commit
This commit is contained in:
247
renderer.js
Normal file
247
renderer.js
Normal file
@@ -0,0 +1,247 @@
|
||||
let ws;
|
||||
const videoPlayer = document.getElementById('videoPlayer');
|
||||
const videoOverlay = document.getElementById('videoOverlay');
|
||||
const progressContainer = document.getElementById('progressContainer');
|
||||
const progressFill = document.getElementById('progressFill');
|
||||
const timer = document.getElementById('timer');
|
||||
const loadingSpinner = document.getElementById('loadingSpinner');
|
||||
const loadingStatusText = document.getElementById('loadingStatusText'); // new element
|
||||
let backendDuration = null; // Duration provided by backend
|
||||
|
||||
console.log('Renderer loaded. DOM elements initialized.');
|
||||
|
||||
// Console log passthrough to Electron main
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
['log', 'error', 'warn', 'info'].forEach(level => {
|
||||
const orig = console[level];
|
||||
console[level] = function(...args) {
|
||||
ipcRenderer.send('ui-log', { level, args });
|
||||
orig.apply(console, args);
|
||||
};
|
||||
});
|
||||
console.log('Electron ipcRenderer logging enabled.');
|
||||
}
|
||||
|
||||
// Always muted for security
|
||||
videoPlayer.muted = true;
|
||||
console.log('Video player muted.');
|
||||
|
||||
function connectWebSocket() {
|
||||
console.log('Connecting to WebSocket...');
|
||||
ws = new WebSocket('ws://localhost:8001');
|
||||
ws.onmessage = (event) => {
|
||||
console.log('WebSocket message received:', event.data);
|
||||
try {
|
||||
const message = JSON.parse(event.data);
|
||||
console.log('Parsed message:', message);
|
||||
if (message.type === 'play_video') {
|
||||
console.log('play_video command received:', message);
|
||||
playVideo(
|
||||
message.url,
|
||||
message.location || "center",
|
||||
message.size || 5,
|
||||
message.duration ?? null
|
||||
);
|
||||
} else if (message.type === 'stop_video') {
|
||||
console.log('stop_video command received.');
|
||||
stopVideo();
|
||||
} else if (message.type === 'status_update') {
|
||||
console.log('status_update received:', message.status);
|
||||
updateLoadingStatus(message.status);
|
||||
}
|
||||
} catch (error) {
|
||||
showError('Error parsing message from server.');
|
||||
console.error('Error parsing message:', error);
|
||||
}
|
||||
};
|
||||
ws.onclose = () => {
|
||||
console.warn('WebSocket closed. Retrying...');
|
||||
showError('Lost connection to WebSocket server. Retrying...');
|
||||
setTimeout(connectWebSocket, 3000);
|
||||
};
|
||||
ws.onerror = (err) => {
|
||||
console.error('WebSocket error:', err);
|
||||
showError('WebSocket connection error. Is the server running?');
|
||||
};
|
||||
}
|
||||
|
||||
function updateLoadingStatus(status) {
|
||||
console.log('Updating loading status:', status);
|
||||
if (loadingStatusText) {
|
||||
loadingStatusText.textContent = status;
|
||||
loadingSpinner.style.display = 'flex';
|
||||
videoPlayer.style.display = 'none';
|
||||
progressContainer.style.display = 'none';
|
||||
videoOverlay.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function playVideo(url, location = "center", size = 5, duration = null) {
|
||||
console.log('[UI] playVideo called:', { url, location, size, duration });
|
||||
backendDuration = typeof duration === 'number' && duration > 0 ? duration : null;
|
||||
|
||||
videoPlayer.src = url;
|
||||
videoOverlay.classList.remove('hidden');
|
||||
setOverlayPosition(location, size);
|
||||
|
||||
// Show loading spinner, hide video and progress until ready
|
||||
loadingSpinner.style.display = 'flex';
|
||||
videoPlayer.style.display = 'none';
|
||||
progressContainer.style.display = backendDuration ? 'block' : 'none';
|
||||
|
||||
// Start loading and wait for canplay to avoid black frames
|
||||
videoPlayer.load();
|
||||
console.log('[UI] Video loading started.');
|
||||
|
||||
const cleanup = () => {
|
||||
videoPlayer.removeEventListener('canplay', onCanPlay);
|
||||
videoPlayer.removeEventListener('error', onError);
|
||||
};
|
||||
|
||||
const onCanPlay = () => {
|
||||
console.log('[UI] canplay: starting playback');
|
||||
loadingSpinner.style.display = 'none';
|
||||
videoPlayer.style.display = '';
|
||||
videoPlayer.play().then(() => {
|
||||
console.log('[UI] Video playback started.');
|
||||
}).catch((err) => {
|
||||
console.warn('[UI] Video playback failed:', err);
|
||||
});
|
||||
updateProgress();
|
||||
cleanup();
|
||||
};
|
||||
|
||||
const onError = (e) => {
|
||||
console.error('[UI] Video error:', e);
|
||||
showError(e.message ? e.message.toString() : 'Unknown video error');
|
||||
cleanup();
|
||||
};
|
||||
|
||||
videoPlayer.addEventListener('canplay', onCanPlay, { once: true });
|
||||
videoPlayer.addEventListener('error', onError, { once: true });
|
||||
|
||||
// Safety fallback in case canplay doesn't fire quickly
|
||||
setTimeout(() => {
|
||||
if (loadingSpinner.style.display !== 'none') {
|
||||
console.warn('[UI] Fallback: forcing playback after timeout.');
|
||||
onCanPlay();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function stopVideo() {
|
||||
console.log('stopVideo called.');
|
||||
hideVideo();
|
||||
}
|
||||
|
||||
function sendStoppedMessage() {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify({ type: "stopped" }));
|
||||
console.log('Sent "stopped" message to backend.');
|
||||
}
|
||||
}
|
||||
|
||||
function hideVideo() {
|
||||
console.log('hideVideo called.');
|
||||
backendDuration = null; // Clear backend-provided duration
|
||||
videoOverlay.classList.add('hidden');
|
||||
videoPlayer.pause();
|
||||
videoPlayer.src = '';
|
||||
videoPlayer.style.width = '100vw';
|
||||
videoPlayer.style.height = '100vh';
|
||||
progressContainer.style.display = 'none';
|
||||
progressFill.style.width = '0%';
|
||||
timer.textContent = '';
|
||||
loadingSpinner.style.display = 'none';
|
||||
videoPlayer.style.display = '';
|
||||
sendStoppedMessage(); // Notify backend when video stops
|
||||
}
|
||||
|
||||
// Start WebSocket connection when page loads
|
||||
console.log('Starting WebSocket connection...');
|
||||
connectWebSocket();
|
||||
|
||||
videoPlayer.addEventListener('ended', () => {
|
||||
console.log('Video ended event.');
|
||||
hideVideo();
|
||||
sendStoppedMessage(); // Notify backend when video ends
|
||||
});
|
||||
videoPlayer.addEventListener('timeupdate', () => {
|
||||
// This can be noisy, so only log occasionally
|
||||
if (Math.floor(videoPlayer.currentTime) % 5 === 0) {
|
||||
console.log('Video timeupdate:', videoPlayer.currentTime);
|
||||
}
|
||||
updateProgress();
|
||||
});
|
||||
|
||||
function updateProgress() {
|
||||
let current = 0;
|
||||
try {
|
||||
current = Number(videoPlayer.currentTime) || 0;
|
||||
if (typeof backendDuration === 'number' && backendDuration > 0) {
|
||||
const total = backendDuration;
|
||||
const percent = Math.min((current / total) * 100, 100);
|
||||
progressFill.style.width = percent + '%';
|
||||
timer.textContent = formatTime(current) + ' / ' + formatTime(total);
|
||||
// Optional: reduce noisy logs
|
||||
// console.log(`[UI] Progress: ${percent.toFixed(2)}%`);
|
||||
} else {
|
||||
// No duration provided; hide progress UI
|
||||
progressFill.style.width = '0%';
|
||||
timer.textContent = formatTime(current) + ' / --:--';
|
||||
progressContainer.style.display = 'none';
|
||||
}
|
||||
} catch (err) {
|
||||
progressFill.style.width = '0%';
|
||||
timer.textContent = formatTime(current) + ' / --:--';
|
||||
console.error('[UI] Error updating progress:', err);
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(seconds) {
|
||||
seconds = Math.floor(seconds);
|
||||
const m = Math.floor(seconds / 60);
|
||||
const s = seconds % 60;
|
||||
return `${m}:${s.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function setOverlayPosition(location, size) {
|
||||
console.log('setOverlayPosition called:', { location, size });
|
||||
// Reset styles
|
||||
videoOverlay.style.justifyContent = '';
|
||||
videoOverlay.style.alignItems = '';
|
||||
videoOverlay.style.top = '';
|
||||
videoOverlay.style.left = '';
|
||||
videoOverlay.style.right = '';
|
||||
videoOverlay.style.bottom = '';
|
||||
videoOverlay.style.width = '100vw';
|
||||
videoOverlay.style.height = '100vh';
|
||||
|
||||
// Calculate video size as percentage of viewport (10% to 100%)
|
||||
const percent = Math.min(Math.max(size, 1), 10) * 10;
|
||||
videoPlayer.style.width = percent + 'vw';
|
||||
videoPlayer.style.height = percent + 'vh';
|
||||
|
||||
// Position overlay and video
|
||||
switch (location) {
|
||||
case 'top_left':
|
||||
videoOverlay.style.justifyContent = 'flex-start';
|
||||
videoOverlay.style.alignItems = 'flex-start';
|
||||
break;
|
||||
case 'bottom_left':
|
||||
videoOverlay.style.justifyContent = 'flex-start';
|
||||
videoOverlay.style.alignItems = 'flex-end';
|
||||
break;
|
||||
case 'top_right':
|
||||
videoOverlay.style.justifyContent = 'flex-end';
|
||||
videoOverlay.style.alignItems = 'flex-start';
|
||||
break;
|
||||
case 'center':
|
||||
default:
|
||||
videoOverlay.style.justifyContent = 'center';
|
||||
videoOverlay.style.alignItems = 'center';
|
||||
break;
|
||||
}
|
||||
console.log('Overlay position set.');
|
||||
}
|
||||
Reference in New Issue
Block a user