38431-vm/bot.php
2026-02-14 20:25:06 +00:00

626 lines
30 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/db/config.php';
use Discord\Discord;
use Discord\Voice\VoiceClient;
use Discord\Parts\Channel\Channel;
use Discord\WebSockets\Event;
use Discord\WebSockets\Intents;
use Discord\Builders\CommandBuilder;
use Discord\Builders\MessageBuilder;
use Discord\Parts\Interactions\Interaction;
use Discord\Parts\Interactions\Command\Option;
use React\ChildProcess\Process;
$db = db();
// Ensure tables exist
$db->exec("CREATE TABLE IF NOT EXISTS bot_logs (id INT AUTO_INCREMENT PRIMARY KEY, message TEXT, log_level VARCHAR(50), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
$db->exec("CREATE TABLE IF NOT EXISTS bot_settings (setting_key VARCHAR(255) PRIMARY KEY, setting_value TEXT)");
$db->exec("CREATE TABLE IF NOT EXISTS bot_alarms (id INT AUTO_INCREMENT PRIMARY KEY, user_id VARCHAR(255) UNIQUE, guild_id VARCHAR(255), channel_id VARCHAR(255), alarm_time TIME, audio_url TEXT, is_active TINYINT(1) DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
// Default settings if not present
$stmt = $db->prepare("INSERT IGNORE INTO bot_settings (setting_key, setting_value) VALUES (?, ?)");
$stmt->execute(['sahur_time', '03:00']);
$stmt->execute(['voice_channel_id', '1457687430189682781']);
$stmt->execute(['sahur_source', 'sahur.mp3']);
$stmt->execute(['bot_token', '']); // User should set this manually or it might be already set
$settings = $db->query("SELECT setting_key, setting_value FROM bot_settings")->fetchAll(PDO::FETCH_KEY_PAIR);
$token = $settings['bot_token'] ?? '';
if (empty($token)) {
// Try to get from env if missing in DB
$token = getenv('BOT_TOKEN') ?: '';
}
if (empty($token)) {
echo "Error: Bot token is missing. Please set it in bot_settings table or as BOT_TOKEN env var.\n";
exit(1);
}
$discord = new Discord([
'token' => $token,
'intents' => Intents::getDefaultIntents() | Intents::GUILD_VOICE_STATES | Intents::MESSAGE_CONTENT,
]);
$voiceClient = null;
$joiningGuilds = [];
$ffmpegPath = trim((string)shell_exec("command -v ffmpeg"));
function logToDb($message, $level = 'info') {
try {
$db = db();
$stmt = $db->prepare("INSERT INTO bot_logs (message, log_level) VALUES (?, ?)");
$stmt->execute([$message, $level]);
} catch (Exception $e) {
echo "Log failed: " . $e->getMessage() . "\n";
}
}
$discord->on('ready', function (Discord $discord) {
echo "Bot is ready as " . $discord->user->username . "#" . $discord->user->discriminator . PHP_EOL;
logToDb("Bot is online and ready: " . $discord->user->username);
$db = db();
$db->prepare("INSERT INTO bot_settings (setting_key, setting_value) VALUES ('bot_status', 'online') ON DUPLICATE KEY UPDATE setting_value = 'online'")->execute();
// Listen for voice state updates to debug disconnecting issues
$discord->on(Event::VOICE_STATE_UPDATE, function ($state, Discord $discord) {
if ($state->user_id == $discord->id) {
echo "Bot voice state updated: Channel=" . ($state->channel_id ?? 'None') . " Session=" . ($state->session_id ?? 'None') . "\n";
logToDb("Bot voice state updated: Channel=" . ($state->channel_id ?? 'None'));
}
});
// Periodic timer for Sahur and Alarms
$discord->getLoop()->addPeriodicTimer(60, function () use ($discord) {
$now = date('H:i');
$db = db();
$settings = $db->query("SELECT setting_key, setting_value FROM bot_settings")->fetchAll(PDO::FETCH_KEY_PAIR);
$sahurTime = $settings['sahur_time'] ?? '03:00';
$vcId = $settings['voice_channel_id'] ?? '1457687430189682781';
if ($now === $sahurTime) {
echo "Sahur time triggered ($now)\n";
logToDb("Sahur time triggered.");
playSahur($discord, $vcId);
}
$stmt = $db->prepare("SELECT * FROM bot_alarms WHERE alarm_time LIKE ? AND is_active = 1");
$stmt->execute([$now . '%']);
$alarms = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($alarms as $alarm) {
echo "Alarm triggered for user {$alarm['user_id']} at {$alarm['alarm_time']}\n";
logToDb("Alarm triggered for user {$alarm['user_id']}");
playAlarm($discord, $alarm);
}
});
// Register Commands
registerCommands($discord);
});
function registerCommands(Discord $discord) {
$commands = [
CommandBuilder::new()->setName('join')->setDescription('Join your current voice channel'),
CommandBuilder::new()->setName('out')->setDescription('Leave the voice channel'),
CommandBuilder::new()->setName('status')->setDescription('Check bot status'),
CommandBuilder::new()->setName('play')->setDescription('Play music from URL')
->addOption((new Option($discord))->setName('url')->setDescription('YouTube/TikTok/SoundCloud URL')->setType(Option::STRING)->setRequired(true)),
CommandBuilder::new()->setName('stop')->setDescription('Stop music'),
CommandBuilder::new()->setName('settime')->setDescription('Set your personal alarm time (HH:MM)')
->addOption((new Option($discord))->setName('time')->setDescription('Time in HH:MM format')->setType(Option::STRING)->setRequired(true)),
CommandBuilder::new()->setName('setalarm')->setDescription('Set your personal alarm audio link')
->addOption((new Option($discord))->setName('link')->setDescription('Audio URL for the alarm')->setType(Option::STRING)->setRequired(true)),
CommandBuilder::new()->setName('help')->setDescription('Show help information'),
CommandBuilder::new()->setName('ping')->setDescription('Check if bot is responsive'),
];
foreach ($commands as $command) {
$discord->application->commands->save($discord->application->commands->create($command->toArray()));
}
}
function streamAudio(VoiceClient $vc, string $url, $interaction = null) {
global $discord;
echo "Streaming audio: $url\n";
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("🎶 Loading audio info from link..."));
}
$safeUrl = escapeshellarg($url);
$process = new Process("yt-dlp --no-warnings --no-check-certificates --print \"%(title)s\" --print \"%(url)s\" -f \"ba/b\" --no-playlist --js-runtimes node $safeUrl");
try {
$process->start($discord->getLoop());
} catch (\Exception $e) {
echo "Failed to start yt-dlp process: " . $e->getMessage() . "\n";
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Failed to start audio downloader."));
}
return;
}
$timer = $discord->getLoop()->addTimer(60.0, function() use ($process, $interaction) {
if ($process->isRunning()) {
echo "yt-dlp process timed out after 60s\n";
$process->terminate(SIGKILL);
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Audio loading timed out (60s)."));
}
}
});
$output = '';
$errorOutput = '';
$process->stdout->on('data', function ($chunk) use (&$output) {
$output .= $chunk;
});
$process->stderr->on('data', function ($chunk) use (&$errorOutput) {
$errorOutput .= $chunk;
});
$process->on('exit', function ($code) use (&$output, &$errorOutput, $vc, $interaction, $url, $discord, $timer) {
$discord->getLoop()->cancelTimer($timer);
$lines = array_values(array_filter(explode("\n", trim($output)), function($line) {
return !empty(trim($line)) && strpos($line, 'WARNING:') !== 0;
}));
if ($code === 0 && count($lines) >= 2) {
$title = $lines[0];
$streamUrl = $lines[count($lines) - 1]; // Take the last line as URL, in case there are other prints
echo "Title: $title, Stream URL found: $streamUrl\n";
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("🎶 **Now Playing:** $title"));
}
$playFunc = function ($isFallback = false) use ($vc, $streamUrl, $title, $interaction) {
try {
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
echo "Attempting to play $title. VC Ready: " . ($isReady ? 'Yes' : 'No') . " (Fallback: " . ($isFallback ? 'Yes' : 'No') . ")\n";
if (!$isReady && !$isFallback) {
echo "Voice client not ready yet for $title, waiting for ready event...\n";
return;
}
echo "Calling playFile for $title. URL: " . substr($streamUrl, 0, 50) . "...\n";
$vc->playFile($streamUrl)->then(function() use ($title) {
echo "Finished playing $title\n";
}, function($e) use ($vc, $streamUrl, $title) {
echo "Error playing $title: " . $e->getMessage() . "\n";
logToDb("Error playing $title: " . $e->getMessage(), 'error');
if (strpos($e->getMessage(), 'not ready') !== false) {
echo "Retrying $title in 2 seconds due to 'not ready' error...\n";
$vc->discord->getLoop()->addTimer(2.0, function() use ($vc, $streamUrl) {
try {
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if ($isReady) {
$vc->playFile($streamUrl);
}
} catch (\Throwable $e) {}
});
}
});
} catch (\Throwable $e) {
echo "Exception in playFunc for $title: " . $e->getMessage() . "\n";
}
};
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if ($isReady) {
$playFunc();
} else {
echo "Voice client not ready yet for $title (initial check), adding listeners...\n";
$fallbackTimer = $vc->discord->getLoop()->addTimer(7.0, function() use ($vc, $playFunc, $title) {
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if (!$isReady) {
echo "Still not ready after 7s for $title, trying playFunc as fallback.\n";
$playFunc(true);
}
});
$safetyTimer = $vc->discord->getLoop()->addTimer(45.0, function () use ($vc, $interaction, $title, $fallbackTimer) {
try {
$vc->discord->getLoop()->cancelTimer($fallbackTimer);
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if (!$isReady) {
echo "Timed out waiting for voice client to be ready for $title after 45s\n";
logToDb("Voice client timeout for $title after 45s", 'warning');
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("⚠️ Voice client timed out waiting to be ready. Please try using `/out` then `/join` again."));
try { $vc->close(); } catch (\Exception $e) {}
}
}
} catch (\Exception $e) {
echo "Error in safety timer: " . $e->getMessage() . "\n";
}
});
$vc->once('ready', function() use ($vc, $playFunc, $fallbackTimer, $safetyTimer) {
$vc->discord->getLoop()->cancelTimer($fallbackTimer);
$vc->discord->getLoop()->cancelTimer($safetyTimer);
$playFunc();
});
$vc->once('close', function() use ($vc, $interaction, $title, $fallbackTimer, $safetyTimer) {
$vc->discord->getLoop()->cancelTimer($fallbackTimer);
$vc->discord->getLoop()->cancelTimer($safetyTimer);
echo "Voice client closed for $title while waiting for ready.\n";
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("⚠️ Voice connection closed before it was ready."));
}
});
$vc->once('error', function ($e) use ($title) {
echo "Voice client encountered error while waiting for ready for $title: " . $e->getMessage() . "\n";
logToDb("Voice client error for $title: " . $e->getMessage(), 'error');
});
}
} else {
echo "Failed to fetch stream URL for $url. Code: $code\nError Output: $errorOutput\n";
if ($interaction) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Failed to fetch audio. Make sure the link is valid. (Code $code)"));
}
}
});
}
function playSahur(Discord $discord, $vcId) {
$channel = $discord->getChannel($vcId);
if (!$channel) return;
$vc = $discord->getVoiceClient($channel->guild_id);
if ($vc && (string)$vc->channel->id === (string)$channel->id) {
echo "Sahur: Already in channel, playing directly.\n";
$db = db();
$source = $db->query("SELECT setting_value FROM bot_settings WHERE setting_key = 'sahur_source'")->fetchColumn() ?: 'sahur.mp3';
if (filter_var($source, FILTER_VALIDATE_URL)) {
streamAudio($vc, $source);
} else if (file_exists($source)) {
$vc->playFile($source);
}
return;
}
if ($vc) {
try { $vc->close(); } catch (\Throwable $e) {}
}
$delay = $vc ? 3.0 : 0;
$discord->getLoop()->addTimer($delay, function() use ($discord, $channel) {
if ($discord->getVoiceClient($channel->guild_id)) return;
$discord->joinVoiceChannel($channel, false, false)->then(function (VoiceClient $vc) {
$db = db();
$source = $db->query("SELECT setting_value FROM bot_settings WHERE setting_key = 'sahur_source'")->fetchColumn() ?: 'sahur.mp3';
$playAction = function() use ($vc, $source) {
if (filter_var($source, FILTER_VALIDATE_URL)) {
streamAudio($vc, $source);
} else if (file_exists($source)) {
$vc->playFile($source);
}
};
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if ($isReady) {
$playAction();
} else {
$vc->once('ready', $playAction);
$discord = $vc->discord;
$discord->getLoop()->addTimer(10.0, function() use ($vc, $playAction) {
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if (!$isReady) $playAction();
});
}
});
});
}
function playAlarm(Discord $discord, $alarm) {
$channel = $discord->getChannel($alarm['channel_id']);
if (!$channel) return;
$vc = $discord->getVoiceClient($channel->guild_id);
if ($vc && (string)$vc->channel->id === (string)$channel->id) {
echo "Alarm: Already in channel, playing directly.\n";
streamAudio($vc, $alarm['audio_url']);
return;
}
if ($vc) {
try { $vc->close(); } catch (\Throwable $e) {}
}
$delay = $vc ? 3.0 : 0;
$discord->getLoop()->addTimer($delay, function() use ($discord, $channel, $alarm) {
if ($discord->getVoiceClient($channel->guild_id)) {
$vc = $discord->getVoiceClient($channel->guild_id);
if ((string)$vc->channel->id === (string)$channel->id) streamAudio($vc, $alarm['audio_url']);
return;
}
$discord->joinVoiceChannel($channel, false, false)->then(function (VoiceClient $vc) use ($alarm) {
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if ($isReady) {
streamAudio($vc, $alarm['audio_url']);
} else {
$vc->once('ready', function() use ($vc, $alarm) {
streamAudio($vc, $alarm['audio_url']);
});
$discord = $vc->discord;
$discord->getLoop()->addTimer(10.0, function() use ($vc, $alarm) {
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
if (!$isReady) streamAudio($vc, $alarm['audio_url']);
});
}
});
});
}
$discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Discord $discord) use (&$voiceClient) {
if ($interaction->type !== 2) return;
$command = $interaction->data->name;
logToDb("Received interaction: $command from " . $interaction->member->user->username);
switch ($command) {
case 'ping':
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Pong! 🏓"));
break;
case 'help':
$interaction->respondWithMessage(MessageBuilder::new()->setContent(
"**AsepSahur Bot Commands:**\n" .
"`/join` - Join your voice channel\n" .
"`/play [url]` - Play music from URL\n" .
"`/stop` - Stop current playback\n" .
"`/settime [HH:MM]` - Set your alarm time\n" .
"`/setalarm [url]` - Set your alarm audio\n" .
"`/status` - Check bot status\n" .
"`/ping` - Test bot responsiveness\n" .
"`/out` - Make bot leave voice channel"
));
break;
case 'status':
$vc = $discord->getVoiceClient($interaction->guild_id);
$status = "Bot is online. " . ($vc ? "Connected to " . $vc->channel->name : "Not in voice channel.");
$interaction->respondWithMessage(MessageBuilder::new()->setContent($status));
break;
case 'join':
$userChannel = $interaction->member->getVoiceChannel();
if (!$userChannel) {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("You must be in a voice channel!"));
return;
}
$interaction->acknowledge();
try {
$vc = $discord->getVoiceClient($interaction->guild_id);
if ($vc && (string)$vc->channel->id === (string)$userChannel->id) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("Already in " . $vc->channel->name));
return;
}
global $joiningGuilds;
if (isset($joiningGuilds[$interaction->guild_id])) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ A join request is already in progress. Please wait."));
return;
}
$joiningGuilds[$interaction->guild_id] = true;
if ($vc) {
echo "Closing existing VC for guild " . $interaction->guild_id . " before joining new channel.\n";
$vc->close();
}
$delay = $vc ? 3.0 : 0;
echo "Joining channel: " . $userChannel->name . " (Join command, delay: $delay)\n";
$discord->getLoop()->addTimer($delay, function() use ($discord, $userChannel, $interaction, &$joiningGuilds) {
$vc = $discord->getVoiceClient($interaction->guild_id);
if ($vc) {
unset($joiningGuilds[$interaction->guild_id]);
if ((string)$vc->channel->id === (string)$userChannel->id) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("Joined " . $vc->channel->name));
return;
}
}
$responded = false;
$joinTimeout = $discord->getLoop()->addTimer(20.0, function() use ($interaction, $discord, &$responded, &$joiningGuilds) {
unset($joiningGuilds[$interaction->guild_id]);
if (!$responded) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Joining voice channel timed out (20s)."));
$responded = true;
}
});
$discord->joinVoiceChannel($userChannel, false, false)->then(function (VoiceClient $vc) use ($interaction, $discord, $joinTimeout, &$responded, &$joiningGuilds, $userChannel) {
unset($joiningGuilds[$interaction->guild_id]);
if ($responded) return;
$discord->getLoop()->cancelTimer($joinTimeout);
$responded = true;
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("Joined " . $vc->channel->name));
$vc->on('close', function() use ($userChannel) {
echo "Voice client closed for channel " . $userChannel->name . "\n";
});
}, function ($e) use ($interaction, $discord, $joinTimeout, &$responded, &$joiningGuilds) {
unset($joiningGuilds[$interaction->guild_id]);
if ($responded) return;
$discord->getLoop()->cancelTimer($joinTimeout);
$responded = true;
echo "Error joining VC: " . $e->getMessage() . "\n";
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Error joining voice channel: " . $e->getMessage()));
});
});
} catch (\Throwable $e) {
global $joiningGuilds;
unset($joiningGuilds[$interaction->guild_id]);
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Error: " . $e->getMessage()));
}
break;
case 'play':
$url = $interaction->data->options['url']->value;
$userChannel = $interaction->member->getVoiceChannel();
if (!$userChannel) {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Join a VC first!"));
return;
}
$interaction->acknowledge();
try {
$vc = $discord->getVoiceClient($interaction->guild_id);
if ($vc && (string)$vc->channel->id === (string)$userChannel->id) {
echo "Already in correct channel. Streaming...\n";
streamAudio($vc, $url, $interaction);
} else {
global $joiningGuilds;
if (isset($joiningGuilds[$interaction->guild_id])) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ A join request is already in progress. Please wait."));
return;
}
$joiningGuilds[$interaction->guild_id] = true;
if ($vc) {
echo "Voice client in wrong channel, closing and rejoining...\n";
$vc->close();
}
$delay = $vc ? 3.0 : 0;
echo "Joining channel: " . $userChannel->name . " (Play command, delay: $delay)\n";
$discord->getLoop()->addTimer($delay, function() use ($discord, $userChannel, $interaction, $url, &$joiningGuilds) {
$vc = $discord->getVoiceClient($interaction->guild_id);
if ($vc) {
unset($joiningGuilds[$interaction->guild_id]);
if ((string)$vc->channel->id === (string)$userChannel->id) {
streamAudio($vc, $url, $interaction);
} else {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Connection busy or in another channel. Try again in a moment."));
}
return;
}
$responded = false;
$joinTimeout = $discord->getLoop()->addTimer(20.0, function() use ($interaction, $discord, &$responded, &$joiningGuilds) {
unset($joiningGuilds[$interaction->guild_id]);
if (!$responded) {
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Joining voice channel timed out (20s). Try again."));
$responded = true;
}
});
$discord->joinVoiceChannel($userChannel, false, false)->then(function (VoiceClient $vc) use ($interaction, $discord, $url, $joinTimeout, &$responded, &$joiningGuilds) {
unset($joiningGuilds[$interaction->guild_id]);
if ($responded) return;
$discord->getLoop()->cancelTimer($joinTimeout);
$responded = true;
echo "Joined voice channel, now streaming...\n";
streamAudio($vc, $url, $interaction);
}, function ($e) use ($interaction, $discord, $joinTimeout, &$responded, &$joiningGuilds) {
unset($joiningGuilds[$interaction->guild_id]);
if ($responded) return;
$discord->getLoop()->cancelTimer($joinTimeout);
$responded = true;
echo "Error joining VC: " . $e->getMessage() . "\n";
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Error joining voice channel: " . $e->getMessage()));
});
});
}
} catch (\Throwable $e) {
global $joiningGuilds;
unset($joiningGuilds[$interaction->guild_id]);
echo "Fatal error in play command: " . $e->getMessage() . "\n";
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Fatal error: " . $e->getMessage()));
}
break;
case 'stop':
$vc = $discord->getVoiceClient($interaction->guild_id);
if ($vc) {
$vc->stop();
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Stopped playback."));
} else {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Nothing is playing."));
}
break;
case 'out':
$vc = $discord->getVoiceClient($interaction->guild_id);
if ($vc) {
try {
$vc->close();
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Left voice channel."));
} catch (\Throwable $e) {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Left voice channel."));
}
} else {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("I'm not in a voice channel."));
}
break;
case 'settime':
$time = $interaction->data->options['time']->value;
if (!preg_match('/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/', $time)) {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Invalid format. Use HH:MM (e.g. 03:00)"));
return;
}
$userId = (string)$interaction->member->id;
$guildId = (string)$interaction->guild_id;
$channelId = (string)($interaction->member->getVoiceChannel()->id ?? '');
if (empty($channelId)) {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Please join a voice channel first so I know where to wake you up!"));
return;
}
$db = db();
$stmt = $db->prepare("INSERT INTO bot_alarms (user_id, guild_id, channel_id, alarm_time, audio_url)
VALUES (?, ?, ?, ?, 'sahur.mp3')
ON DUPLICATE KEY UPDATE alarm_time = ?, guild_id = ?, channel_id = ?");
$stmt->execute([$userId, $guildId, $channelId, $time, $time, $guildId, $channelId]);
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Alarm time set to $time. I will join " . $interaction->member->getVoiceChannel()->name . " at that time."));
break;
case 'setalarm':
$link = $interaction->data->options['link']->value;
$userId = (string)$interaction->member->id;
$guildId = (string)$interaction->guild_id;
$channelId = (string)($interaction->member->getVoiceChannel()->id ?? '');
if (empty($channelId)) {
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Please join a voice channel first!"));
return;
}
$db = db();
$stmt = $db->prepare("INSERT INTO bot_alarms (user_id, guild_id, channel_id, alarm_time, audio_url)
VALUES (?, ?, ?, '03:00', ?)
ON DUPLICATE KEY UPDATE audio_url = ?, guild_id = ?, channel_id = ?");
$stmt->execute([$userId, $guildId, $channelId, $link, $link, $guildId, $channelId]);
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Alarm audio set."));
break;
}
});
$discord->run();