diff --git a/.env b/.env
new file mode 100644
index 0000000..35739e0
--- /dev/null
+++ b/.env
@@ -0,0 +1,2 @@
+DISCORD_TOKEN=MTQ3Mjc2ODQ4NTQ0NzY5NjY1MA.GPu0MI.AGkSXyQrBdV-5cy6wsYX-KmaNbbZljX_7_UiPA
+PORT=8080
diff --git a/assets/css/custom.css b/assets/css/custom.css
index 50e0502..7e27098 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -1,302 +1,283 @@
+:root {
+ --discord-blurple: #5865F2;
+ --discord-green: #3BA55D;
+ --discord-yellow: #FAA61A;
+ --discord-red: #ED4245;
+ --discord-dark: #2F3136;
+ --discord-darker: #23272A;
+ --discord-darkest: #1E1F22;
+ --discord-text: #FFFFFF;
+ --discord-text-muted: #B9BBBE;
+ --discord-card: #36393F;
+}
+
body {
- background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
- background-size: 400% 400%;
- animation: gradient 15s ease infinite;
- color: #212529;
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
- font-size: 14px;
+ background-color: var(--discord-dark);
+ color: var(--discord-text);
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
margin: 0;
+ padding: 0;
min-height: 100vh;
}
.main-wrapper {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 100vh;
- width: 100%;
- padding: 20px;
- box-sizing: border-box;
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 2rem;
position: relative;
- z-index: 1;
+ z-index: 2;
}
-@keyframes gradient {
- 0% {
- background-position: 0% 50%;
- }
- 50% {
- background-position: 100% 50%;
- }
- 100% {
- background-position: 0% 50%;
- }
-}
-
-.chat-container {
- width: 100%;
- max-width: 600px;
- background: rgba(255, 255, 255, 0.85);
- border: 1px solid rgba(255, 255, 255, 0.3);
- border-radius: 20px;
- display: flex;
- flex-direction: column;
- height: 85vh;
- box-shadow: 0 20px 40px rgba(0,0,0,0.2);
- backdrop-filter: blur(15px);
- -webkit-backdrop-filter: blur(15px);
- overflow: hidden;
-}
-
-.chat-header {
- padding: 1.5rem;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- background: rgba(255, 255, 255, 0.5);
- font-weight: 700;
- font-size: 1.1rem;
+.header {
display: flex;
justify-content: space-between;
align-items: center;
+ padding: 1rem 2rem;
+ background-color: var(--discord-darkest);
+ border-bottom: 1px solid rgba(255,255,255,0.05);
+}
+
+.logo {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: var(--discord-blurple);
+ text-decoration: none;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.hero {
+ text-align: center;
+ padding: 4rem 1rem;
+ background: linear-gradient(180deg, var(--discord-darkest) 0%, var(--discord-dark) 100%);
+ border-radius: 0 0 50px 50px;
+ margin-bottom: 3rem;
+ margin-top: -2rem;
+}
+
+.hero h1 {
+ font-size: 3.5rem;
+ margin-bottom: 1rem;
+ font-weight: 800;
+}
+
+.hero p {
+ color: var(--discord-text-muted);
+ font-size: 1.25rem;
+ max-width: 700px;
+ margin: 0 auto 2.5rem;
+}
+
+.btn-primary {
+ background-color: var(--discord-blurple);
+ color: white !important;
+ padding: 1rem 2.5rem;
+ border-radius: 8px;
+ text-decoration: none;
+ font-weight: 600;
+ transition: all 0.2s;
+ border: none;
+ cursor: pointer;
+ display: inline-block;
+}
+
+.btn-primary:hover {
+ background-color: #4752C4;
+ transform: translateY(-2px);
+}
+
+.grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 2rem;
+ margin-bottom: 4rem;
+}
+
+.card {
+ background-color: var(--discord-card);
+ border-radius: 12px;
+ padding: 2rem;
+ border: 1px solid rgba(255,255,255,0.05);
+ transition: transform 0.3s ease;
+}
+
+.card:hover {
+ transform: translateY(-5px);
+}
+
+.card h3 {
+ margin-top: 0;
+ color: var(--discord-blurple);
+ font-size: 1.5rem;
+ margin-bottom: 1.5rem;
+}
+
+.command-item {
+ display: flex;
+ justify-content: space-between;
+ padding: 0.75rem 0;
+ border-bottom: 1px solid rgba(255,255,255,0.05);
+}
+
+.command-name {
+ font-family: 'Fira Code', monospace;
+ color: var(--discord-green);
+ font-weight: 600;
+}
+
+.setup-section {
+ background-color: var(--discord-darkest);
+ padding: 3rem;
+ border-radius: 20px;
+ margin-top: 4rem;
+ border: 1px solid rgba(88, 101, 242, 0.2);
+}
+
+.setup-section h2 {
+ font-size: 2rem;
+ margin-bottom: 2rem;
+}
+
+pre {
+ background-color: #000;
+ padding: 1.5rem;
+ border-radius: 12px;
+ overflow-x: auto;
+ font-size: 0.9rem;
+ color: #e6e6e6;
+ border: 1px solid #333;
+ line-height: 1.6;
+}
+
+.config-form input {
+ width: 100%;
+ padding: 1rem;
+ background: var(--discord-darker);
+ border: 1px solid #444;
+ border-radius: 8px;
+ color: white;
+ margin-bottom: 1.5rem;
+ font-size: 1rem;
+}
+
+.config-form input:focus {
+ outline: none;
+ border-color: var(--discord-blurple);
+}
+
+.mock-chat {
+ background-color: var(--discord-darker);
+ border-radius: 12px;
+ height: 400px;
+ display: flex;
+ flex-direction: column;
+ margin-top: 2rem;
+ border: 1px solid rgba(255,255,255,0.05);
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 1.5rem;
- display: flex;
- flex-direction: column;
- gap: 1.25rem;
-}
-
-/* Custom Scrollbar */
-::-webkit-scrollbar {
- width: 6px;
-}
-
-::-webkit-scrollbar-track {
- background: transparent;
-}
-
-::-webkit-scrollbar-thumb {
- background: rgba(255, 255, 255, 0.3);
- border-radius: 10px;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: rgba(255, 255, 255, 0.5);
}
.message {
- max-width: 85%;
- padding: 0.85rem 1.1rem;
- border-radius: 16px;
- line-height: 1.5;
- font-size: 0.95rem;
- box-shadow: 0 4px 15px rgba(0,0,0,0.05);
- animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
-}
-
-@keyframes fadeIn {
- from { opacity: 0; transform: translateY(20px) scale(0.95); }
- to { opacity: 1; transform: translateY(0) scale(1); }
-}
-
-.message.visitor {
- align-self: flex-end;
- background: linear-gradient(135deg, #212529 0%, #343a40 100%);
- color: #fff;
- border-bottom-right-radius: 4px;
-}
-
-.message.bot {
- align-self: flex-start;
- background: #ffffff;
- color: #212529;
- border-bottom-left-radius: 4px;
-}
-
-.chat-input-area {
- padding: 1.25rem;
- background: rgba(255, 255, 255, 0.5);
- border-top: 1px solid rgba(0, 0, 0, 0.05);
-}
-
-.chat-input-area form {
+ margin-bottom: 1.5rem;
display: flex;
- gap: 0.75rem;
+ gap: 1rem;
}
-.chat-input-area input {
+.avatar {
+ width: 45px;
+ height: 45px;
+ background-color: var(--discord-blurple);
+ border-radius: 50%;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+}
+
+.msg-content {
flex: 1;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 12px;
- padding: 0.75rem 1rem;
- outline: none;
- background: rgba(255, 255, 255, 0.9);
- transition: all 0.3s ease;
}
-.chat-input-area input:focus {
- border-color: #23a6d5;
- box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2);
+.msg-author {
+ font-weight: 700;
+ font-size: 1rem;
+ margin-bottom: 0.25rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
-.chat-input-area button {
- background: #212529;
- color: #fff;
- border: none;
- padding: 0.75rem 1.5rem;
- border-radius: 12px;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.3s ease;
+.bot-tag {
+ background-color: var(--discord-blurple);
+ font-size: 0.65rem;
+ padding: 0.1rem 0.4rem;
+ border-radius: 4px;
+ text-transform: uppercase;
}
-.chat-input-area button:hover {
- background: #000;
- transform: translateY(-2px);
- box-shadow: 0 5px 15px rgba(0,0,0,0.2);
+.msg-text {
+ font-size: 1rem;
+ color: var(--discord-text-muted);
+ line-height: 1.4;
}
-/* Background Animations */
-.bg-animations {
+.embed {
+ background-color: var(--discord-darkest);
+ border-left: 4px solid var(--discord-blurple);
+ padding: 1.25rem;
+ border-radius: 4px;
+ margin-top: 0.75rem;
+ max-width: 450px;
+}
+
+.embed-title {
+ font-weight: 700;
+ color: white;
+ margin-bottom: 0.5rem;
+}
+
+.embed-description {
+ font-size: 0.9rem;
+ color: var(--discord-text-muted);
+}
+
+.toast {
+ position: fixed;
+ bottom: 2rem;
+ right: 2rem;
+ background-color: var(--discord-green);
+ color: white;
+ padding: 1rem 2rem;
+ border-radius: 8px;
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
+ z-index: 1000;
+ display: none;
+ animation: slideUp 0.3s ease;
+}
+
+@keyframes slideUp {
+ from { transform: translateY(100%); opacity: 0; }
+ to { transform: translateY(0); opacity: 1; }
+}
+
+.bg-decorations {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
- overflow: hidden;
pointer-events: none;
}
-.blob {
+.circle {
position: absolute;
- width: 500px;
- height: 500px;
- background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
- filter: blur(80px);
- animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1);
+ background: radial-gradient(circle, rgba(88, 101, 242, 0.1) 0%, transparent 70%);
}
-
-.blob-1 {
- top: -10%;
- left: -10%;
- background: rgba(238, 119, 82, 0.4);
-}
-
-.blob-2 {
- bottom: -10%;
- right: -10%;
- background: rgba(35, 166, 213, 0.4);
- animation-delay: -7s;
- width: 600px;
- height: 600px;
-}
-
-.blob-3 {
- top: 40%;
- left: 30%;
- background: rgba(231, 60, 126, 0.3);
- animation-delay: -14s;
- width: 450px;
- height: 450px;
-}
-
-@keyframes move {
- 0% { transform: translate(0, 0) rotate(0deg) scale(1); }
- 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); }
- 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); }
- 100% { transform: translate(0, 0) rotate(360deg) scale(1); }
-}
-
-.admin-link {
- font-size: 14px;
- color: #fff;
- text-decoration: none;
- background: rgba(0, 0, 0, 0.2);
- padding: 0.5rem 1rem;
- border-radius: 8px;
- transition: all 0.3s ease;
-}
-
-.admin-link:hover {
- background: rgba(0, 0, 0, 0.4);
- text-decoration: none;
-}
-
-/* Admin Styles */
-.admin-container {
- max-width: 900px;
- margin: 3rem auto;
- padding: 2.5rem;
- background: rgba(255, 255, 255, 0.85);
- backdrop-filter: blur(20px);
- -webkit-backdrop-filter: blur(20px);
- border-radius: 24px;
- box-shadow: 0 20px 50px rgba(0,0,0,0.15);
- border: 1px solid rgba(255, 255, 255, 0.4);
- position: relative;
- z-index: 1;
-}
-
-.admin-container h1 {
- margin-top: 0;
- color: #212529;
- font-weight: 800;
-}
-
-.table {
- width: 100%;
- border-collapse: separate;
- border-spacing: 0 8px;
- margin-top: 1.5rem;
-}
-
-.table th {
- background: transparent;
- border: none;
- padding: 1rem;
- color: #6c757d;
- font-weight: 600;
- text-transform: uppercase;
- font-size: 0.75rem;
- letter-spacing: 1px;
-}
-
-.table td {
- background: #fff;
- padding: 1rem;
- border: none;
-}
-
-.table tr td:first-child { border-radius: 12px 0 0 12px; }
-.table tr td:last-child { border-radius: 0 12px 12px 0; }
-
-.form-group {
- margin-bottom: 1.25rem;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 600;
- font-size: 0.9rem;
-}
-
-.form-control {
- width: 100%;
- padding: 0.75rem 1rem;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 12px;
- background: #fff;
- transition: all 0.3s ease;
- box-sizing: border-box;
-}
-
-.form-control:focus {
- outline: none;
- border-color: #23a6d5;
- box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1);
-}
\ No newline at end of file
diff --git a/assets/js/main.js b/assets/js/main.js
index d349598..bbf758c 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,39 +1,76 @@
document.addEventListener('DOMContentLoaded', () => {
- const chatForm = document.getElementById('chat-form');
- const chatInput = document.getElementById('chat-input');
- const chatMessages = document.getElementById('chat-messages');
+ const mockForm = document.getElementById('mock-chat-form');
+ const mockInput = document.getElementById('mock-chat-input');
+ const mockMessages = document.getElementById('mock-chat-messages');
- const appendMessage = (text, sender) => {
+ const appendMockMessage = (content, author = 'You', isBot = false, embed = null) => {
const msgDiv = document.createElement('div');
- msgDiv.classList.add('message', sender);
- msgDiv.textContent = text;
- chatMessages.appendChild(msgDiv);
- chatMessages.scrollTop = chatMessages.scrollHeight;
+ msgDiv.className = 'message';
+
+ let avatarText = author.substring(0, 2).toUpperCase();
+ if (isBot) avatarText = 'MB';
+
+ let html = `
+
${avatarText}
+
+
${author} ${isBot ? 'BOT ' : ''}
+
${content}
+ `;
+
+ if (embed) {
+ html += `
+
+
${embed.title}
+
${embed.description}
+
+ `;
+ }
+
+ html += `
`;
+ msgDiv.innerHTML = html;
+ mockMessages.appendChild(msgDiv);
+ mockMessages.scrollTop = mockMessages.scrollHeight;
};
- chatForm.addEventListener('submit', async (e) => {
- e.preventDefault();
- const message = chatInput.value.trim();
- if (!message) return;
+ if (mockForm) {
+ mockForm.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const val = mockInput.value.trim();
+ if (!val) return;
- appendMessage(message, 'visitor');
- chatInput.value = '';
+ appendMockMessage(val, 'User');
+ mockInput.value = '';
- try {
- const response = await fetch('api/chat.php', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ message })
- });
- const data = await response.json();
-
- // Artificial delay for realism
+ // Bot logic simulation
setTimeout(() => {
- appendMessage(data.reply, 'bot');
- }, 500);
- } catch (error) {
- console.error('Error:', error);
- appendMessage("Sorry, something went wrong. Please try again.", 'bot');
- }
+ if (val.startsWith('/play')) {
+ const song = val.replace('/play', '').trim() || 'Lofi Hip Hop';
+ appendMockMessage('π Searching for `' + song + '`...', 'MusicBot', true);
+
+ setTimeout(() => {
+ appendMockMessage('πΆ Now playing:', 'MusicBot', true, {
+ title: song,
+ description: 'Requested by User β’ Duration: 03:45 β’ Platform: YouTube'
+ });
+ }, 1200);
+ } else if (val.startsWith('/skip')) {
+ appendMockMessage('βοΈ Skipped current song!', 'MusicBot', true);
+ } else if (val.startsWith('/stop')) {
+ appendMockMessage('βΉοΈ Stopped the player and left the voice channel.', 'MusicBot', true);
+ } else {
+ appendMockMessage('β Unknown command. Use /play to start music!', 'MusicBot', true);
+ }
+ }, 600);
+ });
+ }
+
+ // Smooth scroll for nav links
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
+ anchor.addEventListener('click', function (e) {
+ e.preventDefault();
+ document.querySelector(this.getAttribute('href')).scrollIntoView({
+ behavior: 'smooth'
+ });
+ });
});
});
diff --git a/assets/pasted-20260217-172544-3aee9fad.jpg b/assets/pasted-20260217-172544-3aee9fad.jpg
new file mode 100644
index 0000000..a46dc36
Binary files /dev/null and b/assets/pasted-20260217-172544-3aee9fad.jpg differ
diff --git a/bot.log b/bot.log
new file mode 100644
index 0000000..1b10042
--- /dev/null
+++ b/bot.log
@@ -0,0 +1,20 @@
+[dotenv@17.3.1] injecting env (2) from .env -- tip: π οΈ run anywhere with `dotenvx run -- yourcommand`
+/home/ubuntu/executor/workspace/node_modules/distube/dist/index.js:1288
+ if (invalidKey) throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
+ ^
+
+DisTubeError [INVALID_KEY]: 'ffmpegPath' does not need to be provided in DisTubeOptions
+ at checkInvalidKey (/home/ubuntu/executor/workspace/node_modules/distube/dist/index.js:1288:25)
+ at new Options (/home/ubuntu/executor/workspace/node_modules/distube/dist/index.js:1692:5)
+ at new DisTube (/home/ubuntu/executor/workspace/node_modules/distube/dist/index.js:2281:20)
+ at Object. (/home/ubuntu/executor/workspace/index.js:25:17)
+ at Module._compile (node:internal/modules/cjs/loader:1688:14)
+ at Object..js (node:internal/modules/cjs/loader:1820:10)
+ at Module.load (node:internal/modules/cjs/loader:1423:32)
+ at Function._load (node:internal/modules/cjs/loader:1246:12)
+ at TracingChannel.traceSync (node:diagnostics_channel:322:14)
+ at wrapModuleLoad (node:internal/modules/cjs/loader:235:24) {
+ errorCode: 'INVALID_KEY'
+}
+
+Node.js v22.18.0
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..4fddcf3
--- /dev/null
+++ b/index.js
@@ -0,0 +1,138 @@
+const { Client, GatewayIntentBits, EmbedBuilder, PermissionsBitField, REST, Routes, SlashCommandBuilder } = require('discord.js');
+const { DisTube } = require('distube');
+const { YtDlpPlugin } = require('@distube/yt-dlp');
+const { YouTubePlugin } = require('@distube/youtube');
+const express = require('express');
+const ffmpeg = require('ffmpeg-static');
+require('dotenv').config();
+
+// 1. Keep-Alive System
+const app = express();
+app.get('/', (req, res) => res.send('Bot Musik Online!'));
+app.listen(process.env.PORT || 8080, () => console.log('Keep-Alive aktif di port ' + (process.env.PORT || 8080)));
+
+// 2. Discord Client Setup
+const client = new Client({
+ intents: [
+ GatewayIntentBits.Guilds,
+ GatewayIntentBits.GuildVoiceStates,
+ GatewayIntentBits.GuildMessages,
+ GatewayIntentBits.MessageContent
+ ]
+});
+
+// 3. DisTube Setup
+const distube = new DisTube(client, {
+ emitNewSongOnly: true,
+ emitAddSongWhenCreatingQueue: false,
+ emitAddListWhenCreatingQueue: false,
+ plugins: [
+ new YouTubePlugin(),
+ new YtDlpPlugin()
+ ]
+});
+
+// 4. Slash Commands Definition
+const commands = [
+ new SlashCommandBuilder()
+ .setName('play')
+ .setDescription('Putar musik dari judul atau link')
+ .addStringOption(option =>
+ option.setName('query')
+ .setDescription('Judul lagu atau link (YouTube/Spotify/SoundCloud)')
+ .setRequired(true)),
+ new SlashCommandBuilder()
+ .setName('skip')
+ .setDescription('Lewati lagu saat ini'),
+ new SlashCommandBuilder()
+ .setName('stop')
+ .setDescription('Berhentikan musik dan keluar dari voice channel'),
+ new SlashCommandBuilder()
+ .setName('queue')
+ .setDescription('Lihat daftar antrean lagu'),
+ new SlashCommandBuilder()
+ .setName('pause')
+ .setDescription('Jeda musik'),
+ new SlashCommandBuilder()
+ .setName('resume')
+ .setDescription('Lanjutkan musik'),
+].map(command => command.toJSON());
+
+// 5. Interaction Handling
+client.on('interactionCreate', async interaction => {
+ if (!interaction.isChatInputCommand()) return;
+
+ const { commandName } = interaction;
+ const voiceChannel = interaction.member.voice.channel;
+
+ if (!voiceChannel) {
+ return interaction.reply({ content: 'Kamu harus berada di Voice Channel untuk menggunakan perintah ini!', ephemeral: true });
+ }
+
+ // Anti-Stuck: Defer Reply
+ await interaction.deferReply();
+
+ try {
+ if (commandName === 'play') {
+ const query = interaction.options.getString('query');
+ await distube.play(voiceChannel, query, {
+ textChannel: interaction.channel,
+ member: interaction.member
+ });
+ await interaction.editReply(`π Sedang mencari dan memutar: **${query}**`);
+ } else if (commandName === 'skip') {
+ await distube.skip(interaction.guild);
+ await interaction.editReply('βοΈ Lagu dilewati!');
+ } else if (commandName === 'stop') {
+ await distube.stop(interaction.guild);
+ await interaction.editReply('βΉοΈ Musik dihentikan dan bot keluar!');
+ } else if (commandName === 'pause') {
+ distube.pause(interaction.guild);
+ await interaction.editReply('βΈοΈ Musik dijeda!');
+ } else if (commandName === 'resume') {
+ distube.resume(interaction.guild);
+ await interaction.editReply('βΆοΈ Musik dilanjutkan!');
+ } else if (commandName === 'queue') {
+ const queue = distube.getQueue(interaction.guild);
+ if (!queue) return interaction.editReply('Antrean kosong!');
+ const q = queue.songs.map((song, i) => `${i === 0 ? 'Memutar:' : `${i}.`} ${song.name} - \`${song.formattedDuration}\``).join('\n');
+ await interaction.editReply(`πΆ **Antrean Saat Ini:**\n${q.slice(0, 2000)}`);
+ }
+ } catch (error) {
+ console.error(error);
+ await interaction.editReply(`β Terjadi kesalahan: ${error.message}`);
+ }
+});
+
+// 6. DisTube Events
+distube
+ .on('playSong', (queue, song) => {
+ queue.textChannel.send(`πΆ Sedang memutar: **${song.name}** - \`${song.formattedDuration}\`\nDiminta oleh: ${song.user}`);
+ })
+ .on('addSong', (queue, song) => {
+ queue.textChannel.send(`β
Menambahkan **${song.name}** ke antrean!`);
+ })
+ .on('error', (channel, e) => {
+ if (channel) channel.send(`β Error: ${e.message.slice(0, 1900)}`);
+ console.error(e);
+ });
+
+// 7. Client Ready & Command Registration
+client.once('ready', async () => {
+ console.log(`Bot logged in as ${client.user.tag}`);
+
+ // Register Global Slash Commands
+ const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
+ try {
+ console.log('Memulai refresh slash commands...');
+ await rest.put(
+ Routes.applicationCommands(client.user.id),
+ { body: commands },
+ );
+ console.log('Berhasil mendaftarkan slash commands!');
+ } catch (error) {
+ console.error(error);
+ }
+});
+
+client.login(process.env.DISCORD_TOKEN);
diff --git a/index.php b/index.php
index 9416a71..7b1b2db 100644
--- a/index.php
+++ b/index.php
@@ -1,6 +1,17 @@
query("SELECT setting_key, setting_value FROM bot_settings");
+$settings = [];
+while ($row = $stmt->fetch()) {
+ $settings[$row['setting_key']] = $row['setting_value'];
+}
+
+$botToken = $settings['bot_token'] ?? '';
+$prefix = $settings['prefix'] ?? '/';
+
+$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Advanced Discord Music Bot powered by DisTube';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
@@ -8,45 +19,153 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
- Chat Assistant
+ MusicBot Dashboard
-
-
-
-
-
+
-
-
-
-
-
-
- Hello! I'm your assistant. How can I help you today?
-
-
-
-
+
+
+ Powerful Commands
+
+
+
π΅ Playback
+
= htmlspecialchars($prefix) ?>play Search & play song
+
= htmlspecialchars($prefix) ?>skip Next song
+
= htmlspecialchars($prefix) ?>stop Stop music & leave
+
= htmlspecialchars($prefix) ?>pause Pause playback
+
+
+
π Queue
+
= htmlspecialchars($prefix) ?>queue Show current queue
+
= htmlspecialchars($prefix) ?>nowplaying Current song info
+
= htmlspecialchars($prefix) ?>shuffle Shuffle queue
+
= htmlspecialchars($prefix) ?>volume Change volume
+
+
+
βοΈ Simulation
+
Try typing /play [song] below to see the bot in action.
+
+
+
+
MB
+
+
MusicBot BOT
+
Welcome! Use /play to start listening.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Bot Configuration
+
Save your Discord bot credentials here. These settings will be stored in your private database.
+
+
+
+
+
+ Implementation Guide
+ To run this bot locally or on your server, ensure you have Node.js installed and use the following code based on your requirements (DisTube v4 + Discord.js v14).
+
+
1. Install Dependencies:
+
npm install discord.js distube @distube/yt-dlp play-dl ffmpeg-static @discordjs/voice
+
+
+
2. Bot Core Code (index.js):
+
const { Client, GatewayIntentBits } = require('discord.js');
+const { DisTube } = require('distube');
+const { YtDlpPlugin } = require('@distube/yt-dlp');
+const ffmpeg = require('ffmpeg-static');
+
+const client = new Client({
+ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]
+});
+
+const distube = new DisTube(client, {
+ emitNewSongOnly: true,
+ leaveOnFinish: false,
+ ffmpegPath: ffmpeg, // Fix for suara music
+ plugins: [new YtDlpPlugin()]
+});
+
+client.on('interactionCreate', async interaction => {
+ if (!interaction.isChatInputCommand()) return;
+ if (interaction.commandName === 'play') {
+ await interaction.deferReply(); // Anti-stuck
+ const query = interaction.options.getString('query');
+ distube.play(interaction.member.voice.channel, query, {
+ textChannel: interaction.channel,
+ member: interaction.member
+ });
+ await interaction.editReply(`Searching for: ${query}`);
+ }
+});
+
+client.login('YOUR_TOKEN_HERE');
+
+
+
+
+
+
+
Settings saved successfully!
+
+
+
+
+
-