Files
local-transcription/server/php/display.php

185 lines
6.0 KiB
PHP
Raw Normal View History

<!DOCTYPE html>
<html>
<head>
<title>Multi-User Transcription Display</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 0;
padding: 20px;
background: transparent;
font-family: Arial, sans-serif;
color: white;
}
#transcriptions {
max-height: 100vh;
overflow-y: auto;
}
.transcription {
margin: 10px 0;
padding: 10px;
background: rgba(0, 0, 0, 0.7);
border-radius: 5px;
animation: slideIn 0.3s ease-out;
transition: opacity 1s ease-out;
}
.transcription.fading {
opacity: 0;
}
.timestamp {
color: #888;
font-size: 0.9em;
margin-right: 10px;
}
.user {
font-weight: bold;
margin-right: 10px;
/* Color set dynamically via inline style */
}
.text {
color: white;
}
#status {
position: fixed;
top: 10px;
right: 10px;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
border-radius: 5px;
font-size: 0.9em;
}
#status.connected { color: #4CAF50; }
#status.disconnected { color: #f44336; }
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<div id="status" class="disconnected"> Connecting...</div>
<div id="transcriptions"></div>
<script>
// Get URL parameters
const urlParams = new URLSearchParams(window.location.search);
const room = urlParams.get('room') || 'default';
const passphrase = urlParams.get('passphrase') || '';
const fadeAfter = parseInt(urlParams.get('fade') || '10');
const showTimestamps = urlParams.get('timestamps') !== 'false';
const container = document.getElementById('transcriptions');
const statusEl = document.getElementById('status');
const userColors = new Map(); // Map user names to HSL colors
let colorIndex = 0;
// Generate distinct color for each user using golden ratio
function getUserColor(userName) {
if (!userColors.has(userName)) {
// Use golden ratio for evenly distributed hues
const goldenRatio = 0.618033988749895;
const hue = (colorIndex * goldenRatio * 360) % 360;
// High saturation and medium lightness for vibrant, readable colors
const color = `hsl(${hue}, 85%, 65%)`;
userColors.set(userName, color);
colorIndex++;
}
return userColors.get(userName);
}
// Connect to Server-Sent Events
function connect() {
const url = `server.php?action=stream&room=${encodeURIComponent(room)}&passphrase=${encodeURIComponent(passphrase)}`;
const eventSource = new EventSource(url);
eventSource.onopen = () => {
statusEl.textContent = '🟢 Connected';
statusEl.className = 'connected';
};
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
addTranscription(data);
};
eventSource.onerror = () => {
statusEl.textContent = '🔴 Disconnected';
statusEl.className = 'disconnected';
eventSource.close();
// Reconnect after 3 seconds
setTimeout(connect, 3000);
};
}
function addTranscription(data) {
const div = document.createElement('div');
div.className = 'transcription';
// Get user color (generates new color if first time)
const userColor = getUserColor(data.user_name);
let html = '';
if (showTimestamps && data.timestamp) {
html += `<span class="timestamp">[${data.timestamp}]</span>`;
}
if (data.user_name) {
html += `<span class="user" style="color: ${userColor}">${data.user_name}:</span>`;
}
html += `<span class="text">${data.text}</span>`;
div.innerHTML = html;
container.appendChild(div);
// Auto-scroll to bottom
container.scrollTop = container.scrollHeight;
// Set up fade-out if enabled
if (fadeAfter > 0) {
setTimeout(() => {
div.classList.add('fading');
setTimeout(() => {
if (div.parentNode === container) {
container.removeChild(div);
}
}, 1000);
}, fadeAfter * 1000);
}
// Limit to 100 transcriptions
while (container.children.length > 100) {
container.removeChild(container.firstChild);
}
}
// Load recent transcriptions on startup
async function loadRecent() {
try {
const url = `server.php?action=list&room=${encodeURIComponent(room)}&passphrase=${encodeURIComponent(passphrase)}`;
const response = await fetch(url);
const data = await response.json();
if (data.transcriptions) {
// Show last 20 transcriptions
data.transcriptions.slice(-20).forEach(addTranscription);
}
} catch (error) {
console.error('Error loading recent transcriptions:', error);
}
}
// Start
loadRecent().then(() => {
connect();
});
</script>
</body>
</html>