diff --git a/docs/MusicStructure.md b/docs/MusicStructure.md new file mode 100644 index 0000000..ed8b9de --- /dev/null +++ b/docs/MusicStructure.md @@ -0,0 +1,130 @@ +# The commands + +```lang-none +- "mhelp" - Display a help embed. +- "play" - Adds a song to the queue and plays it. +- "skip" - Skips the currently playing track. +- "queue" - Shows the current queue. +- "stop" - Stops currently playing media and leaves the voice channel. +- "np" - Displays the currently playing track. +- "pause" - Pauses the currently playing track. +- "resume" - Resumes the currently paused track. +- "volume" - Changes the global volume of the bot. +- "loop" - Loops the current queue. +- "seek" - Seeks through the queue. +``` + +--- + +Now that the actual info about the functionality of this thing is out of the way, its storytime! + +## The music structure + +Originally, I, keanucode, aimed to port the music structure of TravBot-v2 to this version. + +This would have been much too difficult of a task for three main reasons: + +1. The original code is written badly. +2. The original code is written by *another person*. +3. The original code is written in JS. + +These three reasons make porting the structure *considerably* harder. + +So, of course, I resorted to different matters. I present: [discord.js-lavalink-musicbot](https://github.com/BluSpring/discord.js-lavalink-musicbot). ([npmjs.org](https://www.npmjs.com/package/discord.js-lavalink-musicbot)) + +This *pre-built* module utilises [Lavalink](https://github.com/Frederikam/Lavalink), which is an audio sending node based on [Lavaplayer](https://github.com/sedmelluq/lavaplayer) and [JDA-Audio](https://github.com/DV8FromTheWorld/JDA-Audio). + +I've previously considered using Lavalink, but it turned out to be more difficult for me to implement than I thought. + +So, I tried again with `discord.js-lavalink-musicbot`. + +*ahem*... + +**The library was written in such a way that it didn't work!** + +--- + +## Fixing the broken library + +First off; in the library's interface `LavaLinkNodeOptions`, option `id` was a *required* option: + +```ts +interface LavalinkNodeOptions { + host: string; + id: string; + /* ... */ +} +``` + +Here's the catch. `id` was referenced *nowhere* in the library code. +It was *literally* useless. + +So, I lazily removed that by adding a `?` to the parameter. (`id?:`) + +Next up: + +```ts +declare function LavalinkMusic(client: Client, options: MusicbotOptions) {} +``` + +First up, the TS compiler reports that: `An implementation cannot be declared in ambient contexts. ts(1183)` + +Secondly, this function, which makes up the entirety of the library, explicitly returns an `any` type. As you can see, the *declared* function returns... no specific type. + +So, that had to be changed to: + +```diff +- declare function LavalinkMusic(client: Client, options: MusicbotOptions) {} ++ declare function LavalinkMusic(client: Client, options: MusicbotOptions): any +``` + +...next up: + +```ts +try { +const res = await axios.get( + /* ... */ + `https://${music.lavalink.restnode.host}:` + /* ... */ +) +``` + +The library tries to fetch the URL of the Lavalink node. With *HTTPS*. + +I think you can see where this is going. An SSL error. + +Changed the `https` to `http`, and all is well. + +I republished the library under the name "[discord.js-lavalink-lib](https://npmjs.org/package/discord.js-lavalink-lib)" so I can easily install the non-broken version. + +--- + +## Implementing the functionality + +There's nothing much to do there, honestly. Only one edit to the original snippet has to be made. + +The original example snippet has the following: + +```ts +const Discord = require('discord.js'); +const client = new Discord.Client(); +client.music = new (require('discord.js-lavalink-musicbot'))(client, { + /* ...config... */ +}); +``` + +As you can see, this is... kind of disgusting. And on top of that, incompatible with TS. + +So, we have to change a few things. First off, since TS is strict, it'll tell you that `music` doesn't exist on `client`. Which is true. The `Client` class has no `music` property. + +So, we make `client.` an `any` type using keyword `as`: + +```ts +const Discord = require('discord.js'); +const client = new Discord.Client(); +(client as any).music = LavalinkMusic(client, { + /* ...config... */ +}); +``` + +And that's about it. Launch up Lavalink, and start the bot. diff --git a/package-lock.json b/package-lock.json index c41153c..ca34de3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,25 @@ "mime-types": "^2.1.12" } }, + "@lavacord/discord.js": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@lavacord/discord.js/-/discord.js-0.0.5.tgz", + "integrity": "sha512-qc2lw0zB48fq4SrSlpMJOmogUXIeM5YvufQfPg0ubjp7jqm20JnOXF9fliy1MPdcKPnZ8LwIZ222H0+ghGzP/Q==", + "requires": { + "lavacord": "^1.1.9" + }, + "dependencies": { + "lavacord": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/lavacord/-/lavacord-1.1.9.tgz", + "integrity": "sha512-haZghbblO1w3Hodc9q63ZWgV5zA/jB6xFKS17fImK5aIdn0PkKuZ6AsJBxMFpR275v8GNYOxg6cTQBYBQ+batQ==", + "requires": { + "node-fetch": "^2.6.0", + "ws": "^7.3.0" + } + } + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -142,6 +161,14 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -373,6 +400,17 @@ "ws": "^7.3.1" } }, + "discord.js-lavalink-lib": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/discord.js-lavalink-lib/-/discord.js-lavalink-lib-0.1.5.tgz", + "integrity": "sha512-cgQR1JgNav2BiFkuPBV03fNCETm+t70fXaImSiEL0hqookgTdGb+ZxfbRvzmtvGvch6MqfH2AaAYDVvLo5PR4Q==", + "requires": { + "@lavacord/discord.js": "0.0.5", + "axios": "^0.19.2", + "discord.js": "^12.2.0", + "lavacord": "^1.1.7" + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -512,6 +550,29 @@ "is-buffer": "~2.0.3" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -781,6 +842,15 @@ "esprima": "^4.0.0" } }, + "lavacord": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/lavacord/-/lavacord-1.1.9.tgz", + "integrity": "sha512-haZghbblO1w3Hodc9q63ZWgV5zA/jB6xFKS17fImK5aIdn0PkKuZ6AsJBxMFpR275v8GNYOxg6cTQBYBQ+batQ==", + "requires": { + "node-fetch": "^2.6.0", + "ws": "^7.3.0" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", diff --git a/package.json b/package.json index 34c3697..cd76328 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dependencies": { "chalk": "^4.1.0", "discord.js": "^12.4.0", + "discord.js-lavalink-lib": "^0.1.5", "inquirer": "^7.3.1", "moment": "^2.27.0" }, diff --git a/src/index.ts b/src/index.ts index 4ce813a..207bb4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,11 +3,33 @@ import setup from './setup'; import { Config } from './core/structures'; import { loadCommands } from './core/command'; import { loadEvents } from './core/event'; +import 'discord.js-lavalink-lib'; +import LavalinkMusic from 'discord.js-lavalink-lib'; // This is here in order to make it much less of a headache to access the client from other files. // This of course won't actually do anything until the setup process is complete and it logs in. export const client = new Client(); +(client as any).music = LavalinkMusic(client, { + lavalink: { + restnode: { + host: 'localhost', + port: 2333, + password: 'youshallnotpass', + }, + nodes: [ + { + host: 'localhost', + port: 2333, + password: 'youshallnotpass', + }, + ], + }, + prefix: '!!', + helpCmd: 'mhelp', + admins: ['717352467280691331'], +}); + // Begin the command loading here rather than when it's needed like in the message event. setup.init().then(() => { loadCommands();