Autosave: 20260215-002917
This commit is contained in:
parent
bdc277f00b
commit
fbb0a6dc6c
BIN
assets/pasted-20260214-205736-0d32c9c1.jpg
Normal file
BIN
assets/pasted-20260214-205736-0d32c9c1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 635 KiB |
187
bot.php
187
bot.php
@ -171,50 +171,85 @@ function streamAudio(VoiceClient $vc, string $url, $interaction = null) {
|
||||
$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;
|
||||
$outputLines = explode("\n", trim($output));
|
||||
$lines = array_values(array_filter($outputLines, function($line) {
|
||||
$trimmed = trim($line);
|
||||
return !empty($trimmed) && strpos($trimmed, 'WARNING:') !== 0 && strpos($trimmed, 'ERROR:') !== 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";
|
||||
$title = trim($lines[0]);
|
||||
// Find the last line that looks like a URL
|
||||
$streamUrl = '';
|
||||
for ($i = count($lines) - 1; $i >= 0; $i--) {
|
||||
if (filter_var(trim($lines[$i]), FILTER_VALIDATE_URL)) {
|
||||
$streamUrl = trim($lines[$i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($streamUrl)) {
|
||||
echo "Failed to find valid stream URL in yt-dlp output for $url\n";
|
||||
if ($interaction) {
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Failed to parse audio stream URL."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
echo "Title: $title, Stream URL found: " . substr($streamUrl, 0, 60) . "...\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;
|
||||
}
|
||||
$playAttempted = false;
|
||||
$isClosed = false;
|
||||
$retryCount = 0;
|
||||
$maxRetries = 20;
|
||||
$playFunc = function ($isFallback = false) use (&$playFunc, &$playAttempted, &$isClosed, &$retryCount, $maxRetries, $vc, $streamUrl, $title, $interaction) {
|
||||
if ($isClosed) return;
|
||||
|
||||
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
|
||||
echo "Attempting to play $title. VC Ready: " . ($isReady ? 'Yes' : 'No') . " (Retry: $retryCount/$maxRetries, Fallback: " . ($isFallback ? 'Yes' : 'No') . ")\n";
|
||||
|
||||
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) {}
|
||||
});
|
||||
if (!$isReady) {
|
||||
if ($retryCount < $maxRetries) {
|
||||
$retryCount++;
|
||||
echo "Voice client not ready yet for $title, waiting 2s (attempt $retryCount/$maxRetries)...\n";
|
||||
$vc->discord->getLoop()->addTimer(2.0, function() use (&$playFunc) {
|
||||
$playFunc();
|
||||
});
|
||||
} else {
|
||||
echo "Failed to play $title after $maxRetries retries: Voice client never became ready.\n";
|
||||
if ($interaction) {
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Failed to play: Voice client timed out waiting to be ready."));
|
||||
}
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
echo "Exception in playFunc for $title: " . $e->getMessage() . "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($playAttempted && !$isFallback) return;
|
||||
$playAttempted = true;
|
||||
|
||||
echo "Calling playFile for $title...\n";
|
||||
$vc->playFile($streamUrl)->then(function() use ($title) {
|
||||
echo "Finished playing $title\n";
|
||||
}, function($e) use ($vc, $streamUrl, $title, &$playFunc, &$playAttempted, &$retryCount, $maxRetries, $interaction) {
|
||||
echo "Error playing $title: " . $e->getMessage() . "\n";
|
||||
logToDb("Error playing $title: " . $e->getMessage(), 'error');
|
||||
|
||||
if ($retryCount < $maxRetries && (strpos($e->getMessage(), 'ready') !== false || strpos($e->getMessage(), 'connected') !== false || strpos($e->getMessage(), 'Voice Client') !== false)) {
|
||||
$retryCount++;
|
||||
$playAttempted = false;
|
||||
echo "Retrying $title (attempt $retryCount/$maxRetries) in 3 seconds due to error: " . $e->getMessage() . "\n";
|
||||
$vc->discord->getLoop()->addTimer(3.0, function() use (&$playFunc) {
|
||||
$playFunc();
|
||||
});
|
||||
} else {
|
||||
if ($interaction) {
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Error playing audio: " . $e->getMessage()));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
|
||||
@ -223,7 +258,8 @@ function streamAudio(VoiceClient $vc, string $url, $interaction = null) {
|
||||
} 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) {
|
||||
$fallbackTimer = $vc->discord->getLoop()->addTimer(7.0, function() use ($vc, $playFunc, $title, &$isClosed) {
|
||||
if ($isClosed) return;
|
||||
$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";
|
||||
@ -231,7 +267,8 @@ function streamAudio(VoiceClient $vc, string $url, $interaction = null) {
|
||||
}
|
||||
});
|
||||
|
||||
$safetyTimer = $vc->discord->getLoop()->addTimer(45.0, function () use ($vc, $interaction, $title, $fallbackTimer) {
|
||||
$safetyTimer = $vc->discord->getLoop()->addTimer(45.0, function () use ($vc, $interaction, $title, $fallbackTimer, &$isClosed) {
|
||||
if ($isClosed) return;
|
||||
try {
|
||||
$vc->discord->getLoop()->cancelTimer($fallbackTimer);
|
||||
|
||||
@ -250,13 +287,15 @@ function streamAudio(VoiceClient $vc, string $url, $interaction = null) {
|
||||
}
|
||||
});
|
||||
|
||||
$vc->once('ready', function() use ($vc, $playFunc, $fallbackTimer, $safetyTimer) {
|
||||
$vc->once('ready', function() use ($vc, &$playFunc, $fallbackTimer, $safetyTimer, &$isClosed) {
|
||||
if ($isClosed) return;
|
||||
$vc->discord->getLoop()->cancelTimer($fallbackTimer);
|
||||
$vc->discord->getLoop()->cancelTimer($safetyTimer);
|
||||
$playFunc();
|
||||
});
|
||||
|
||||
$vc->once('close', function() use ($vc, $interaction, $title, $fallbackTimer, $safetyTimer) {
|
||||
$vc->once('close', function() use ($vc, $interaction, $title, $fallbackTimer, $safetyTimer, &$isClosed) {
|
||||
$isClosed = true;
|
||||
$vc->discord->getLoop()->cancelTimer($fallbackTimer);
|
||||
$vc->discord->getLoop()->cancelTimer($safetyTimer);
|
||||
echo "Voice client closed for $title while waiting for ready.\n";
|
||||
@ -398,7 +437,8 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
|
||||
case 'status':
|
||||
$vc = $discord->getVoiceClient($interaction->guild_id);
|
||||
$status = "Bot is online. " . ($vc ? "Connected to " . $vc->channel->name : "Not in voice channel.");
|
||||
$isReady = $vc ? (method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false)) : false;
|
||||
$status = "Bot is online. " . ($vc ? "Connected to " . $vc->channel->name . ($isReady ? " (Ready)" : " (Connecting...)") : "Not in voice channel.");
|
||||
$interaction->respondWithMessage(MessageBuilder::new()->setContent($status));
|
||||
break;
|
||||
|
||||
@ -412,7 +452,9 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
|
||||
try {
|
||||
$vc = $discord->getVoiceClient($interaction->guild_id);
|
||||
if ($vc && (string)$vc->channel->id === (string)$userChannel->id) {
|
||||
$isReady = $vc ? (method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false)) : false;
|
||||
|
||||
if ($vc && $isReady && (string)$vc->channel->id === (string)$userChannel->id) {
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("Already in " . $vc->channel->name));
|
||||
return;
|
||||
}
|
||||
@ -424,28 +466,29 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
}
|
||||
$joiningGuilds[$interaction->guild_id] = true;
|
||||
|
||||
$hadVc = $vc !== null;
|
||||
if ($vc) {
|
||||
echo "Closing existing VC for guild " . $interaction->guild_id . " before joining new channel.\n";
|
||||
$vc->close();
|
||||
try {
|
||||
$vc->close();
|
||||
} catch (\Throwable $e) {}
|
||||
}
|
||||
|
||||
$delay = $vc ? 3.0 : 0;
|
||||
$delay = $hadVc ? 7.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) {
|
||||
if ($vc && (string)$vc->channel->id === (string)$userChannel->id) {
|
||||
unset($joiningGuilds[$interaction->guild_id]);
|
||||
if ((string)$vc->channel->id === (string)$userChannel->id) {
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("Joined " . $vc->channel->name));
|
||||
return;
|
||||
}
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("Joined " . $vc->channel->name));
|
||||
return;
|
||||
}
|
||||
|
||||
$responded = false;
|
||||
$joinTimeout = $discord->getLoop()->addTimer(20.0, function() use ($interaction, $discord, &$responded, &$joiningGuilds) {
|
||||
$joinTimeout = $discord->getLoop()->addTimer(25.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)."));
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Joining voice channel timed out (25s)."));
|
||||
$responded = true;
|
||||
}
|
||||
});
|
||||
@ -488,9 +531,10 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
|
||||
try {
|
||||
$vc = $discord->getVoiceClient($interaction->guild_id);
|
||||
$isReady = $vc ? (method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false)) : false;
|
||||
|
||||
if ($vc && (string)$vc->channel->id === (string)$userChannel->id) {
|
||||
echo "Already in correct channel. Streaming...\n";
|
||||
if ($vc && $isReady && (string)$vc->channel->id === (string)$userChannel->id) {
|
||||
echo "Already in correct channel and ready. Streaming...\n";
|
||||
streamAudio($vc, $url, $interaction);
|
||||
} else {
|
||||
global $joiningGuilds;
|
||||
@ -500,30 +544,41 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
}
|
||||
$joiningGuilds[$interaction->guild_id] = true;
|
||||
|
||||
$hadVc = $vc !== null;
|
||||
if ($vc) {
|
||||
echo "Voice client in wrong channel, closing and rejoining...\n";
|
||||
$vc->close();
|
||||
echo "Voice client in bad state (ready=" . ($isReady ? 'yes' : 'no') . ") or wrong channel, closing and rejoining...\n";
|
||||
try {
|
||||
$vc->close();
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error closing VC: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$delay = $vc ? 3.0 : 0;
|
||||
$delay = $hadVc ? 7.0 : 0; // Increased delay to 7s for cleaner state
|
||||
echo "Joining channel: " . $userChannel->name . " (Play command, delay: $delay)\n";
|
||||
$discord->getLoop()->addTimer($delay, function() use ($discord, $userChannel, $interaction, $url, &$joiningGuilds) {
|
||||
// Double check if we already joined via another command during the delay
|
||||
$vc = $discord->getVoiceClient($interaction->guild_id);
|
||||
if ($vc) {
|
||||
unset($joiningGuilds[$interaction->guild_id]);
|
||||
if ((string)$vc->channel->id === (string)$userChannel->id) {
|
||||
if ($vc && (string)$vc->channel->id === (string)$userChannel->id) {
|
||||
$isReady = method_exists($vc, 'isReady') ? $vc->isReady() : ($vc->ready ?? false);
|
||||
if ($isReady) {
|
||||
unset($joiningGuilds[$interaction->guild_id]);
|
||||
echo "Already in channel after delay and ready, streaming...\n";
|
||||
streamAudio($vc, $url, $interaction);
|
||||
} else {
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Connection busy or in another channel. Try again in a moment."));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a stale VC that didn't close, try one last time
|
||||
if ($vc && (string)$vc->channel->id !== (string)$userChannel->id) {
|
||||
try { $vc->close(); } catch (\Throwable $e) {}
|
||||
}
|
||||
|
||||
$responded = false;
|
||||
$joinTimeout = $discord->getLoop()->addTimer(20.0, function() use ($interaction, $discord, &$responded, &$joiningGuilds) {
|
||||
$joinTimeout = $discord->getLoop()->addTimer(25.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."));
|
||||
$interaction->updateOriginalResponse(MessageBuilder::new()->setContent("❌ Joining voice channel timed out (25s). Try again."));
|
||||
$responded = true;
|
||||
}
|
||||
});
|
||||
@ -534,8 +589,10 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
$discord->getLoop()->cancelTimer($joinTimeout);
|
||||
$responded = true;
|
||||
|
||||
echo "Joined voice channel, now streaming...\n";
|
||||
streamAudio($vc, $url, $interaction);
|
||||
echo "Joined voice channel, waiting 2s for state to settle...\n";
|
||||
$discord->getLoop()->addTimer(2.0, function() use ($vc, $url, $interaction) {
|
||||
streamAudio($vc, $url, $interaction);
|
||||
});
|
||||
}, function ($e) use ($interaction, $discord, $joinTimeout, &$responded, &$joiningGuilds) {
|
||||
unset($joiningGuilds[$interaction->guild_id]);
|
||||
if ($responded) return;
|
||||
@ -569,7 +626,7 @@ $discord->on(Event::INTERACTION_CREATE, function (Interaction $interaction, Disc
|
||||
if ($vc) {
|
||||
try {
|
||||
$vc->close();
|
||||
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Left voice channel."));
|
||||
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Left voice channel and cleaned up connection."));
|
||||
} catch (\Throwable $e) {
|
||||
$interaction->respondWithMessage(MessageBuilder::new()->setContent("Left voice channel."));
|
||||
}
|
||||
|
||||
866
bot_output.log
866
bot_output.log
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user