Updated to Node:16.9 & Discord.js:13. Added support for ytsearch.
This commit is contained in:
parent
668e57d2f6
commit
8e6b46d115
3
.dockerignore
Executable file
3
.dockerignore
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
Sounds
|
||||||
|
Markov
|
||||||
|
|
||||||
23
.gitignore
vendored
23
.gitignore
vendored
@ -1,21 +1,2 @@
|
|||||||
|
.env
|
||||||
### SkypeBot Git Ignore file ###
|
config.json
|
||||||
|
|
||||||
# I aint leaking API keys like Craze
|
|
||||||
auth.json
|
|
||||||
|
|
||||||
# Ignore libraries that you can find elsewhere
|
|
||||||
node_modules/*
|
|
||||||
!node_modules/.gitkeep
|
|
||||||
|
|
||||||
# Create the necessary Sounds folder
|
|
||||||
sounds/*
|
|
||||||
!sounds/.gitkeep
|
|
||||||
|
|
||||||
# remove all other unnecessary stuff
|
|
||||||
*.jpg
|
|
||||||
sounds_flac/
|
|
||||||
|
|
||||||
# Docker Image Creation Files
|
|
||||||
Dockerfile
|
|
||||||
.dockerignore
|
|
||||||
|
|||||||
12
Dockerfile
Executable file
12
Dockerfile
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
FROM node:latest
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
CMD [ "node", "bot.js" ]
|
||||||
|
|
||||||
178
bot.js
178
bot.js
@ -1,21 +1,15 @@
|
|||||||
// Include Discordjs library
|
// ZeSkypeBot 7.0.0_a
|
||||||
// http://github.com/discordjs/
|
|
||||||
const { Client, VoiceChannel, Intents } = require('discord.js');
|
|
||||||
// Include fs, for reading and writing files
|
|
||||||
const fs = require('fs');
|
|
||||||
// Include ytdl, so we can play youtube videos over voice
|
|
||||||
const ytdl = require('ytdl-core-discord');
|
|
||||||
// Include our local auth key, so that we don't leak keys
|
|
||||||
const auth = require('./auth.json');
|
|
||||||
// Volume for playback (fraction)
|
|
||||||
const volume = 0.60;
|
|
||||||
|
|
||||||
// **** PROGRAM START ****
|
// *** Libraries to import ***
|
||||||
// This program is 2 lines of code, the rest is callback function definition, wherein the bot magic happens
|
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('./config.json');
|
||||||
|
|
||||||
// Initialize a new Discord Client, and tell Discord what updates we are interested in recieving
|
// Declare a new Discord Client Instance
|
||||||
// https://discord.com/developers/docs/topics/gateway#list-of-intents
|
const client = new Client( { intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildVoiceStates] } );
|
||||||
const client = new Client({ intents: [Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS] });
|
|
||||||
|
|
||||||
// Define Sigtrap Callback for clean shutdowns
|
// Define Sigtrap Callback for clean shutdowns
|
||||||
function signalExit(signal) {
|
function signalExit(signal) {
|
||||||
@ -29,18 +23,12 @@ function signalExit(signal) {
|
|||||||
process.on('SIGINT', signalExit); // For Ctrl-C when running in a TTY
|
process.on('SIGINT', signalExit); // For Ctrl-C when running in a TTY
|
||||||
process.on('SIGTERM', signalExit); // for systemd's stoppping of services
|
process.on('SIGTERM', signalExit); // for systemd's stoppping of services
|
||||||
|
|
||||||
// Define Several Discord Related Callbacks
|
// Define Discord Callbacks
|
||||||
|
client.on( Events.ClientReady, c => {
|
||||||
// This one only triggers when the connection to Discord is sucessful. Usually this is once at the start,
|
console.log(`Logged in Successfully as ${c.user.tag}`);
|
||||||
// But if the connection to Discord hiccups for any reason, this will trigger again.
|
});
|
||||||
client.on('ready', () => { console.log(`Logged in as ${client.user.tag}!`); });
|
client.on( Events.MessageCreate, async message => {
|
||||||
|
// *** FIlter Section ***
|
||||||
// Here's the brains of the operation. This triggers every time a message is sent in any server the bot is in.
|
|
||||||
// the async modifier really means async and concurently. Consider thread safety when interacting with globals.
|
|
||||||
// The Message Object is our keyhole into Discord, where we have lots of fields and objects to work with.
|
|
||||||
// https://discord.js.org/#/docs/main/v12/class/Message
|
|
||||||
client.on('message', async message => {
|
|
||||||
// Filter Section
|
|
||||||
// In the event of a DM...
|
// In the event of a DM...
|
||||||
if (message.guild == null) {
|
if (message.guild == null) {
|
||||||
switch (message.author.id) {
|
switch (message.author.id) {
|
||||||
@ -72,17 +60,18 @@ client.on('message', async message => {
|
|||||||
console.log(`Message from Unauthorized Guild ${message.guild.name}!`);
|
console.log(`Message from Unauthorized Guild ${message.guild.name}!`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Pre-Work
|
|
||||||
// Do a few things that may be helpful
|
// *** Process Section ***
|
||||||
const d = new Date();
|
// Variables that may be useful
|
||||||
// Process Section
|
const d = new Date(); // Today's date and timestamp
|
||||||
// Check for the shutup message
|
// Check for the shutup message
|
||||||
if (message.content === "~") {
|
if (message.content === "~") {
|
||||||
console.log(`!stop issued by ${message.author.tag}`);
|
console.log(`!stop issued by ${message.author.tag}`);
|
||||||
if (!message.member.voice.channel) {
|
if (!message.member.voice.channel) {
|
||||||
message.channel.send('you can\'t stop the party if you\'re not here');
|
message.channel.send('you can\'t stop the party if you\'re not here');
|
||||||
} else {
|
} else {
|
||||||
message.member.voice.channel.leave();
|
const connection = Voice.getVoiceConnection(message.guild.id);
|
||||||
|
connection.destroy();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -90,7 +79,7 @@ client.on('message', async message => {
|
|||||||
if (!message.content.match(/[ \/;]/)) {
|
if (!message.content.match(/[ \/;]/)) {
|
||||||
// we had to add '/' because moose tried to 'play' ../../../../etc/shadow
|
// we had to add '/' because moose tried to 'play' ../../../../etc/shadow
|
||||||
// Construct the expected sound path
|
// Construct the expected sound path
|
||||||
const soundPath = `./sounds/${message.content}.ogg`;
|
const soundPath = `./Sounds/${message.content}.ogg`;
|
||||||
if (message.author.id === "172538370440953867") {
|
if (message.author.id === "172538370440953867") {
|
||||||
switch(message.content) {
|
switch(message.content) {
|
||||||
case "butthash":
|
case "butthash":
|
||||||
@ -106,75 +95,100 @@ client.on('message', async message => {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: this try block optional?
|
// Test if there is a file at the expected path
|
||||||
try {
|
if (message.member.voice.channel && existsSync(soundPath)) {
|
||||||
// Test if there is a file at the expected path
|
console.log(`Sound '${message.content}' issued by ${message.author.tag} ${message.author.id}`);
|
||||||
if (message.member.voice.channel && fs.existsSync(soundPath)) {
|
// Join the Voice Channel of the author
|
||||||
console.log(`Sound '${message.content}' issued by ${message.author.tag} ${message.author.id}`);
|
const connection = Voice.joinVoiceChannel({
|
||||||
// Join the Voice Channel of the author
|
channelId: message.member.voice.channelId,
|
||||||
const connection = await message.member.voice.channel.join();
|
guildId: message.guild.id,
|
||||||
// TODO: Switch to fs-based file read?
|
adapterCreator: message.guild.voiceAdapterCreator,
|
||||||
// Play the sound file as requested
|
});
|
||||||
const dispatcher = connection.play(soundPath, { volume: volume });
|
// Create an audio player for the desired sound
|
||||||
dispatcher.on('start', () => { console.log(`Playing ${soundPath}`); });
|
const resource = Voice.createAudioResource(createReadStream(soundPath));
|
||||||
dispatcher.on('finish', () => { console.log(`Finished ${soundPath}`); });
|
const player = Voice.createAudioPlayer();
|
||||||
dispatcher.on('error', console.error);
|
// Play the resource through the player to the connection (i hate discord v16)
|
||||||
return;
|
player.on('Playing', () => {
|
||||||
}
|
console.log(`Playing ${soundpath}`);
|
||||||
// else no sound file, fall through past catch block
|
});
|
||||||
} catch(err) {
|
player.play(resource);
|
||||||
console.error(err);
|
connection.subscribe(player);
|
||||||
|
// Setup Callbacks for when the player completes
|
||||||
|
player.on('Idle', () => {
|
||||||
|
console.log(`Finished ${soundpath}`);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise process commands
|
// Otherwise process commands
|
||||||
if (message.content === "!help" ) {
|
if (message.content === "!help" ) {
|
||||||
console.log(`!help issued by ${message.author.tag} ${message.author.id}`);
|
console.log(`!help issued by ${message.author.tag} ${message.author.id}`);
|
||||||
var response = 'ZeSkypeBot v6.0.6 \'black pepper\'\n';
|
var response = 'ZeSkypeBot v7.1.0 \'Table Salt\'\n';
|
||||||
response += 'Original by moosecrap#5953 for Skype, Remade by Weegee#6402 for Discord\n';
|
response += 'Original by moosecrap#5953 for Skype, Remade by Weegee#6402 for Discord\n';
|
||||||
response += 'Changelog:\n';
|
response += 'Changelog:\n';
|
||||||
response += 'v6.0.6 Changes to !play regex in pursuit of playing at timestamps\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.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.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.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.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 += 'v6.0.0 Public release, plays sounds from Goldar Squad\'s collection of micspam audio files. No list will be provided\n';
|
||||||
//response += 'v6.0.0 Changed version numbers to match moosecrap\'s, removed sound file extension requirement\n';
|
|
||||||
//response += 'v0.2.0 Added !help command and printout\n';
|
|
||||||
//response += 'v0.1.0 Initial Release - Can play sounds from file\n';
|
|
||||||
response += 'Commands:\n';
|
response += 'Commands:\n';
|
||||||
response += '~ stop any sounds in progress and disconnect from voice\n';
|
response += '~ stop any sounds in progress and disconnect from voice\n';
|
||||||
response += '!help print this message\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 += '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 [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);
|
message.channel.send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check for youtube play command
|
// Check for youtube play command
|
||||||
const ytmatch = message.content.match(/(?<=!play (https?:\/\/)(www\.)?youtu((be\.com\/watch\?v=)|(\.be\/)))[\w-]{11}/);
|
if (message.content.startsWith('!play') && message.member.voice.channel) {
|
||||||
if (ytmatch && message.member.voice.channel) {
|
// Determine if we have a URL or a search term
|
||||||
const timematch = message.content.match(/(?<=t=)(\d{1,2}h)?(\d{1,2}m)?\d{1,4}s?(?=$)/);
|
const ytmatch = message.content.match(/(?<=(https?:\/\/)(www\.)?youtu((be\.com\/watch\?v=)|(\.be\/)))[\w-]{11}/);
|
||||||
var timestamp = '0';
|
var yturl = null;
|
||||||
if (timematch) {
|
var timestamp = '0'
|
||||||
timestamp = timematch[0];
|
if (ytmatch) {
|
||||||
}
|
// Message matches the youtube video regex, see if it comes with a timestamp
|
||||||
console.log(`!play issued for ${ytmatch[0]} by ${message.author.tag} ${message.author.id}`);
|
const timematch = message.content.match(/(?<=t=)(\d{1,4})s?(?=$)/);
|
||||||
// Reconstruct a youtu.be url for the supplied video
|
if (timematch) {
|
||||||
const yturl = `https://youtu.be/${ytmatch[0]}`;
|
timestamp = timematch[1];
|
||||||
//TODO: Factor out common code with the soundbyte play?
|
}
|
||||||
const connection = await message.member.voice.channel.join();
|
// Reconstruct a URL for the supplied video
|
||||||
// Play the video as requested
|
yturl = `https://youtu.be/${ytmatch[0]}`;
|
||||||
try {
|
} else {
|
||||||
//TODO: process the timestamp with ffmpeg or whatever
|
// Message may be a search term
|
||||||
const dispatcher = connection.play(await ytdl(yturl, { begin: timestamp }), { type: 'opus', volume: volume});
|
let args = message.content.split('play')[1];
|
||||||
dispatcher.on('start', () => { console.log(`Playing ${yturl}`); });
|
// Search youtube with the term
|
||||||
dispatcher.on('finish', () => { console.log(`Finished ${yturl}`); });
|
let yt_info = await play.search(args, { limit: 1 });
|
||||||
dispatcher.on('error', console.error);
|
// and get the first result as a URL
|
||||||
} catch (error) {
|
yturl = yt_info[0].url;
|
||||||
console.error(error);
|
|
||||||
message.channel.send("Bro youtube says this shit is porn, i aint playing that");
|
|
||||||
const dispatcher = connection.play('./sounds/cantlet.ogg');
|
|
||||||
}
|
}
|
||||||
|
// 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.on('Playing', () => {
|
||||||
|
console.log(`Playing ${yturl}`);
|
||||||
|
});
|
||||||
|
player.play(resource);
|
||||||
|
// Connect the player to the voice connection (internal screaming intensifies)
|
||||||
|
connection.subscribe(player);
|
||||||
|
// Setup Callbacks for when the player completes
|
||||||
|
player.on('Idle', () => {
|
||||||
|
console.log(`Finished ${yturl}`);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,5 +202,5 @@ client.on('message', async message => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Now our client is prepared, we can log in. Callbacks defined previously
|
// Now our client is prepared, we can log in.
|
||||||
client.login(auth.token);
|
client.login(token);
|
||||||
|
|||||||
Binary file not shown.
2350
package-lock.json
generated
2350
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
27
package.json
27
package.json
@ -1,15 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "ZeSkypeBot",
|
"name": "zeskypebot",
|
||||||
"version": "6.0.0",
|
"version": "7.0.0_a",
|
||||||
"description": "Goldar Squad's Skype Bot, ported for Discord",
|
"description": "Goldar Squad's Skype Bot, ported for Discord\"",
|
||||||
"main": "bot.js",
|
"main": "bot.js",
|
||||||
"author": "Original by moosecrap#5953, ported by Weegee#6402",
|
"scripts": {
|
||||||
"dependencies": {
|
"preinstall": "npm install discord.js @discordjs/voice sodium @discordjs/opus ffmpeg-static play-dl",
|
||||||
"console-stamp": "^3.0.3",
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
"discord.js": "^12.5.3",
|
},
|
||||||
"node-gyp": "^8.3.0",
|
"repository": {
|
||||||
"node-opus": "^0.3.3",
|
"type": "git",
|
||||||
"opusscript": "0.0.8",
|
"url": "https://long-cat.net/gitea/Rob/ZeSkypeBot.git"
|
||||||
"ytdl-core-discord": "^1.3.1"
|
},
|
||||||
}
|
"author": "Original by moosecrap#5953, ported by Weegee#6402",
|
||||||
|
"license": "ISC"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user