const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const { DatabaseSync } = require('node:sqlite'); const DB_PATH = process.env.DB_PATH || path.join(__dirname, 'data', 'app.db'); fs.mkdirSync(path.dirname(DB_PATH), { recursive: true }); const db = new DatabaseSync(DB_PATH); db.exec(` CREATE TABLE IF NOT EXISTS streamers ( id INTEGER PRIMARY KEY AUTOINCREMENT, google_id TEXT UNIQUE NOT NULL, email TEXT NOT NULL, name TEXT NOT NULL, picture TEXT, overlay_token TEXT UNIQUE NOT NULL, sender_token TEXT UNIQUE NOT NULL, tts_voice TEXT NOT NULL DEFAULT 'ru-RU-DmitryNeural', created_at INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS viewer_names ( streamer_id INTEGER NOT NULL, google_id TEXT NOT NULL, display_name TEXT NOT NULL, updated_at INTEGER NOT NULL, PRIMARY KEY (streamer_id, google_id) ); `); function generateToken() { return crypto.randomBytes(16).toString('hex'); } function findStreamerByGoogleId(googleId) { return db.prepare('SELECT * FROM streamers WHERE google_id = ?').get(googleId); } function findStreamerByOverlayToken(token) { return db.prepare('SELECT * FROM streamers WHERE overlay_token = ?').get(token); } function findStreamerBySenderToken(token) { return db.prepare('SELECT * FROM streamers WHERE sender_token = ?').get(token); } function createStreamer({ googleId, email, name, picture }) { const overlayToken = generateToken(); const senderToken = generateToken(); db.prepare( `INSERT INTO streamers (google_id, email, name, picture, overlay_token, sender_token, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)` ).run(googleId, email, name, picture || null, overlayToken, senderToken, Date.now()); return findStreamerByGoogleId(googleId); } function getOrCreateStreamerByGoogle({ googleId, email, name, picture }) { return findStreamerByGoogleId(googleId) || createStreamer({ googleId, email, name, picture }); } function getViewerName(streamerId, googleId) { const row = db .prepare('SELECT display_name FROM viewer_names WHERE streamer_id = ? AND google_id = ?') .get(streamerId, googleId); return row ? row.display_name : null; } function setViewerName(streamerId, googleId, displayName) { db.prepare( `INSERT INTO viewer_names (streamer_id, google_id, display_name, updated_at) VALUES (?, ?, ?, ?) ON CONFLICT(streamer_id, google_id) DO UPDATE SET display_name = excluded.display_name, updated_at = excluded.updated_at` ).run(streamerId, googleId, displayName, Date.now()); } module.exports = { findStreamerByOverlayToken, findStreamerBySenderToken, getOrCreateStreamerByGoogle, getViewerName, setViewerName, };