This repository has been archived on 2021-12-10. You can view files and clone it, but cannot push or open issues or pull requests.
foggy/src/index.js

386 lines
12 KiB
JavaScript

// Require the necessary discord.js classes
const Discord = require('discord.js');
const Voice = require('@discordjs/voice');
const { token } = require('../config.json');
const { exec } = require('child_process');
const { promisify } = require('util');
const got = require('got');
const youtubedl = require('youtube-dl');
const cheerio = require('cheerio');
const bot = new Discord.Client({
intents: [
Discord.Intents.FLAGS.GUILDS,
Discord.Intents.FLAGS.GUILD_MESSAGES,
Discord.Intents.FLAGS.GUILD_VOICE_STATES,
Discord.Intents.FLAGS.GUILD_MESSAGE_REACTIONS
],
});
bot.once('ready', () => {
console.log('Ready!');
});
const prefix = ';';
const embedColor = 0xa0ffa5;
const foggyImg = 'https://cdn.discordapp.com/attachments/789023763396165633/898908687299657728/552bb191-93e3-4eaa-b935-d5031f3845e7.gif';
const randomTrendStrings = [
'GUYS GUYS GUYS GUYS GUYS DID YOU know That {}',
'trending in russia today: {}',
'I Am Going To Tear Off Your {}',
'tghhe {} is feeling sussy today',
'i am going to devour a {}',
'{},,,,,,,........ mmmmmhhmhmhh :yummy:',
'{}..... no whay',
'Hot Singles Straight From [{}]',
'l',
'{} =)',
'Guys guys checkl this out: {}',
'hehe ..... ... {}.... :)',
'SyntaxError: {}',
'{} is veyr instantly',
'BITCOIN AT {} GO GO TO HTTPS://BITCOIN GO NOW for free ;;!!!!!',
'lol {}',
'the {}',
'GUYS today i accidentaly {}',
'jesus fuckign christ im going to actually fucking {}',
'`{}`. :)',
'holy shit lholy shit hHOLY shit HOLY SHIT {}\n\n!!!!!!!!!!!d'
];
async function postInRandomChannel(text) {
const guild = await bot.guilds.fetch('587108210121506816');
if (!guild.available) return;
const channels = await guild.channels.fetch();
const textChannels = channels.filter(c => c.parentId === '821064982439264308' && c.isText() && c.permissionsFor(bot.user.id).has(Discord.Permissions.FLAGS.SEND_MESSAGES));
if (textChannels.size === 0) return;
textChannels.random().send(text);
}
async function getTrend() {
try {
let t = await got('https://trends24.in/russia/');
const $ = cheerio.load(t.body);
const elems = $('.trend-card > .trend-card__list')[0];
const trends = elems.children.map(n => n.children[0].children[0].data).filter(t => !t.startsWith('#'));
return trends[Math.floor(Math.random() * trends.length)];
} catch(err) {
console.log(err);
}
}
async function postRandomTrend() {
const trend = await getTrend();
if (!trend) return;
postInRandomChannel(randomTrendStrings[Math.floor(Math.random() * randomTrendStrings.length)].replace('{}', trend));
}
function randomTimeout() {
if (Math.random() < 0.2) {
return Math.random() * 1000 * 60; // up to a minute
} else {
return 1000 * 60 * 60 * 12 + Math.random() * 1000 * 60 * 60 * 12; // from 12 to 24 hours
}
}
function doTrendTimeout() {
postRandomTrend();
setTimeout(doTrendTimeout, randomTimeout());
}
// let t = randomTimeout();
// console.log(t / 1000 + ' Seconds Left.');
// setTimeout(doTrendTimeout, t);
async function checkVoiceChannel(msg) {
if (!msg.guild) return;
const clientVoiceState = msg.guild.me.voice;
const memberVoiceState = msg.member.voice;
const voiceConnection = await Voice.getVoiceConnection(msg.guild.id);
if (clientVoiceState.channelId === memberVoiceState.channelId && voiceConnection) {
console.log('reusing connection');
return voiceConnection;
}
if (!memberVoiceState.channelId) {
msg.channel.send('you aren\'t in a voice channel!');
return;
}
if (clientVoiceState.channelId && clientVoiceState.channelId !== memberVoiceState.channelId) {
msg.channel.send('you are in a different voice channel!');
return;
}
console.log('creating new connection');
return Voice.joinVoiceChannel({
channelId: msg.member.voice.channelId,
guildId: msg.guild.id,
adapterCreator: msg.guild.voiceAdapterCreator,
});
}
/*
{
url: string,
}
*/
let queue = {};
let players = {};
let playerStartTime = {};
function advanceQueue(id, channel, subscription, connection) {
if (queue[id][1]) {
const song = queue[id][1];
const embed = new Discord.MessageEmbed()
.setDescription(`now playing: **${song.titleFormat}**`)
.setThumbnail(song.thumbnail)
.setColor(embedColor)
.setAuthor('foggy ♫', foggyImg);
channel.send({embeds: [embed]});
play(queue[id][1], id, connection);
queue[id] = queue[id].slice(1);
} else {
channel.send('no songs left, leaving');
console.log('destroyig');
if (subscription) subscription.unsubscribe();
if (players[id]) delete players[id];
if (connection) connection.destroy();
queue[id] = [];
}
}
async function play(song, id, connection, channel) {
// const stream = ytdl(url, { filter: 'audioonly' });
let player;
let subscription;
let url = song.directUrl;
if (song.redownload) {
let err, out
try {
err, out = await promisify(exec)('youtube-dl -f bestaudio --youtube-skip-dash-manifest --force-ipv4 -g "' + song.originalUrl + '"');
} catch(err_) {
try {
err, out = await promisify(exec)('youtube-dl -f best --youtube-skip-dash-manifest --force-ipv4 -g "' + song.originalUrl + '"');
} catch(err_) {
err = err_
}
}
if (err) {
console.log(err);
channel.send(`failed to retrieve youtube-dl info!: \`\`\`${err}\`\`\``);
advanceQueue(id, channel, subscription, connection);
return;
}
url = out.stdout;
}
try {
const stream = got(url, {isStream: true});
const resource = Voice.createAudioResource(stream, { inputType: Voice.StreamType.Arbitrary });
stream.on('error', err => {
console.log(err);
channel.send(`failed to play track: \`\`\`${err}\`\`\``);
advanceQueue(id, channel, subscription, connection);
return;
});
if (players[id]) {
console.log('reusing player');
player = players[id];
} else {
console.log('creating new player');
player = Voice.createAudioPlayer();
players[id] = player;
subscription = connection.subscribe(player);
player.on(Voice.AudioPlayerStatus.Idle, () => {
advanceQueue(id, channel, subscription, connection);
});
player.on(Voice.AudioPlayerStatus.Playing, () => {
playerStartTime[id] = Date.now();
})
}
player.play(resource);
} catch(err) {
console.log(err);
channel.send(`failed to play track: \`\`\`${err}\`\`\``);
advanceQueue(id, channel, subscription, connection);
return;
}
return player;
}
function rawYTDLQueue(info) {
let song = {
originalUrl: info.webpage_url || url,
directUrl: info.url,
redownload: true,
title: info.title,
thumbnail: info.thumbnail,
titleFormat: info.title,
duration: info._duration_raw,
fileType: info.acodec,
bitrate: info.abr,
};
if (song.track && song.artist && song.album) {
song.titleFormat = `${song.artist} - [${song.track}](${info.webpage_url}) from ${song.album}`;
} else {
if (song.originalUrl.startsWith('http')) song.titleFormat = `[${song.title}](${song.originalUrl})`;
}
return song;
}
function formatTime(t) {
return `${Math.floor(t / 60).toString().padStart(2, '0')}:${Math.floor(t % 60).toString().padStart(2, '0')}`
}
async function queueUp(url, id) {
if (!queue[id]) queue[id] = [];
let song = {};
let err, info;
try {
err, info = await promisify(youtubedl.getInfo)(url, ['--force-ipv4']);
} catch(err_) {
err = err_;
}
if (err) {
return [null, `failed to retrieve youtube-dl info!: \`\`\`${err.toString().slice(0, 1000)}\`\`\``];
} else {
if (info.length) {
info.forEach(i => {
let song = rawYTDLQueue(i);
queue[id].push(song);
});
return [info.length, null];
} else {
song = rawYTDLQueue(info);
}
}
queue[id].push(song)
return [1, null];
}
async function playOrQueue(qsong, channel, msg) {
const connection = await checkVoiceChannel(msg);
if (!connection) return;
console.log(`queueing ${qsong}`);
channel.send(`queueing <${qsong}>...`);
let [q, e] = await queueUp(qsong, msg.guild.id);
if (!q && e) [q, e] = await queueUp('ytsearch:' + qsong, msg.guild.id);
if (!q && e) return msg.channel.send(e);
const song = queue[msg.guild.id][queue[msg.guild.id].length - 1];
if (queue[msg.guild.id].length === 1) {
const embed = new Discord.MessageEmbed()
.setDescription(`now playing: **${song.titleFormat}**`)
.setThumbnail(song.thumbnail)
.setColor(embedColor)
.setAuthor('foggy ♫', foggyImg);
msg.channel.send({embeds: [embed]});
await play(queue[msg.guild.id][0], msg.guild.id, connection, msg.channel);
} else {
let queueString = `queued: **${song.titleFormat}** _at position ${queue[msg.guild.id].length - 1}_`;
if (q > 1) queueString = `queued **${q} songs** _at positions ${queue[msg.guild.id].length - q} - ${queue[msg.guild.id].length - 1}_`;
const embed = new Discord.MessageEmbed()
.setDescription(queueString)
.setColor(embedColor)
.setAuthor('foggy ♫', foggyImg);
msg.channel.send({embeds: [embed]});
if (!players[msg.guild.id] || players[msg.guild.id].state === Voice.AudioPlayerStatus.Idle || players[msg.guild.id].state === Voice.AudioPlayerStatus.Paused) {
await play(queue[msg.guild.id][0], msg.guild.id, connection, msg.channel);
}
}
}
bot.on('messageCreate', async (msg) => {
const content = msg.content;
const params = content.replace(prefix, '').split(' ');
const cmd = params[0];
if (!msg.guild || !content.startsWith(prefix) || !msg.channel) return;
if ((cmd === 'playm' || cmd === 'playmany' || cmd === 'pm') && params[1]) {
for (const p of params.slice(1)) {
await playOrQueue(p, msg.channel, msg);
}
} else if (cmd === 'play' || cmd === 'p') {
playOrQueue(params.slice(1).join(' '), msg.channel, msg);
} else if (cmd === 'skip' || cmd === 's') {
const player = players[msg.guild.id];
if (!player) return msg.channel.send('the bot isn\'t playing any music!');
const song = queue[msg.guild.id][0];
const embed = new Discord.MessageEmbed()
.setDescription(`skipped **${song.titleFormat}**`)
.setColor(embedColor)
.setAuthor('foggy ♫', foggyImg);
msg.channel.send({embeds: [embed]});
player.stop();
} else if (cmd === 'queue' || cmd === 'q') {
const q = queue[msg.guild.id] || [];
if (q.length === 0) {
msg.channel.send('no songs queued!');
} else {
msg.channel.send(`${q.length} track${q.length === 1 ? '' : 's'}\ntotal queue length: \`${formatTime(q.map(s => s.duration).reduce((p, c) => p || 0 + c || 0))}\`\n` + '```' + q.slice(0, 10).map((m, i) => `${i === 0 ? 'now playing:' : i + '.'} ${m.title} ${(m.duration !== 0) ? formatTime(m.duration) : ''}`).join('\n') + '```');
}
} else if (cmd === 'np' || cmd === 'nowplaying') {
const song = (queue[msg.guild.id] || [])[0];
if (!song) return msg.channel.send('no song playing!');
let progress = (Date.now() - (playerStartTime[msg.guild.id] || 0)) / 1000 / song.duration;
let progressLength = 20;
let progressStr = '';
if (song.duration === -1) {
progressStr = '🔘 `where?..`';
} else if (progress < 0 || progress > 1) {
progressStr = '🔘 `buffering,,`';
} else {
progressStr = `${'▬'.repeat(Math.floor(Math.abs(progress) * progressLength))}🔘${'▬'.repeat(Math.floor((1 - Math.abs(progress)) * progressLength))}`;
progressStr += `\n\`${formatTime((Date.now() - (playerStartTime[msg.guild.id] || 0)) / 1000)}\`/\`${formatTime(song.duration)}\``
}
let embed = new Discord.MessageEmbed()
.setDescription(`now playing: **${song.titleFormat}**\n${progressStr}`)
.setFooter(`${song.fileType}${song.bitrate}KB/s`)
.setThumbnail(song.thumbnail)
.setColor(embedColor)
.setAuthor('foggy ♫', foggyImg);
if (queue[msg.guild.id].length !== 1) {
embed = embed.addField('up next', '```' + queue[msg.guild.id].slice(1, 5).map((m, i) => {
if (i === 3) {
return '...';
} else {
return `${i + 1}. ${m.title}`;
}
}).join('\n') + '```')
}
msg.channel.send({embeds: [embed]});
}
});
// Login to Discord with your bot's token
bot.login(token);