send2streamer/public/send.js
vrubelroman ec6d8c4cfe
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 30s
Let streamers name their AI assistant; fix overlay TTS audio overlap
Streamer dashboard gains an editable AI assistant name (default
"Альтушка Ирина"), stored per-streamer and used for the overlay label,
TTS intro, and DeepSeek system prompt. Also fixes a bug where a long
message's TTS audio could still be playing when the next queued
message started its own audio — the overlay queue now waits for the
current audio to actually finish (not just the configured display
duration) before advancing.
2026-07-08 17:28:36 +00:00

110 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const loginContainer = document.getElementById('login-container');
const mainSection = document.getElementById('hidden-until-login');
const userPic = document.getElementById('user-pic');
const userName = document.getElementById('user-name');
const logoutBtn = document.getElementById('logout');
const displayNameInput = document.getElementById('display-name');
const messageInput = document.getElementById('message');
const aiReplyCheckbox = document.getElementById('ai-reply');
const aiReplyLabel = document.getElementById('ai-reply-label');
const sendBtn = document.getElementById('send');
const statusEl = document.getElementById('status');
const token = location.pathname.split('/').filter(Boolean).pop();
const socket = io({ query: { role: 'sender', token } });
function showLoggedIn(user) {
loginContainer.style.display = 'none';
mainSection.style.display = 'block';
userPic.src = user.picture || '';
userName.textContent = user.name || user.email;
}
function showLoggedOut() {
loginContainer.style.display = 'block';
mainSection.style.display = 'none';
}
async function loadDisplayName() {
const res = await fetch(`/api/viewer-name?token=${encodeURIComponent(token)}`);
if (!res.ok) return;
const { name } = await res.json();
displayNameInput.value = name || '';
}
async function handleCredentialResponse(response) {
const res = await fetch('/auth/google', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ credential: response.credential }),
});
if (res.ok) {
const { user } = await res.json();
showLoggedIn(user);
loadDisplayName();
// The socket connected before login with no session cookie; reconnect so
// its handshake picks up the freshly-issued, now-authenticated cookie.
socket.disconnect();
socket.connect();
} else {
statusEl.textContent = 'Не удалось войти, попробуйте ещё раз';
}
}
async function loadAiName() {
const res = await fetch(`/api/streamer-info?token=${encodeURIComponent(token)}`);
if (!res.ok) return;
const { aiName } = await res.json();
if (aiName) aiReplyLabel.textContent = `Задать вопрос: ${aiName} 🤖`;
}
async function init() {
loadAiName();
const configRes = await fetch('/config');
const { googleClientId } = await configRes.json();
google.accounts.id.initialize({
client_id: googleClientId,
callback: handleCredentialResponse,
});
google.accounts.id.renderButton(loginContainer, { theme: 'outline', size: 'large' });
const meRes = await fetch('/me');
const { user } = await meRes.json();
if (user) {
showLoggedIn(user);
loadDisplayName();
} else {
showLoggedOut();
}
}
sendBtn.addEventListener('click', () => {
const text = messageInput.value.trim();
if (!text) return;
const name = displayNameInput.value.trim();
const aiReply = aiReplyCheckbox.checked;
socket.emit('send_message', { token, text, name, aiReply });
messageInput.value = '';
statusEl.textContent = 'Отправлено';
setTimeout(() => { statusEl.textContent = ''; }, 1500);
});
messageInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
sendBtn.click();
}
});
socket.on('send_error', (msg) => {
statusEl.textContent = 'Ошибка: ' + msg;
});
logoutBtn.addEventListener('click', async () => {
await fetch('/auth/logout', { method: 'POST' });
showLoggedOut();
});
init();