Autosave: 20260217-173440
This commit is contained in:
parent
7406216157
commit
3380578641
2
.env
Normal file
2
.env
Normal file
@ -0,0 +1,2 @@
|
||||
DISCORD_TOKEN=MTQ3Mjc2ODQ4NTQ0NzY5NjY1MA.GPu0MI.AGkSXyQrBdV-5cy6wsYX-KmaNbbZljX_7_UiPA
|
||||
PORT=8080
|
||||
@ -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);
|
||||
}
|
||||
@ -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 = `
|
||||
<div class="avatar" style="${isBot ? 'background-color: #5865F2;' : 'background-color: #4F545C;'}">${avatarText}</div>
|
||||
<div class="msg-content">
|
||||
<div class="msg-author">${author} ${isBot ? '<span class="bot-tag">BOT</span>' : ''}</div>
|
||||
<div class="msg-text">${content}</div>
|
||||
`;
|
||||
|
||||
if (embed) {
|
||||
html += `
|
||||
<div class="embed">
|
||||
<div class="embed-title">${embed.title}</div>
|
||||
<div class="embed-description">${embed.description}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
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'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
BIN
assets/pasted-20260217-172544-3aee9fad.jpg
Normal file
BIN
assets/pasted-20260217-172544-3aee9fad.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 558 KiB |
20
bot.log
Normal file
20
bot.log
Normal file
@ -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.<anonymous> (/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
|
||||
138
index.js
Normal file
138
index.js
Normal file
@ -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);
|
||||
181
index.php
181
index.php
@ -1,6 +1,17 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Modern AI-ready Chat Assistant';
|
||||
|
||||
// Fetch current settings
|
||||
$stmt = db()->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'] ?? '';
|
||||
?>
|
||||
<!doctype html>
|
||||
@ -8,45 +19,153 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Chat Assistant</title>
|
||||
<title>MusicBot Dashboard</title>
|
||||
<?php if ($projectDescription): ?>
|
||||
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>">
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>">
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=Fira+Code:wght@400;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-animations">
|
||||
<div class="blob blob-1"></div>
|
||||
<div class="blob blob-2"></div>
|
||||
<div class="blob blob-3"></div>
|
||||
</div>
|
||||
<div class="main-wrapper">
|
||||
<div class="chat-container">
|
||||
<div class="chat-header">
|
||||
<span>Chat Assistant</span>
|
||||
<a href="admin.php" class="admin-link">Admin</a>
|
||||
</div>
|
||||
<div class="chat-messages" id="chat-messages">
|
||||
<div class="message bot">
|
||||
Hello! I'm your assistant. How can I help you today?
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-input-area">
|
||||
<form id="chat-form">
|
||||
<input type="text" id="chat-input" placeholder="Type your message..." autocomplete="off">
|
||||
<button type="submit">Send</button>
|
||||
</form>
|
||||
<div class="bg-decorations">
|
||||
<div class="circle" style="width: 600px; height: 600px; top: -200px; left: -200px;"></div>
|
||||
<div class="circle" style="width: 800px; height: 800px; bottom: -300px; right: -300px;"></div>
|
||||
</div>
|
||||
|
||||
<header class="header">
|
||||
<a href="/" class="logo">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-7c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5z"/></svg>
|
||||
MusicBot
|
||||
</a>
|
||||
<nav>
|
||||
<a href="#commands" style="color: white; margin-right: 1.5rem; text-decoration: none;">Commands</a>
|
||||
<a href="#setup" style="color: white; margin-right: 1.5rem; text-decoration: none;">Setup</a>
|
||||
<a href="#config" class="btn-primary" style="padding: 0.5rem 1.2rem;">Get Started</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="hero">
|
||||
<h1>Your Music, Elevated.</h1>
|
||||
<p>The most stable Discord music player with DisTube support. High-quality audio, zero timeout, and support for all your favorite platforms.</p>
|
||||
<div style="display: flex; gap: 1rem; justify-content: center;">
|
||||
<a href="#config" class="btn-primary">Configure Bot</a>
|
||||
<a href="#commands" class="btn-primary" style="background-color: #4F545C;">View Commands</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<main class="main-wrapper">
|
||||
<section id="commands" style="padding-top: 4rem;">
|
||||
<h2 style="text-align: center; margin-bottom: 3rem; font-size: 2.5rem;">Powerful Commands</h2>
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<h3>🎵 Playback</h3>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>play</span> <span>Search & play song</span></div>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>skip</span> <span>Next song</span></div>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>stop</span> <span>Stop music & leave</span></div>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>pause</span> <span>Pause playback</span></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>📋 Queue</h3>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>queue</span> <span>Show current queue</span></div>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>nowplaying</span> <span>Current song info</span></div>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>shuffle</span> <span>Shuffle queue</span></div>
|
||||
<div class="command-item"><span class="command-name"><?= htmlspecialchars($prefix) ?>volume</span> <span>Change volume</span></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>⚙️ Simulation</h3>
|
||||
<p style="color: var(--discord-text-muted); font-size: 0.9rem;">Try typing <span style="color: var(--discord-green)">/play [song]</span> below to see the bot in action.</p>
|
||||
<div class="mock-chat">
|
||||
<div class="chat-messages" id="mock-chat-messages">
|
||||
<div class="message">
|
||||
<div class="avatar">MB</div>
|
||||
<div class="msg-content">
|
||||
<div class="msg-author">MusicBot <span class="bot-tag">BOT</span></div>
|
||||
<div class="msg-text">Welcome! Use /play to start listening.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding: 1rem; border-top: 1px solid rgba(255,255,255,0.05);">
|
||||
<form id="mock-chat-form" style="display: flex; gap: 0.5rem;">
|
||||
<input type="text" id="mock-chat-input" placeholder="Type a command..." style="flex: 1; padding: 0.5rem; background: #40444B; border: none; border-radius: 4px; color: white;">
|
||||
<button type="submit" style="display: none;">Send</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="config" style="padding-top: 4rem;">
|
||||
<div class="card" style="max-width: 600px; margin: 0 auto;">
|
||||
<h3>Bot Configuration</h3>
|
||||
<p style="color: var(--discord-text-muted); margin-bottom: 2rem;">Save your Discord bot credentials here. These settings will be stored in your private database.</p>
|
||||
<form action="save_settings.php" method="POST" class="config-form">
|
||||
<label>Discord Bot Token</label>
|
||||
<input type="password" name="bot_token" value="<?= htmlspecialchars($botToken) ?>" placeholder="Enter your bot token...">
|
||||
<label>Command Prefix</label>
|
||||
<input type="text" name="prefix" value="<?= htmlspecialchars($prefix) ?>" placeholder="/">
|
||||
<button type="submit" class="btn-primary" style="width: 100%;">Save Settings</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="setup" class="setup-section">
|
||||
<h2>Implementation Guide</h2>
|
||||
<p>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).</p>
|
||||
<div style="margin-bottom: 1.5rem;">
|
||||
<strong>1. Install Dependencies:</strong>
|
||||
<pre>npm install discord.js distube @distube/yt-dlp play-dl ffmpeg-static @discordjs/voice</pre>
|
||||
</div>
|
||||
<div>
|
||||
<strong>2. Bot Core Code (index.js):</strong>
|
||||
<pre>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');</pre>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer style="text-align: center; padding: 4rem 2rem; color: var(--discord-text-muted);">
|
||||
<p>© <?= date('Y') ?> MusicBot. Built for high-performance Discord communities.</p>
|
||||
</footer>
|
||||
|
||||
<div id="toast" class="toast">Settings saved successfully!</div>
|
||||
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<?php if (isset($_GET['saved'])): ?>
|
||||
<script>
|
||||
document.getElementById('toast').style.display = 'block';
|
||||
setTimeout(() => { document.getElementById('toast').style.display = 'none'; }, 3000);
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
1804
package-lock.json
generated
Normal file
1804
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
package.json
Normal file
28
package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "workspace",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@discordjs/voice": "^0.19.0",
|
||||
"@distube/youtube": "^1.0.4",
|
||||
"@distube/yt-dlp": "^2.0.1",
|
||||
"@snazzah/davey": "^0.1.9",
|
||||
"discord-api-types": "^0.38.39",
|
||||
"discord.js": "^14.25.1",
|
||||
"distube": "^5.2.3",
|
||||
"dotenv": "^17.3.1",
|
||||
"express": "^5.2.1",
|
||||
"ffmpeg-static": "^5.3.0",
|
||||
"is-ci": "^4.1.0",
|
||||
"libsodium-wrappers": "^0.8.2",
|
||||
"opusscript": "^0.0.8"
|
||||
}
|
||||
}
|
||||
29
save_settings.php
Normal file
29
save_settings.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$botToken = $_POST['bot_token'] ?? '';
|
||||
$prefix = $_POST['prefix'] ?? '/';
|
||||
|
||||
$db = db();
|
||||
|
||||
// UPSERT pattern for MySQL/MariaDB
|
||||
$sql = "INSERT INTO bot_settings (setting_key, setting_value)
|
||||
VALUES (:key1, :val1), (:key2, :val2)
|
||||
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)";
|
||||
|
||||
try {
|
||||
$stmt = $db->prepare("INSERT INTO bot_settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?");
|
||||
|
||||
$db->beginTransaction();
|
||||
$stmt->execute(['bot_token', $botToken, $botToken]);
|
||||
$stmt->execute(['prefix', $prefix, $prefix]);
|
||||
$db->commit();
|
||||
|
||||
header('Location: index.php?saved=1#config');
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
if ($db->inTransaction()) $db->rollBack();
|
||||
die("Error saving settings: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user