First push
This commit is contained in:
commit
eb75bb1a32
|
@ -0,0 +1,4 @@
|
|||
node_modules/
|
||||
cookies.txt
|
||||
config.json
|
||||
package-lock.json
|
|
@ -0,0 +1,63 @@
|
|||
const { addToQueue, playNextInQueue } = require('../utils/queueManager');
|
||||
const ytDlpExec = require('yt-dlp-exec');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
name: 'play',
|
||||
description: 'Play a song from YouTube',
|
||||
async execute(message, args) {
|
||||
const searchQuery = args.join(' ');
|
||||
const voiceChannel = message.member.voice.channel;
|
||||
|
||||
if (!voiceChannel) {
|
||||
return message.reply('You need to be in a voice channel to play music!');
|
||||
}
|
||||
|
||||
if (!searchQuery) {
|
||||
return message.reply('Please provide a YouTube link or a song name.');
|
||||
}
|
||||
|
||||
let url;
|
||||
if (isValidURL(searchQuery)) {
|
||||
url = searchQuery;
|
||||
} else {
|
||||
try {
|
||||
const searchResult = await ytDlpExec(`ytsearch:${searchQuery}`, {
|
||||
dumpSingleJson: true,
|
||||
noPlaylist: true,
|
||||
format: 'bestaudio/best',
|
||||
quiet: true,
|
||||
});
|
||||
url = searchResult.webpage_url;
|
||||
} catch (error) {
|
||||
console.error('yt-dlp search error:', error);
|
||||
return message.reply('Could not find the song. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
const tempFilePath = path.join(__dirname, '../utils/tmp', `${uuidv4()}.mp3`);
|
||||
try {
|
||||
await ytDlpExec(url, {
|
||||
cookies: path.join(__dirname, '../cookies.txt'),
|
||||
format: 'bestaudio',
|
||||
output: tempFilePath,
|
||||
quiet: true,
|
||||
});
|
||||
addToQueue(message.guild.id, tempFilePath);
|
||||
playNextInQueue(message.guild.id, voiceChannel);
|
||||
} catch (error) {
|
||||
console.error('yt-dlp error:', error);
|
||||
message.reply('Failed to download video with yt-dlp.');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function isValidURL(string) {
|
||||
try {
|
||||
new URL(string);
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
const { getQueue } = require('../utils/queueManager');
|
||||
|
||||
module.exports = {
|
||||
name: 'queue',
|
||||
execute(message) {
|
||||
const queue = getQueue(message.guild.id);
|
||||
if (queue.length === 0) {
|
||||
return message.channel.send('The queue is empty!');
|
||||
}
|
||||
const queueString = queue.map((track, index) => `${index + 1}. ${track.title}`).join('\n');
|
||||
message.channel.send(`Current queue:\n${queueString}`);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
const { skipTrack } = require('../utils/queueManager');
|
||||
|
||||
module.exports = {
|
||||
name: 'skip',
|
||||
execute(message) {
|
||||
skipTrack(message.guild.id);
|
||||
message.channel.send('Skipped the current track!');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"prefix": "+",
|
||||
"token": "token",
|
||||
"cookie-file": "/home/user/dz-musicbot/cookies.txt"
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
const { Client, GatewayIntentBits } = require('discord.js');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { prefix, token } = require('./config.json');
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
|
||||
|
||||
client.commands = new Map();
|
||||
|
||||
const tmpDir = path.join(__dirname, 'utils', 'tmp');
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, { recursive: true });
|
||||
}
|
||||
|
||||
fs.readdir(tmpDir, (err, files) => {
|
||||
if (err) throw err;
|
||||
|
||||
for (const file of files) {
|
||||
if (file.endsWith('.mp3')) {
|
||||
fs.unlink(path.join(tmpDir, file), err => {
|
||||
if (err) throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const commandFiles = fs.readdirSync(path.join(__dirname, 'commands')).filter(file => file.endsWith('.js'));
|
||||
for (const file of commandFiles) {
|
||||
const command = require(`./commands/${file}`);
|
||||
client.commands.set(command.name, command);
|
||||
}
|
||||
|
||||
client.once('ready', () => {
|
||||
console.log(`Logged in as ${client.user.tag}!`);
|
||||
});
|
||||
|
||||
client.on('messageCreate', async message => {
|
||||
if (!message.content.startsWith(prefix) || message.author.bot) return;
|
||||
|
||||
const args = message.content.slice(prefix.length).trim().split(/ +/);
|
||||
const commandName = args.shift().toLowerCase();
|
||||
|
||||
if (!client.commands.has(commandName)) return;
|
||||
|
||||
try {
|
||||
await client.commands.get(commandName).execute(message, args);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
message.reply('There was an error trying to execute that command!');
|
||||
}
|
||||
});
|
||||
|
||||
client.login(token);
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@discordjs/voice": "^0.17.0",
|
||||
"discord.js": "^14.15.3",
|
||||
"ffmpeg-static": "^5.2.0",
|
||||
"libsodium-wrappers": "^0.7.15",
|
||||
"opusscript": "^0.0.8",
|
||||
"prism-media": "^1.3.5",
|
||||
"uuid": "^10.0.0",
|
||||
"yt-dlp-exec": "^1.0.2",
|
||||
"ytdl-core": "^4.11.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
const { createAudioPlayer, createAudioResource, AudioPlayerStatus, joinVoiceChannel } = require('@discordjs/voice');
|
||||
const fs = require('fs');
|
||||
|
||||
const queueMap = new Map();
|
||||
|
||||
function addToQueue(guildId, filePath) {
|
||||
if (!queueMap.has(guildId)) {
|
||||
queueMap.set(guildId, []);
|
||||
}
|
||||
queueMap.get(guildId).push(filePath);
|
||||
}
|
||||
|
||||
function getQueue(guildId) {
|
||||
return queueMap.get(guildId) || [];
|
||||
}
|
||||
|
||||
function playNextInQueue(guildId, voiceChannel) {
|
||||
const queue = getQueue(guildId);
|
||||
if (queue.length === 0) return false;
|
||||
|
||||
const connection = joinVoiceChannel({
|
||||
channelId: voiceChannel.id,
|
||||
guildId: guildId,
|
||||
adapterCreator: voiceChannel.guild.voiceAdapterCreator,
|
||||
});
|
||||
|
||||
const audioPlayer = createAudioPlayer();
|
||||
|
||||
const filePath = queue.shift();
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error('Audio file not found:', filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
const resource = createAudioResource(filePath);
|
||||
audioPlayer.play(resource);
|
||||
connection.subscribe(audioPlayer);
|
||||
|
||||
audioPlayer.on(AudioPlayerStatus.Idle, () => {
|
||||
if (queue.length > 0) {
|
||||
playNextInQueue(guildId, voiceChannel);
|
||||
} else {
|
||||
connection.destroy();
|
||||
}
|
||||
fs.unlink(filePath, (err) => {
|
||||
if (err) console.error('Error deleting file:', filePath, err);
|
||||
});
|
||||
});
|
||||
|
||||
audioPlayer.on('error', (err) => {
|
||||
console.error('AudioPlayer error:', err);
|
||||
connection.destroy();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function skipTrack(guildId) {
|
||||
const queue = getQueue(guildId);
|
||||
if (queue.length > 0) {
|
||||
queue.shift();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { addToQueue, getQueue, playNextInQueue, skipTrack };
|
Binary file not shown.
|
@ -0,0 +1,26 @@
|
|||
const { exec } = require('child_process');
|
||||
const path = require('path');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
async function downloadVideo(searchQuery) {
|
||||
const tempFilePath = path.join(__dirname, 'tmp', `${uuidv4()}.mp3`);
|
||||
|
||||
const ytDlpArgs = [
|
||||
'--cookies', path.join(__dirname, '../cookies.txt'),
|
||||
'--format', 'bestaudio',
|
||||
'--output', tempFilePath,
|
||||
searchQuery,
|
||||
];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`yt-dlp ${ytDlpArgs.join(' ')}`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error('yt-dlp error:', stderr);
|
||||
return reject(new Error('Failed to download video with yt-dlp'));
|
||||
}
|
||||
resolve(tempFilePath);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { downloadVideo };
|
Loading…
Reference in New Issue