mirror of
				https://github.com/keanuplayz/TravBot-v3.git
				synced 2024-08-15 02:33:12 +00:00 
			
		
		
		
	Reorganized lib/libd functions and Lavalink
This commit is contained in:
		
							parent
							
								
									86ccb74ac2
								
							
						
					
					
						commit
						3ef487c4a4
					
				
					 10 changed files with 230 additions and 223 deletions
				
			
		|  | @ -1,9 +1,9 @@ | |||
| import Command, {handler} from "../core/command"; | ||||
| import {botHasPermission, clean} from "../core/libd"; | ||||
| import {clean} from "../core/lib"; | ||||
| import {botHasPermission} from "../core/libd"; | ||||
| import {Config, Storage} from "../core/structures"; | ||||
| import {getPermissionLevel, getPermissionName} from "../core/permissions"; | ||||
| import {Permissions} from "discord.js"; | ||||
| import * as discord from "discord.js"; | ||||
| import {logs} from "../globals"; | ||||
| 
 | ||||
| function getLogBuffer(type: string) { | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import {User} from "discord.js"; | ||||
| import Command from "../../core/command"; | ||||
| import {random} from "../../core/lib"; | ||||
| import {parseVars} from "../../core/libd"; | ||||
| import {parseVars} from "../../core/lib"; | ||||
| 
 | ||||
| const cookies = [ | ||||
|     `has given %target% a chocolate chip cookie!`, | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import {URL} from "url"; | ||||
| import Command from "../../core/command"; | ||||
| import {getContent} from "../../core/libd"; | ||||
| import {getContent} from "../../core/lib"; | ||||
| 
 | ||||
| const endpoints: {sfw: {[key: string]: string}} = { | ||||
|     sfw: { | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ import {MessageEmbed, version as djsversion} from "discord.js"; | |||
| import ms from "ms"; | ||||
| import os from "os"; | ||||
| import Command from "../core/command"; | ||||
| import {formatBytes, trimArray, getMemberByUsername} from "../core/libd"; | ||||
| import {formatBytes, trimArray} from "../core/lib"; | ||||
| import {getMemberByUsername} from "../core/libd"; | ||||
| import {verificationLevels, filterLevels, regions} from "../defs/info"; | ||||
| import moment from "moment"; | ||||
| import utc from "moment"; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {parseVars} from "./libd"; | ||||
| import {parseVars} from "./lib"; | ||||
| import {Collection} from "discord.js"; | ||||
| import {Client, Message, TextChannel, DMChannel, NewsChannel, Guild, User, GuildMember} from "discord.js"; | ||||
| import {getPrefix} from "../core/structures"; | ||||
|  |  | |||
							
								
								
									
										165
									
								
								src/core/lib.ts
									
										
									
									
									
								
							
							
						
						
									
										165
									
								
								src/core/lib.ts
									
										
									
									
									
								
							|  | @ -1,4 +1,169 @@ | |||
| // Library for pure functions
 | ||||
| import {get} from "https"; | ||||
| import FileManager from "./storage"; | ||||
| 
 | ||||
| /** | ||||
|  * Splits a command by spaces while accounting for quotes which capture string arguments. | ||||
|  * - `\"` = `"` | ||||
|  * - `\\` = `\` | ||||
|  */ | ||||
| export function parseArgs(line: string): string[] { | ||||
|     let result = []; | ||||
|     let selection = ""; | ||||
|     let inString = false; | ||||
|     let isEscaped = false; | ||||
| 
 | ||||
|     for (let c of line) { | ||||
|         if (isEscaped) { | ||||
|             if (['"', "\\"].includes(c)) selection += c; | ||||
|             else selection += "\\" + c; | ||||
| 
 | ||||
|             isEscaped = false; | ||||
|         } else if (c === "\\") isEscaped = true; | ||||
|         else if (c === '"') inString = !inString; | ||||
|         else if (c === " " && !inString) { | ||||
|             result.push(selection); | ||||
|             selection = ""; | ||||
|         } else selection += c; | ||||
|     } | ||||
| 
 | ||||
|     if (selection.length > 0) result.push(selection); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Allows you to store a template string with variable markers and parse it later. | ||||
|  * - Use `%name%` for variables | ||||
|  * - `%%` = `%` | ||||
|  * - If the invalid token is null/undefined, nothing is changed. | ||||
|  */ | ||||
| export function parseVars(line: string, definitions: {[key: string]: string}, invalid: string | null = ""): string { | ||||
|     let result = ""; | ||||
|     let inVariable = false; | ||||
|     let token = ""; | ||||
| 
 | ||||
|     for (const c of line) { | ||||
|         if (c === "%") { | ||||
|             if (inVariable) { | ||||
|                 if (token === "") result += "%"; | ||||
|                 else { | ||||
|                     if (token in definitions) result += definitions[token]; | ||||
|                     else if (invalid === null) result += `%${token}%`; | ||||
|                     else result += invalid; | ||||
| 
 | ||||
|                     token = ""; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             inVariable = !inVariable; | ||||
|         } else if (inVariable) token += c; | ||||
|         else result += c; | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| export function isType(value: any, type: any): boolean { | ||||
|     if (value === undefined && type === undefined) return true; | ||||
|     else if (value === null && type === null) return true; | ||||
|     else return value !== undefined && value !== null && value.constructor === type; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Checks a value to see if it matches the fallback's type, otherwise returns the fallback. | ||||
|  * For the purposes of the templates system, this function will only check array types, objects should be checked under their own type (as you'd do anyway with something like a User object). | ||||
|  * If at any point the value doesn't match the data structure provided, the fallback is returned. | ||||
|  * Warning: Type checking is based on the fallback's type. Be sure that the "type" parameter is accurate to this! | ||||
|  */ | ||||
| export function select<T>(value: any, fallback: T, type: Function, isArray = false): T { | ||||
|     if (isArray && isType(value, Array)) { | ||||
|         for (let item of value) if (!isType(item, type)) return fallback; | ||||
|         return value; | ||||
|     } else { | ||||
|         if (isType(value, type)) return value; | ||||
|         else return fallback; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export function clean(text: any) { | ||||
|     if (typeof text === "string") | ||||
|         return text.replace(/`/g, "`" + String.fromCharCode(8203)).replace(/@/g, "@" + String.fromCharCode(8203)); | ||||
|     else return text; | ||||
| } | ||||
| 
 | ||||
| export function trimArray(arr: any, maxLen = 10) { | ||||
|     if (arr.length > maxLen) { | ||||
|         const len = arr.length - maxLen; | ||||
|         arr = arr.slice(0, maxLen); | ||||
|         arr.push(`${len} more...`); | ||||
|     } | ||||
|     return arr; | ||||
| } | ||||
| 
 | ||||
| export function formatBytes(bytes: any) { | ||||
|     if (bytes === 0) return "0 Bytes"; | ||||
|     const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; | ||||
|     const i = Math.floor(Math.log(bytes) / Math.log(1024)); | ||||
|     return `${parseFloat((bytes / Math.pow(1024, i)).toFixed(2))} ${sizes[i]}`; | ||||
| } | ||||
| 
 | ||||
| export function getContent(url: string): Promise<{url: string}> { | ||||
|     return new Promise((resolve, reject) => { | ||||
|         get(url, (res) => { | ||||
|             const {statusCode} = res; | ||||
|             if (statusCode !== 200) { | ||||
|                 res.resume(); | ||||
|                 reject(`Request failed. Status code: ${statusCode}`); | ||||
|             } | ||||
|             res.setEncoding("utf8"); | ||||
|             let rawData = ""; | ||||
|             res.on("data", (chunk: string) => { | ||||
|                 rawData += chunk; | ||||
|             }); | ||||
|             res.on("end", () => { | ||||
|                 try { | ||||
|                     const parsedData = JSON.parse(rawData); | ||||
|                     resolve(parsedData); | ||||
|                 } catch (e) { | ||||
|                     reject(`Error: ${e.message}`); | ||||
|                 } | ||||
|             }); | ||||
|         }).on("error", (err: {message: any}) => { | ||||
|             reject(`Error: ${err.message}`); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export interface GenericJSON { | ||||
|     [key: string]: any; | ||||
| } | ||||
| 
 | ||||
| export abstract class GenericStructure { | ||||
|     private __meta__ = "generic"; | ||||
| 
 | ||||
|     constructor(tag?: string) { | ||||
|         this.__meta__ = tag || this.__meta__; | ||||
|     } | ||||
| 
 | ||||
|     public save(asynchronous = true) { | ||||
|         const tag = this.__meta__; | ||||
|         /// @ts-ignore
 | ||||
|         delete this.__meta__; | ||||
|         FileManager.write(tag, this, asynchronous); | ||||
|         this.__meta__ = tag; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // A 50% chance would be "Math.random() < 0.5" because Math.random() can be [0, 1), so to make two equal ranges, you'd need [0, 0.5)U[0.5, 1).
 | ||||
| // Similar logic would follow for any other percentage. Math.random() < 1 is always true (100% chance) and Math.random() < 0 is always false (0% chance).
 | ||||
| export const Random = { | ||||
|     num: (min: number, max: number) => Math.random() * (max - min) + min, | ||||
|     int: (min: number, max: number) => Math.floor(Random.num(min, max)), | ||||
|     chance: (decimal: number) => Math.random() < decimal, | ||||
|     sign: (number = 1) => number * (Random.chance(0.5) ? -1 : 1), | ||||
|     deviation: (base: number, deviation: number) => Random.num(base - deviation, base + deviation) | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Pluralises a word and chooses a suffix attached to the root provided. | ||||
|  |  | |||
							
								
								
									
										164
									
								
								src/core/libd.ts
									
										
									
									
									
								
							
							
						
						
									
										164
									
								
								src/core/libd.ts
									
										
									
									
									
								
							|  | @ -9,7 +9,6 @@ import { | |||
|     NewsChannel, | ||||
|     MessageOptions | ||||
| } from "discord.js"; | ||||
| import {get} from "https"; | ||||
| import FileManager from "./storage"; | ||||
| import {eventListeners} from "../events/messageReactionRemove"; | ||||
| import {client} from "../index"; | ||||
|  | @ -274,166 +273,3 @@ export async function callMemberByUsername( | |||
|         else send(`Couldn't find a user by the name of \`${username}\`!`); | ||||
|     } else send("You must execute this command in a server!"); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Splits a command by spaces while accounting for quotes which capture string arguments. | ||||
|  * - `\"` = `"` | ||||
|  * - `\\` = `\` | ||||
|  */ | ||||
| export function parseArgs(line: string): string[] { | ||||
|     let result = []; | ||||
|     let selection = ""; | ||||
|     let inString = false; | ||||
|     let isEscaped = false; | ||||
| 
 | ||||
|     for (let c of line) { | ||||
|         if (isEscaped) { | ||||
|             if (['"', "\\"].includes(c)) selection += c; | ||||
|             else selection += "\\" + c; | ||||
| 
 | ||||
|             isEscaped = false; | ||||
|         } else if (c === "\\") isEscaped = true; | ||||
|         else if (c === '"') inString = !inString; | ||||
|         else if (c === " " && !inString) { | ||||
|             result.push(selection); | ||||
|             selection = ""; | ||||
|         } else selection += c; | ||||
|     } | ||||
| 
 | ||||
|     if (selection.length > 0) result.push(selection); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Allows you to store a template string with variable markers and parse it later. | ||||
|  * - Use `%name%` for variables | ||||
|  * - `%%` = `%` | ||||
|  * - If the invalid token is null/undefined, nothing is changed. | ||||
|  */ | ||||
| export function parseVars(line: string, definitions: {[key: string]: string}, invalid: string | null = ""): string { | ||||
|     let result = ""; | ||||
|     let inVariable = false; | ||||
|     let token = ""; | ||||
| 
 | ||||
|     for (const c of line) { | ||||
|         if (c === "%") { | ||||
|             if (inVariable) { | ||||
|                 if (token === "") result += "%"; | ||||
|                 else { | ||||
|                     if (token in definitions) result += definitions[token]; | ||||
|                     else if (invalid === null) result += `%${token}%`; | ||||
|                     else result += invalid; | ||||
| 
 | ||||
|                     token = ""; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             inVariable = !inVariable; | ||||
|         } else if (inVariable) token += c; | ||||
|         else result += c; | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| export function isType(value: any, type: any): boolean { | ||||
|     if (value === undefined && type === undefined) return true; | ||||
|     else if (value === null && type === null) return true; | ||||
|     else return value !== undefined && value !== null && value.constructor === type; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Checks a value to see if it matches the fallback's type, otherwise returns the fallback. | ||||
|  * For the purposes of the templates system, this function will only check array types, objects should be checked under their own type (as you'd do anyway with something like a User object). | ||||
|  * If at any point the value doesn't match the data structure provided, the fallback is returned. | ||||
|  * Warning: Type checking is based on the fallback's type. Be sure that the "type" parameter is accurate to this! | ||||
|  */ | ||||
| export function select<T>(value: any, fallback: T, type: Function, isArray = false): T { | ||||
|     if (isArray && isType(value, Array)) { | ||||
|         for (let item of value) if (!isType(item, type)) return fallback; | ||||
|         return value; | ||||
|     } else { | ||||
|         if (isType(value, type)) return value; | ||||
|         else return fallback; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export function clean(text: any) { | ||||
|     if (typeof text === "string") | ||||
|         return text.replace(/`/g, "`" + String.fromCharCode(8203)).replace(/@/g, "@" + String.fromCharCode(8203)); | ||||
|     else return text; | ||||
| } | ||||
| 
 | ||||
| export function trimArray(arr: any, maxLen = 10) { | ||||
|     if (arr.length > maxLen) { | ||||
|         const len = arr.length - maxLen; | ||||
|         arr = arr.slice(0, maxLen); | ||||
|         arr.push(`${len} more...`); | ||||
|     } | ||||
|     return arr; | ||||
| } | ||||
| 
 | ||||
| export function formatBytes(bytes: any) { | ||||
|     if (bytes === 0) return "0 Bytes"; | ||||
|     const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; | ||||
|     const i = Math.floor(Math.log(bytes) / Math.log(1024)); | ||||
|     return `${parseFloat((bytes / Math.pow(1024, i)).toFixed(2))} ${sizes[i]}`; | ||||
| } | ||||
| 
 | ||||
| export function getContent(url: string): Promise<{url: string}> { | ||||
|     return new Promise((resolve, reject) => { | ||||
|         get(url, (res) => { | ||||
|             const {statusCode} = res; | ||||
|             if (statusCode !== 200) { | ||||
|                 res.resume(); | ||||
|                 reject(`Request failed. Status code: ${statusCode}`); | ||||
|             } | ||||
|             res.setEncoding("utf8"); | ||||
|             let rawData = ""; | ||||
|             res.on("data", (chunk: string) => { | ||||
|                 rawData += chunk; | ||||
|             }); | ||||
|             res.on("end", () => { | ||||
|                 try { | ||||
|                     const parsedData = JSON.parse(rawData); | ||||
|                     resolve(parsedData); | ||||
|                 } catch (e) { | ||||
|                     reject(`Error: ${e.message}`); | ||||
|                 } | ||||
|             }); | ||||
|         }).on("error", (err: {message: any}) => { | ||||
|             reject(`Error: ${err.message}`); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export interface GenericJSON { | ||||
|     [key: string]: any; | ||||
| } | ||||
| 
 | ||||
| export abstract class GenericStructure { | ||||
|     private __meta__ = "generic"; | ||||
| 
 | ||||
|     constructor(tag?: string) { | ||||
|         this.__meta__ = tag || this.__meta__; | ||||
|     } | ||||
| 
 | ||||
|     public save(asynchronous = true) { | ||||
|         const tag = this.__meta__; | ||||
|         /// @ts-ignore
 | ||||
|         delete this.__meta__; | ||||
|         FileManager.write(tag, this, asynchronous); | ||||
|         this.__meta__ = tag; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // A 50% chance would be "Math.random() < 0.5" because Math.random() can be [0, 1), so to make two equal ranges, you'd need [0, 0.5)U[0.5, 1).
 | ||||
| // Similar logic would follow for any other percentage. Math.random() < 1 is always true (100% chance) and Math.random() < 0 is always false (0% chance).
 | ||||
| export const Random = { | ||||
|     num: (min: number, max: number) => Math.random() * (max - min) + min, | ||||
|     int: (min: number, max: number) => Math.floor(Random.num(min, max)), | ||||
|     chance: (decimal: number) => Math.random() < decimal, | ||||
|     sign: (number = 1) => number * (Random.chance(0.5) ? -1 : 1), | ||||
|     deviation: (base: number, deviation: number) => Random.num(base - deviation, base + deviation) | ||||
| }; | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import FileManager from "./storage"; | ||||
| import {select, GenericJSON, GenericStructure} from "./libd"; | ||||
| import {select, GenericJSON, GenericStructure} from "./lib"; | ||||
| import {watch} from "fs"; | ||||
| import {Guild as DiscordGuild, Snowflake} from "discord.js"; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										56
									
								
								src/index.ts
									
										
									
									
									
								
							
							
						
						
									
										56
									
								
								src/index.ts
									
										
									
									
									
								
							|  | @ -1,62 +1,14 @@ | |||
| import "./globals"; | ||||
| import * as discord from "discord.js"; | ||||
| import {Client} from "discord.js"; | ||||
| import setup from "./setup"; | ||||
| import {Config} from "./core/structures"; | ||||
| import {loadEvents} from "./core/event"; | ||||
| import "discord.js-lavalink-lib"; | ||||
| import LavalinkMusic from "discord.js-lavalink-lib"; | ||||
| 
 | ||||
| declare module "discord.js" { | ||||
|     interface Presence { | ||||
|         patch(data: any): void; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // The terrible hacks were written by none other than The Noble Programmer On The White PC.
 | ||||
| 
 | ||||
| // NOTE: Terrible hack ahead!!! In order to reduce the memory usage of the bot
 | ||||
| // we only store the information from presences that we actually end up using,
 | ||||
| // which currently is only the (online/idle/dnd/offline/...) status (see
 | ||||
| // `src/commands/info.ts`). What data is retrieved from the `data` object
 | ||||
| // (which contains the data received from the Gateway) and how can be seen
 | ||||
| // here:
 | ||||
| // <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/structures/Presence.js#L81-L110>.
 | ||||
| const oldPresencePatch = discord.Presence.prototype.patch; | ||||
| discord.Presence.prototype.patch = function patch(data: any) { | ||||
|     oldPresencePatch.call(this, {status: data.status}); | ||||
| }; | ||||
| import {attachToClient} from "./modules/lavalink"; | ||||
| 
 | ||||
| // 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 discord.Client(); | ||||
| 
 | ||||
| // NOTE: Terrible hack continued!!! Unfortunately we can't receive the presence
 | ||||
| // data at all when the GUILD_PRESENCES intent is disabled, so while we do
 | ||||
| // waste network bandwidth and the CPU time for decoding the incoming packets,
 | ||||
| // the function which handles those packets is NOP-ed out, which, among other
 | ||||
| // things, skips the code which caches the referenced users in the packet. See
 | ||||
| // <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/client/actions/PresenceUpdate.js#L7-L41>.
 | ||||
| (client["actions"] as any)["PresenceUpdate"].handle = () => {}; | ||||
| 
 | ||||
| (client as any).music = LavalinkMusic(client, { | ||||
|     lavalink: { | ||||
|         restnode: { | ||||
|             host: "localhost", | ||||
|             port: 2333, | ||||
|             password: "youshallnotpass" | ||||
|         }, | ||||
|         nodes: [ | ||||
|             { | ||||
|                 host: "localhost", | ||||
|                 port: 2333, | ||||
|                 password: "youshallnotpass" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     prefix: Config.prefix, | ||||
|     helpCmd: "mhelp", | ||||
|     admins: ["717352467280691331"] | ||||
| }); | ||||
| export const client = new Client(); | ||||
| attachToClient(client); | ||||
| 
 | ||||
| // Command loading will start as soon as an instance of "core/command" is loaded, which is loaded during "events/message".
 | ||||
| setup.init().then(() => { | ||||
|  |  | |||
							
								
								
									
										53
									
								
								src/modules/lavalink.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/modules/lavalink.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| import {Presence, Client} from "discord.js"; | ||||
| import LavalinkMusic from "discord.js-lavalink-lib"; | ||||
| import {Config} from "../core/structures"; | ||||
| 
 | ||||
| declare module "discord.js" { | ||||
|     interface Presence { | ||||
|         patch(data: any): void; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // The terrible hacks were written by none other than The Noble Programmer On The White PC.
 | ||||
| 
 | ||||
| // NOTE: Terrible hack ahead!!! In order to reduce the memory usage of the bot
 | ||||
| // we only store the information from presences that we actually end up using,
 | ||||
| // which currently is only the (online/idle/dnd/offline/...) status (see
 | ||||
| // `src/commands/info.ts`). What data is retrieved from the `data` object
 | ||||
| // (which contains the data received from the Gateway) and how can be seen
 | ||||
| // here:
 | ||||
| // <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/structures/Presence.js#L81-L110>.
 | ||||
| const oldPresencePatch = Presence.prototype.patch; | ||||
| Presence.prototype.patch = function patch(data: any) { | ||||
|     oldPresencePatch.call(this, {status: data.status}); | ||||
| }; | ||||
| 
 | ||||
| // NOTE: Terrible hack continued!!! Unfortunately we can't receive the presence
 | ||||
| // data at all when the GUILD_PRESENCES intent is disabled, so while we do
 | ||||
| // waste network bandwidth and the CPU time for decoding the incoming packets,
 | ||||
| // the function which handles those packets is NOP-ed out, which, among other
 | ||||
| // things, skips the code which caches the referenced users in the packet. See
 | ||||
| // <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/client/actions/PresenceUpdate.js#L7-L41>.
 | ||||
| export function attachToClient(client: Client) { | ||||
|     (client["actions"] as any)["PresenceUpdate"].handle = () => {}; | ||||
| 
 | ||||
|     (client as any).music = LavalinkMusic(client, { | ||||
|         lavalink: { | ||||
|             restnode: { | ||||
|                 host: "localhost", | ||||
|                 port: 2333, | ||||
|                 password: "youshallnotpass" | ||||
|             }, | ||||
|             nodes: [ | ||||
|                 { | ||||
|                     host: "localhost", | ||||
|                     port: 2333, | ||||
|                     password: "youshallnotpass" | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         prefix: Config.prefix, | ||||
|         helpCmd: "mhelp", | ||||
|         admins: ["717352467280691331"] | ||||
|     }); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue