exec( 'CREATE TABLE IF NOT EXISTS music_requests ( id INT AUTO_INCREMENT PRIMARY KEY, guild_name VARCHAR(120) NOT NULL, requester_name VARCHAR(80) NOT NULL, query_text VARCHAR(255) NOT NULL, source_type VARCHAR(20) NOT NULL, voice_channel VARCHAR(80) DEFAULT NULL, notes VARCHAR(255) DEFAULT NULL, status VARCHAR(20) NOT NULL DEFAULT "queued", created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;' ); $pdo->exec( 'CREATE TABLE IF NOT EXISTS bot_logs ( id INT AUTO_INCREMENT PRIMARY KEY, guild_id VARCHAR(100) DEFAULT NULL, user_name VARCHAR(100) NOT NULL, action VARCHAR(50) NOT NULL, details TEXT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;' ); $pdo->exec( 'CREATE TABLE IF NOT EXISTS bot_settings ( id INT AUTO_INCREMENT PRIMARY KEY, prefix VARCHAR(8) NOT NULL, dj_role VARCHAR(80) DEFAULT NULL, max_volume INT NOT NULL DEFAULT 100, auto_reconnect TINYINT(1) NOT NULL DEFAULT 1, log_level VARCHAR(16) NOT NULL DEFAULT "info", discord_token VARCHAR(255) DEFAULT NULL, discord_app_id VARCHAR(100) DEFAULT NULL, discord_public_key VARCHAR(100) DEFAULT NULL, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;' ); // Add missing columns if they don't exist $cols = $pdo->query("SHOW COLUMNS FROM bot_settings")->fetchAll(PDO::FETCH_COLUMN); if (!in_array('discord_token', $cols)) { $pdo->exec('ALTER TABLE bot_settings ADD COLUMN discord_token VARCHAR(255) DEFAULT NULL AFTER log_level'); } if (!in_array('discord_app_id', $cols)) { $pdo->exec('ALTER TABLE bot_settings ADD COLUMN discord_app_id VARCHAR(100) DEFAULT NULL AFTER discord_token'); } if (!in_array('discord_public_key', $cols)) { $pdo->exec('ALTER TABLE bot_settings ADD COLUMN discord_public_key VARCHAR(100) DEFAULT NULL AFTER discord_app_id'); } $count = (int)$pdo->query('SELECT COUNT(*) FROM bot_settings')->fetchColumn(); if ($count === 0) { $stmt = $pdo->prepare('INSERT INTO bot_settings (prefix, dj_role, max_volume, auto_reconnect, log_level) VALUES (:prefix, :dj_role, :max_volume, :auto_reconnect, :log_level)'); $stmt->execute([ ':prefix' => '!', ':dj_role' => 'DJ', ':max_volume' => 100, ':auto_reconnect' => 1, ':log_level' => 'info', ]); } } function get_settings(): array { $pdo = db(); $settings = $pdo->query('SELECT * FROM bot_settings ORDER BY id ASC LIMIT 1')->fetch(); if (!$settings) { ensure_tables(); $settings = $pdo->query('SELECT * FROM bot_settings ORDER BY id ASC LIMIT 1')->fetch(); } return $settings ?: [ 'id' => 0, 'prefix' => '!', 'dj_role' => 'DJ', 'max_volume' => 100, 'auto_reconnect' => 1, 'log_level' => 'info', 'discord_token' => '', 'discord_app_id' => '', 'discord_public_key' => '', ]; } function status_badge_class(string $status): string { $map = [ 'queued' => 'status-queued', 'playing' => 'status-playing', 'paused' => 'status-paused', 'skipped' => 'status-skipped', 'ended' => 'status-ended', 'failed' => 'status-failed', ]; return $map[$status] ?? 'status-queued'; } function add_log(string $user, string $action, ?string $details = null, ?string $guild_id = null): void { $pdo = db(); $stmt = $pdo->prepare('INSERT INTO bot_logs (user_name, action, details, guild_id) VALUES (:user, :action, :details, :guild_id)'); $stmt->execute([ ':user' => $user, ':action' => $action, ':details' => $details, ':guild_id' => $guild_id, ]); }