diff --git a/.env.example b/.env.example index db567735..61ad2138 100644 --- a/.env.example +++ b/.env.example @@ -34,7 +34,6 @@ ANILIST_USERNAME= BITLY_KEY= CLEVERBOT_KEY= GITHUB_ACCESS_TOKEN= -GOOGLE_KEY= GOV_KEY= IDIOT_URL= REMOVEBG_KEY= diff --git a/README.md b/README.md index 7e08915d..85b72c3b 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,6 @@ Only if you want to use the DECTalk command. * `BITLY_KEY` is your API key for Bit.ly. You can get one [here](https://dev.bitly.com/docs/getting-started/authentication/). * `CLEVERBOT_KEY` is your API key for Cleverbot. You can get one [here](https://www.cleverbot.com/api/). * `GITHUB_ACCESS_TOKEN` is your access token for GitHub. [Follow these steps](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) to make one. -* `GOOGLE_KEY` is your API key for Google, used for the YouTube Data API. You can get one [here](https://console.cloud.google.com/apis/dashboard). You must also [activate the YouTube Data API](https://console.cloud.google.com/marketplace/product/google/youtube.googleapis.com?q=search). * `GOV_KEY` is your API key for NASA. You get get one [here](https://api.nasa.gov/). * `IDIOT_URL` is a URL, ideally to the [Wikipedia page of an idiot](https://en.wikipedia.org/wiki/Donald_Trump). By default, it will reply with "_Stares at you._" * `REMOVEBG_KEY` is your API key for remove.bg. You can get one [here](https://www.remove.bg/api). @@ -114,7 +113,7 @@ Only if you want to use the DECTalk command. 18. Start Xiao up! ## Commands -Total: 518 +Total: 515 ### Utility: @@ -127,8 +126,10 @@ Total: 518 * **help:** Displays a list of available commands, or detailed information for a specific command. * **high-scores:** Responds with the high scores the bot has saved. * **info:** Responds with detailed bot information. +* **join:** Joins your voice channel. * **last-run:** Responds with a command's most recent run date. * **last-run-leaderboard:** Responds with the bot's most recently run commands. +* **leave:** Leaves the current voice channel. * **options:** Responds with a list of server options. * **ping:** Checks the bot's ping to the Discord server. * **report:** Reports something to the bot owner(s). @@ -138,14 +139,6 @@ Total: 518 * **unknown-command:** Displays help information for when an unknown command is used. * **uses:** Responds with a command's usage stats. -### Utility (Voice): - -* **join:** Joins your voice channel. -* **leave:** Leaves the current voice channel. -* **pause:** Pauses the current audio playing. -* **resume:** Resume the current audio playing. -* **stop:** Stops the current audio playing. - ### Discord Information: * **avatar:** Responds with a user's avatar. @@ -665,7 +658,6 @@ Total: 518 * **dec-talk:** The world's best Text-to-Speech. * **mindfulness:** Immerse yourself in some mindful quotes. * **morse:** Converts text to morse code. -* **play:** Plays a YouTube video in your voice channel. * **tts:** Say the text you provide in the accent you choose. ### Reminders: @@ -695,7 +687,6 @@ Total: 518 ### NPM Packages * [@discordjs/opus](https://www.npmjs.com/package/@discordjs/opus) * [@discordjs/voice](https://www.npmjs.com/package/@discordjs/voice) -* [@distube/ytdl-core](https://www.npmjs.com/package/@distube/ytdl-core) * [@mediapipe/face_detection](https://www.npmjs.com/package/@mediapipe/face_detection) * [@napi-rs/canvas](https://www.npmjs.com/package/@napi-rs/canvas) * [@skyra/gifenc](https://www.npmjs.com/package/@skyra/gifenc) @@ -1451,8 +1442,6 @@ Total: 518 - [Digital Equipment Corporation](http://gordonbell.azurewebsites.net/digital/timeline/tmlnhome.htm) (Original DECTalk Software) * **mindfulness:** - [InspiroBot](https://inspirobot.me/) (API) -* **play:** - - [Google](https://www.google.com/) ([YouTube Data API](https://developers.google.com/youtube/v3/)) * **tts:** - [Google](https://www.google.com/) (Translate TTS API) * **cleverbot:** diff --git a/Xiao.js b/Xiao.js index 0e5baad7..2f5206e5 100644 --- a/Xiao.js +++ b/Xiao.js @@ -44,7 +44,6 @@ client.registry .registerGroups([ ['util', 'Utility (Owner)'], ['util-public', 'Utility'], - ['util-voice', 'Utility (Voice)'], ['info', 'Discord Information'], ['random-res', 'Random Response'], ['random-img', 'Random Image'], diff --git a/assets/json/logos.json b/assets/json/logos.json index 31579e53..98853034 100644 --- a/assets/json/logos.json +++ b/assets/json/logos.json @@ -8,7 +8,6 @@ "urban": "https://i.imgur.com/Fo0nRTe.png", "wikipedia": "https://i.imgur.com/Z7NJBK2.png", "yugioh": "https://i.imgur.com/AJNBflD.png", - "youtube": "https://i.imgur.com/kKHJg9Q.png", "scryfall": "https://i.imgur.com/DyuauFS.png", "lorcana": "https://i.imgur.com/rqatpU3.png" } diff --git a/commands/util-voice/join.js b/commands/util-public/join.js similarity index 98% rename from commands/util-voice/join.js rename to commands/util-public/join.js index c9281b0a..294815ef 100644 --- a/commands/util-voice/join.js +++ b/commands/util-public/join.js @@ -9,7 +9,7 @@ module.exports = class JoinCommand extends Command { super(client, { name: 'join', aliases: ['join-voice-channel', 'join-vc', 'join-voice', 'join-channel', 'connect'], - group: 'util-voice', + group: 'util', description: 'Joins your voice channel.', guildOnly: true, guarded: true, diff --git a/commands/util-voice/leave.js b/commands/util-public/leave.js similarity index 97% rename from commands/util-voice/leave.js rename to commands/util-public/leave.js index c8eff718..459fdbe8 100644 --- a/commands/util-voice/leave.js +++ b/commands/util-public/leave.js @@ -6,7 +6,7 @@ module.exports = class LeaveCommand extends Command { super(client, { name: 'leave', aliases: ['leave-voice-channel', 'leave-vc', 'leave-voice', 'leave-channel', 'disconnect'], - group: 'util-voice', + group: 'util', description: 'Leaves the current voice channel.', guildOnly: true, guarded: true diff --git a/commands/util-voice/pause.js b/commands/util-voice/pause.js deleted file mode 100644 index f3e75a7a..00000000 --- a/commands/util-voice/pause.js +++ /dev/null @@ -1,28 +0,0 @@ -const Command = require('../../framework/Command'); -const { PermissionFlagsBits } = require('discord.js'); - -module.exports = class PauseCommand extends Command { - constructor(client) { - super(client, { - name: 'pause', - aliases: ['pause-voice-channel', 'pause-vc', 'pause-voice', 'pause-music', 'pause-playing'], - group: 'util-voice', - description: 'Pauses the current audio playing.', - guildOnly: true, - guarded: true - }); - } - - run(msg) { - const connection = this.client.dispatchers.get(msg.guild.id); - if (!connection) return msg.reply('I am not in a voice channel.'); - if (connection.canPlay) { - return msg.reply('I am not currently playing audio in this server.'); - } - if (!connection.channel.permissionsFor(msg.author).has(PermissionFlagsBits.MoveMembers)) { - return msg.reply(`You need the "MOVE_MEMBERS" permission to use the \`${this.name}\` command.`); - } - connection.pause(); - return msg.reply('Paused playing.'); - } -}; diff --git a/commands/util-voice/resume.js b/commands/util-voice/resume.js deleted file mode 100644 index 8767333c..00000000 --- a/commands/util-voice/resume.js +++ /dev/null @@ -1,28 +0,0 @@ -const Command = require('../../framework/Command'); -const { PermissionFlagsBits } = require('discord.js'); - -module.exports = class ResumeCommand extends Command { - constructor(client) { - super(client, { - name: 'resume', - aliases: ['resume-voice-channel', 'resume-vc', 'resume-voice', 'resume-music', 'resume-playing'], - group: 'util-voice', - description: 'Resume the current audio playing.', - guildOnly: true, - guarded: true - }); - } - - run(msg) { - const connection = this.client.dispatchers.get(msg.guild.id); - if (!connection) return msg.reply('I am not in a voice channel.'); - if (connection.canPlay) { - return msg.reply('I am not currently playing audio in this server.'); - } - if (!connection.channel.permissionsFor(msg.author).has(PermissionFlagsBits.MoveMembers)) { - return msg.reply(`You need the "MOVE_MEMBERS" permission to use the \`${this.name}\` command.`); - } - connection.unpause(); - return msg.reply('Resumed playing.'); - } -}; diff --git a/commands/util-voice/stop.js b/commands/util-voice/stop.js deleted file mode 100644 index 706c3180..00000000 --- a/commands/util-voice/stop.js +++ /dev/null @@ -1,28 +0,0 @@ -const Command = require('../../framework/Command'); -const { PermissionFlagsBits } = require('discord.js'); - -module.exports = class StopCommand extends Command { - constructor(client) { - super(client, { - name: 'stop', - aliases: ['stop-voice-channel', 'stop-vc', 'stop-voice', 'stop-music', 'stop-playing'], - group: 'util-voice', - description: 'Stops the current audio playing.', - guildOnly: true, - guarded: true - }); - } - - run(msg) { - const connection = this.client.dispatchers.get(msg.guild.id); - if (!connection) return msg.reply('I am not in a voice channel.'); - if (connection.canPlay) { - return msg.reply('I am not currently playing audio in this server.'); - } - if (!connection.channel.permissionsFor(msg.author).has(PermissionFlagsBits.MoveMembers)) { - return msg.reply(`You need the "MOVE_MEMBERS" permission to use the \`${this.name}\` command.`); - } - connection.stop(); - return msg.reply('Stopped playing.'); - } -}; diff --git a/commands/voice/play.js b/commands/voice/play.js deleted file mode 100644 index 418efd0c..00000000 --- a/commands/voice/play.js +++ /dev/null @@ -1,98 +0,0 @@ -const Command = require('../../framework/Command'); -const { EmbedBuilder, PermissionFlagsBits } = require('discord.js'); -const request = require('node-superfetch'); -const ytdl = require('@distube/ytdl-core'); -const { shorten, verify } = require('../../util/Util'); -const logos = require('../../assets/json/logos'); -const { GOOGLE_KEY } = process.env; - -module.exports = class PlayCommand extends Command { - constructor(client) { - super(client, { - name: 'play', - aliases: ['play-music', 'music'], - group: 'voice', - description: 'Plays a YouTube video in your voice channel.', - guildOnly: true, - throttling: { - usages: 2, - duration: 60 - }, - userPermissions: [PermissionFlagsBits.Connect, PermissionFlagsBits.Speak], - credit: [ - { - name: 'Google', - url: 'https://www.google.com/', - reason: 'YouTube Data API', - reasonURL: 'https://developers.google.com/youtube/v3/' - } - ], - args: [ - { - key: 'query', - type: 'string' - } - ] - }); - } - - async run(msg, { query }) { - const connection = this.client.dispatchers.get(msg.guild.id); - if (!connection) { - const usage = this.client.registry.commands.get('join').usage(); - return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`); - } - if (!connection.canPlay) return msg.reply('I am already playing audio in this server.'); - const result = await this.searchForVideo(query, msg.channel.nsfw || false); - if (!result) return msg.reply('Could not find any results for your query.'); - const data = await ytdl.getInfo(result); - const canPlay = this.canUseVideo(data, msg.channel.nsfw || false); - if (!canPlay) return msg.reply('I cannot play this video.'); - if (canPlay === 'length') return msg.reply('This video is longer than 15 minutes, so I can\'t play it.'); - await msg.reply('Is this the video you want to play? Reply with **[y]es** or **[n]o**.', { - embeds: [this.generateEmbed(data)] - }); - const verification = await verify(msg.channel, msg.author); - if (!verification) return msg.reply('Aborting playback.'); - connection.play(ytdl(result, { filter: 'audioonly' })); - return msg.reply(`🔉 Now playing **${shorten(data.videoDetails.title, 70)}**!`); - } - - async searchForVideo(query, nsfw) { - if (ytdl.validateURL(query)) return ytdl.getURLVideoID(query); - if (ytdl.validateID(query)) return query; - if (!GOOGLE_KEY) return null; - const { body } = await request - .get('https://www.googleapis.com/youtube/v3/search') - .query({ - part: 'snippet', - type: 'video', - maxResults: 1, - q: query, - safeSearch: nsfw ? 'none' : 'strict', - key: GOOGLE_KEY - }); - if (!body.items.length) return null; - const data = body.items[0]; - return data.id.videoId; - } - - canUseVideo(data, nsfw) { - if (data.videoDetails.isPrivate || data.videoDetails.isLiveContent) return false; - if (data.videoDetails.age_restricted && nsfw) return false; - if (Number.parseInt(data.videoDetails.lengthSeconds, 10) > 900) return 'length'; - return true; - } - - generateEmbed(data) { - return new EmbedBuilder() - .setColor(0xDD2825) - .setTitle(shorten(data.videoDetails.title, 70)) - .setDescription(shorten(data.videoDetails.description, 100)) - .setAuthor({ name: 'YouTube', iconURL: logos.youtube, url: 'https://www.youtube.com/' }) - .setURL(data.videoDetails.video_url) - .setThumbnail(data.videoDetails.thumbnails.length ? data.videoDetails.thumbnails[0].url : null) - .addField('❯ ID', data.videoDetails.videoId, true) - .addField('❯ Publish Date', data.videoDetails.publishDate, true); - } -}; diff --git a/package.json b/package.json index aa3a01ac..de30d8c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xiao", - "version": "158.0.1", + "version": "159.0.0", "description": "Your personal server companion.", "main": "Xiao.js", "scripts": { @@ -31,7 +31,6 @@ "dependencies": { "@discordjs/opus": "^0.10.0", "@discordjs/voice": "^0.19.0", - "@distube/ytdl-core": "^4.16.12", "@dotenvx/dotenvx": "^1.49.0", "@mediapipe/face_detection": "^0.4.1646425229", "@napi-rs/canvas": "^0.1.80",