send2streamer/db.js

97 lines
3.2 KiB
JavaScript
Raw Normal View History

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',
display_duration_seconds INTEGER NOT NULL DEFAULT 10,
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)
);
`);
// Idempotent migration for databases created before display_duration_seconds existed.
const existingColumns = db.prepare('PRAGMA table_info(streamers)').all().map((c) => c.name);
if (!existingColumns.includes('display_duration_seconds')) {
db.exec('ALTER TABLE streamers ADD COLUMN display_duration_seconds INTEGER NOT NULL DEFAULT 10');
}
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());
}
function updateDisplayDuration(streamerId, seconds) {
db.prepare('UPDATE streamers SET display_duration_seconds = ? WHERE id = ?').run(seconds, streamerId);
}
module.exports = {
findStreamerByOverlayToken,
findStreamerBySenderToken,
getOrCreateStreamerByGoogle,
getViewerName,
setViewerName,
updateDisplayDuration,
};