// *** Libraries to import *** const { Client, Events, GatewayIntentBits } = require('discord.js'); const Voice = require('@discordjs/voice'); const { createReadStream, existsSync } = require('fs'); //const play = require('play-dl'); // Local config files to import const { token } = require('./.data/config.json'); // Declare a new Discord Client Instance const client = new Client( { intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildVoiceStates] } ); // Define Sigtrap Callback for clean shutdowns function signalExit(signal) { console.log(`\tCaught ${signal}`); // Close the client cleanly client.destroy(); // And exit cleanly process.exit(0); } // Subscribe to a few signal events process.on('SIGINT', signalExit); // For Ctrl-C when running in a TTY process.on('SIGTERM', signalExit); // for systemd's stopping of services // Define Discord Callbacks // Phone Home when the process is started successfully client.on( Events.ClientReady, c => { console.log(`Logged in Successfully as ${c.user.tag}`); // Signal via discord that we are alive client.channels.fetch("860393205401255936") .then( papi => papi.send('hello papi') ); }); // In order to leave a voice channel when its just us we need to process every voice change state in a guild we are in client.on( Events.VoiceStateUpdate, async (oldState, newState) => { // We can limit the exposure to only looking at oldState, the channel the user left if(!oldState.channel) return; // User was not in a channel, this is probably a join if(!oldState.channel.members.has(client.user.id)) return; // We are not in this channel // grab the members, filtering out bots const members = oldState.channel.members.filter(m => !m.user.bot); if(members.size) return; // There are still others in the channel const connection = Voice.getVoiceConnection(oldState.channel.guild.id); connection.destroy(); }); // In order to process text commands we need to process every message sent in a guild we are in client.on( Events.MessageCreate, async message => { if (message.content.match(/[\/;]/)) return; // we had to add '/' because moose tried to 'play' ../../../../etc/shadow // Variables that may be useful const d = new Date(); // Today's date and timestamp // *** Filter Section *** // Prevent any triggering if the message is our own if( message.author.id === "860345552742907935" ) return; //TODO: Also ignore other bots? message.author.bot // In the event of a DM... if (message.guild == null) { switch (message.author.id) { case "262406433201586177": // Weegee case "137358406821347328": // moosecrap case "144317130026778624": // Piroglith case "137293315883139072": // tks_ftw case "172538370440953867": // Brightland case "183009699300507648": // spamminn case "209154502412992514": // NariNaju case "198278682677084160": // DrunkZombie case "137349560610586624": // craze case "305491553198145539": // Sam case "174356437550497792": // NoobWantsHacks case "308412988329558017": // Revanite // TODO: Recieve sound files from trusted parties? return; default: console.log(`Ignoring DM from ${message.author.tag}: ${message.content}`); return; } } // Filter Authorized Guilds switch (message.guild.id) { case "860344888301846538": // ZeSkypeBot Incubator case "305204527152365581": // Goldar Squad break; default: console.log(`Message from Unauthorized Guild ${message.guild.name}!`); return; } // *** Process Section *** // Check for the shut up message if (message.content === "~") { console.log(`!stop issued by ${message.author.tag}`); if (!message.member.voice.channel) { message.channel.send('you can\'t stop the party if you\'re not here'); } else { const connection = Voice.getVoiceConnection(message.guild.id); connection.destroy(); } return; } // Check for youtube play command /* if (message.content.startsWith('!play') && message.member.voice.channel) { console.log(`!play issued by ${message.author.tag} ${message.author.id}`); // Determine if we have a URL or a search term const ytmatch = message.content.match(/(?<=(?:https?:\/\/)(?:www\.)?youtu(?:(?:be\.com\/(?:(?:watch\?v=)|(?:shorts\/)))|(?:\.be\/)))[\w-]{11,12}/); var yturl = null; var timestamp = '0' if (ytmatch) { console.log(`ytmatch yields ${ytmatch[0]}`); // Message matches the youtube video regex, see if it comes with a timestamp const timematch = message.content.match(/(?<=t=)(\d{1,4})s?(?=$)/); if (timematch) {const connection = Voice.getVoiceConnection(message.guild.id); connection.destroy(); console.log(`timematch yields $timematch[1]`); timestamp = timematch[1]; } // Reconstruct a URL for the supplied video yturl = `https://youtu.be/${ytmatch[0]}`; } else { // Message may be a search term let args = message.content.split('play ')[1]; console.log(`ytsearch args: "${args}"`); // Search youtube with the term let yt_info = await play.search(args, { limit: 1 }); // and get the first result as a URL yturl = yt_info[0].url; // Link it to the chat message.channel.send(`Found video ${yturl} hope its what you were looking for`); } console.log(`yturl: ${yturl}`); // Create a stream reference to the provided URL const stream = await play.stream(yturl, { seek: timestamp }); // Now that we have a stream reference we can join the channel and play const connection = Voice.joinVoiceChannel({ channelId: message.member.voice.channel.id, guildId: message.guild.id, adapterCreator: message.guild.voiceAdapterCreator, }); // Open the stream as a voice resource const resource = Voice.createAudioResource(stream.stream, { inputType: stream.type }); // Create a player to play the resource const player = Voice.createAudioPlayer(); // Play the resource through the player (i hate discord v16) player.play(resource); // Connect the player to the voice connection (internal screaming intensifies) connection.subscribe(player); // Setup Callbacks for when the player completes return; } */ if (message.content.match( "!new" )) { const response = 'got tired of getting left in voice calls all night\n' message.channel.send(response); return; } if (message.content.match( "!help" )) { console.log(`!help issued by ${message.author.tag} ${message.author.id}`); var response = 'ZeSkypeBot v7.2.5 \'What Year is it?\'\n'; response += 'Original by @moosecrap for Skype, Remade by @fredstonemason for Discord\n'; response += 'Changelog:\n'; response += 'v4.2.4 First Update in 18 months, !play has been ripped out. Discord.js 14 updated to latest to fix no sound audio\n'; response += 'v7.2.1 Added !echo to try and deduce why theres lag in commands\n'; response += 'v7.2.0 Attempts to fix seemingly random searches, now should support age-restricted videos\n'; response += 'v7.1.0 Added support for searching in !play\n' response += 'v7.0.0 Update to Discord.js 14\n'; response += 'v6.1.0 Update to Discord.js 13, replaced ytdl-core-discord with play-dl\n'; response += 'v6.0.6 Changes to !play regex in pursuit of playing at timestamps\n'; response += 'v6.0.5 Added feedback for cases where ytdl crashes\n'; response += 'v6.0.3 Changed !play regex per user feedback and counterexamples\n'; response += 'v6.0.2 Removed response to voiceless sound commands, for being too spammy\n'; response += 'v6.0.1 Added !play for youtube videos\n'; response += 'v6.0.0 Public release, plays sounds from Goldar Squad\'s collection of micspam audio files. No list will be provided\n'; response += 'Commands:\n'; response += '~ stop any sounds in progress and disconnect from voice\n'; response += '!help print this message\n'; response += 'To play Sounds, first join a voice channel then send a message in the text chat with the name of the sound\n'; // response += '!play [youtube url] play a youtube video over chat\n'; // response += '!play [search terms] play the first video that comes up after searching youtube with your terms\n'; message.channel.send(response); return; } if (message.content.match( "!echo" )) { var response = 'Debug Timers:\n```'; response += `Discord Timestamp: ${message.createdAt.toISOString()}\n`; response += `Local event start: ${d.toISOString()}\n`; d = new Date(); response += `Local event now: ${d.toISOString()}\n`; response += `Online Since: ${client.readyAt.toISOString()}\n`; response += '```'; message.channel.send(response); return; } // Generic message responses if (message.content.match(/https:\/\/ootbingo\.github\.io/)) { var response = 'ooh its bingo time, i call '; if (Math.floor(Math.random()*2)) { response += 'over'; } else { response += 'under'; } response += ' on gateskip'; message.channel.send(response); return; } // Try to find a sound file that matches the message if(message.content.match(' ')) return; // Construct the expected sound path var soundPath = ''; if( d.getMonth() == 3 && d.getDate() == 1 ) { // TODO: april fools! // Scan the directory as an array // select randomly from the array // play that sound instead } else soundPath = `./Sounds/${message.content}.ogg`; if (message.author.id === "172538370440953867") { switch(message.content) { case "butthash": message.react('859687015247511561'); default: } } if (message.author.id === "144317130026778624") { switch(message.content) { case "daytona": case "e": if ([0,5,6].includes(d.getDay()) && Math.random() < 0.8) return; default: } } // Test if there is a file at the expected path if (existsSync(soundPath)) { // Get the VoiceChannel of the sender if there is one const channel = message.member.voice.channel; if (!(channel && channel.joinable && channel.speakable)) return; console.log(`Sound '${message.content}' issued by ${message.author.tag} ${message.author.id}`); // // Join the Voice Channel of the author const connection = Voice.joinVoiceChannel({ channelId: channel.id, guildId: message.guild.id, adapterCreator: message.guild.voiceAdapterCreator, }); // Create an audio player for the desired sound const resource = Voice.createAudioResource(createReadStream(soundPath)); const player = Voice.createAudioPlayer(); // Play the resource through the player to the connection (i hate discord v16) player.play(resource); // Connect the player to the voice connection (internal screaming intensifies) connection.subscribe(player); return; } }); // Now our client is prepared, we can log in. client.login(token);