├── Src ├── Saavan.js ├── Events │ ├── Nodes │ │ ├── Error.js │ │ ├── Close.js │ │ ├── Ready.js │ │ └── Disconnect.js │ ├── Dispatcher │ │ ├── PlayerResumed.js │ │ ├── PlayerEnd.js │ │ ├── PlayerExpeption.js │ │ ├── PlayerError.js │ │ ├── playerMoved.js │ │ ├── PlayerDestroy.js │ │ ├── PlayerStart.js │ │ └── PlayerEmpty.js │ └── Client │ │ ├── ChannelDelete.js │ │ ├── InteractionCreate.js │ │ ├── GuildRemove.js │ │ ├── VoiceStateUpdate.js │ │ ├── Ready.js │ │ ├── GuildDelete.js │ │ ├── GuildCreate.js │ │ ├── RequestChannel.js │ │ ├── ButtonInteraction.js │ │ └── MessageCreate.js ├── Shard.js ├── Components │ ├── Delete.js │ ├── Stop.js │ ├── Pause.js │ ├── Shuffle.js │ ├── Skip.js │ └── Loop.js ├── Models │ ├── Dj.js │ ├── Prefix.js │ ├── 247.js │ ├── Announce.js │ └── Setup.js ├── Scripts │ ├── Button.js │ ├── Events.js │ └── Message.js ├── Handler │ ├── Emoji.js │ └── RequestChannelEvent.js ├── Commands │ └── Message │ │ ├── Music │ │ ├── Stop.js │ │ ├── leave.js │ │ ├── Autoplay.js │ │ ├── Replay.js │ │ ├── Resume.js │ │ ├── Pause.js │ │ ├── Shuffle.js │ │ ├── Forward.js │ │ ├── Rewind.js │ │ ├── Seek.js │ │ ├── Volume.js │ │ ├── Join.js │ │ ├── Nowplaying.js │ │ ├── Loop.js │ │ ├── Skip.js │ │ ├── Clear.js │ │ ├── Previous.js │ │ ├── Play.js │ │ ├── Remove.js │ │ ├── Search.js │ │ └── Queue.js │ │ ├── Misc │ │ ├── Invite.js │ │ ├── Support.js │ │ ├── Ping.js │ │ ├── Vote.js │ │ ├── Player.js │ │ └── Stats.js │ │ ├── Filters │ │ ├── NightCore.js │ │ ├── VaporWave.js │ │ ├── TrebleBass.js │ │ ├── Speed.js │ │ └── BassBoost.js │ │ ├── Developers │ │ ├── GuildInvite.js │ │ ├── Node.js │ │ └── Eval.js │ │ └── Settings │ │ ├── 247.js │ │ ├── Prefix.js │ │ ├── Announce.js │ │ ├── Setup.js │ │ └── Dj.js ├── Utility │ └── Console.js ├── Base │ ├── Spotify.js │ └── Client.js └── Config.js ├── .github ├── dependabot.yml └── workflows │ ├── deno.yml │ └── codeql.yml ├── .gitpod.yml ├── SECURITY.md ├── LICENSE ├── package.json └── README.md /Src/Saavan.js: -------------------------------------------------------------------------------- 1 | const { Savaan } = require('./Base/Client'); 2 | const client = new Savaan(); 3 | module.exports = client 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" # Adjusted to check for updates every day 7 | -------------------------------------------------------------------------------- /Src/Events/Nodes/Error.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'error', 3 | /** 4 | * @param {import("../../Saavan")} client 5 | */ 6 | async execute(client, name, error) { 7 | client.console.log(`${name}: Error Caught,`, 'node'); 8 | }, 9 | }); -------------------------------------------------------------------------------- /Src/Events/Nodes/Close.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'close', 3 | /** 4 | * @param {import("../../Saavan")} client 5 | */ 6 | async execute(client, name, code, reason) { 7 | client.console.log(`${name}: Closed, Code ${code}`, 'node'); 8 | }, 9 | }); -------------------------------------------------------------------------------- /Src/Events/Nodes/Ready.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'ready', 3 | /** 4 | * @param {import("../../Saavan")} client 5 | * @param {import("kazagumo").KazagumoPlayer} dispatcher 6 | */ 7 | async execute(client, name) { 8 | client.console.log(`${name}: Ready!`, 'node'); 9 | }, 10 | }); -------------------------------------------------------------------------------- /Src/Events/Dispatcher/PlayerResumed.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'playerResumed', 3 | /** 4 | * @param {import("../../Saavan")} client 5 | * @param {import("kazagumo").KazagumoPlayer} dispatcher 6 | */ 7 | async execute(client, dispatcher) { 8 | client.console.log(`Player Resume in @ ${dispatcher.guildId}`, 'player'); 9 | }, 10 | }); -------------------------------------------------------------------------------- /Src/Events/Client/ChannelDelete.js: -------------------------------------------------------------------------------- 1 | const db = require('../../Models/Setup') 2 | module.exports = new Object({ 3 | name: "channelDelete", 4 | /** 5 | * @param {import("discord.js").TextChannel} channel 6 | */ 7 | async execute(_, channel) { 8 | const data = await db.findOne({ _id: channel.guild.id }) 9 | if (data && channel.id === data.channel) await data.delete() 10 | } 11 | }) -------------------------------------------------------------------------------- /Src/Shard.js: -------------------------------------------------------------------------------- 1 | const { Token } = require("./Config"); 2 | const { ShardingManager } = require("discord.js"); 3 | 4 | const manager = new ShardingManager("./Src/Saavan.js", { 5 | respawn: true, 6 | autoSpawn: true, 7 | token: "jngjdvjx2q43QgTS8i7DrwgCrkRf7nSRv8p8s0", 8 | totalShards: 1, 9 | shardList: "auto", 10 | }); 11 | manager.spawn({ amount: manager.totalShards, delay: null, timeout: -1 }); 12 | -------------------------------------------------------------------------------- /Src/Events/Client/InteractionCreate.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "interactionCreate", 3 | /** 4 | * @param {import("../../Saavan")} client 5 | * @param {import('discord.js').CommandInteraction} interaction 6 | */ 7 | async execute(client, interaction) { 8 | if (interaction.isButton()) { 9 | client.emit('ButtonInteraction', interaction) 10 | } 11 | } 12 | }) -------------------------------------------------------------------------------- /Src/Events/Client/GuildRemove.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "guildRemove", 3 | /** 4 | * @param {import("discord.js").Guild} guild 5 | * @param {import("../../Saavan")} client 6 | */ 7 | async execute(_, guild, client) { 8 | const dispatcher = client.dispatcher.players.get(guild.id) 9 | if (!dispatcher) return; 10 | if (guild.id === dispatcher.guildId) dispatcher.destroy(); 11 | } 12 | }) -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart 6 | 7 | tasks: 8 | - init: npm install 9 | command: npm run start 10 | 11 | 12 | -------------------------------------------------------------------------------- /Src/Events/Dispatcher/PlayerEnd.js: -------------------------------------------------------------------------------- 1 | const db = require('../../Models/Setup'); 2 | module.exports = new Object({ 3 | name: 'playerEnd', 4 | /** 5 | * @param {import("../../Saavan")} client 6 | * @param {import("kazagumo").KazagumoPlayer} dispatcher 7 | */ 8 | async execute(client, dispatcher) { 9 | if (dispatcher.data.get("message") && !dispatcher.data.get("message").deleted) dispatcher.data.get("message").delete().catch(() => null); 10 | }, 11 | }); -------------------------------------------------------------------------------- /Src/Events/Nodes/Disconnect.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'disconnect', 3 | /** 4 | * @param {import("../../Saavan")} client 5 | * @param {import("kazagumo").KazagumoPlayer} players 6 | * @param {import("kazagumo").KazagumoTrack} track 7 | */ 8 | async execute(client, name, players, moved) { 9 | if (moved) return; 10 | players.map(player => player.connection.disconnect()); 11 | client.console.log(`Lavalink ${name}: Disconnected`, 'node'); 12 | }, 13 | }); -------------------------------------------------------------------------------- /Src/Events/Dispatcher/PlayerExpeption.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'playerException', 3 | /** 4 | * @param {import("../../Saavan")} client 5 | * @param {import("kazagumo").KazagumoPlayer} dispatcher 6 | * @param {*} reason 7 | */ 8 | async execute(client, dispatcher, reason) { 9 | client.console.log(`Player Get exception ${reason}`, 'error'); 10 | const guild = client.guilds.cache.get(dispatcher.guildId); 11 | if (!guild) return; 12 | dispatcher.destroy(guild.id); 13 | }, 14 | }); -------------------------------------------------------------------------------- /Src/Components/Delete.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'delete', 3 | id: 'delete', 4 | permissions: { 5 | client: [], 6 | user: [], 7 | dev: true, 8 | 9 | }, 10 | player: { voice: false, active: false, dj: false, }, 11 | cooldown: 5, 12 | /** 13 | * @param {import("../Saavan")} client 14 | * @param {import("discord.js").ButtonInteraction} interaction 15 | */ 16 | execute: async (client, interaction, color, dispatcher) => { 17 | interaction.message.delete(); 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /Src/Events/Dispatcher/PlayerError.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'playerError', 3 | /** 4 | * 5 | * @param {import("../../Saavan")} client 6 | * @param {import("kazagumo").KazagumoPlayer} dispatcher 7 | * @param {*} type 8 | * @param {*} error 9 | */ 10 | async execute(client, dispatcher, type, error) { 11 | client.console.log(`Player get error ${error.message}`, 'error'); 12 | const guild = client.guilds.cache.get(dispatcher.guildId); 13 | if (!guild) return; 14 | await dispatcher.destroy(guild); 15 | }, 16 | }); -------------------------------------------------------------------------------- /Src/Models/Dj.js: -------------------------------------------------------------------------------- 1 | const { model, Schema } = require('mongoose'); 2 | 3 | module.exports = model('dj-schema', new Schema({ 4 | _id: { 5 | type: String, 6 | required: true, 7 | }, 8 | 9 | roles: { 10 | type: Array, 11 | default: null, 12 | }, 13 | 14 | mode: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | 19 | moderator: { 20 | type: String, 21 | required: true, 22 | }, 23 | 24 | lastUpdated: { 25 | type: String, 26 | default: Math.round(new Date().getDate / 1000), 27 | }, 28 | })); -------------------------------------------------------------------------------- /Src/Scripts/Button.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('node:fs'); 2 | const { join } = require('path'); 3 | /** 4 | * @param {import('../Saavan')} client 5 | */ 6 | module.exports = (client) => { 7 | let count = 0; 8 | const buttonFile = readdirSync(join(__dirname, '..', 'Components')).filter( 9 | files => files.endsWith('.js'), 10 | ); 11 | for (const files of buttonFile) { 12 | const buttons = require(`../Components/${files}`); 13 | client.ButtonInt.set(buttons.id, buttons); 14 | count++; 15 | } 16 | client.console.log(`Loaded: ${count}`, 'button'); 17 | } -------------------------------------------------------------------------------- /Src/Models/Prefix.js: -------------------------------------------------------------------------------- 1 | const { Schema, model } = require('mongoose'); 2 | const PrefixSchema = new Schema({ 3 | _id: { 4 | type: String, 5 | required: true, 6 | }, 7 | prefix: { 8 | type: String, 9 | required: true, 10 | }, 11 | oldPrefix: { 12 | type: String, 13 | required: true, 14 | }, 15 | moderator: { 16 | type: String, 17 | required: true, 18 | }, 19 | lastUpdated: { 20 | type: String, 21 | default: new Date().getDate(), 22 | }, 23 | }); 24 | module.exports = model('prefix-schema', PrefixSchema); 25 | -------------------------------------------------------------------------------- /Src/Models/247.js: -------------------------------------------------------------------------------- 1 | const { model, Schema } = require('mongoose'); 2 | 3 | module.exports = model('247-schema', new Schema({ 4 | _id: { 5 | type: String, 6 | required: true, 7 | }, 8 | mode: { 9 | type: Boolean, 10 | required: true, 11 | }, 12 | textChannel: { 13 | type: String, 14 | default: null, 15 | }, 16 | voiceChannel: { 17 | type: String, 18 | default: null, 19 | }, 20 | moderator: { 21 | type: String, 22 | required: true, 23 | }, 24 | lastUpdated: { 25 | type: String, 26 | default: Math.round(new Date().getDate() / 1000), 27 | }, 28 | })); 29 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /Src/Models/Announce.js: -------------------------------------------------------------------------------- 1 | const { model, Schema } = require('mongoose'); 2 | 3 | module.exports = model('announce_schema', new Schema({ 4 | _id: { 5 | type: String, 6 | required: true, 7 | }, 8 | 9 | mode: { 10 | type: Boolean, 11 | required: true, 12 | }, 13 | 14 | lastUpdated: { 15 | type: String, 16 | default: Math.round(new Date().getDate() / 1000), 17 | }, 18 | 19 | prunning: { 20 | type: Boolean, 21 | default: false, 22 | }, 23 | 24 | channel: { 25 | type: String, 26 | default: null, 27 | }, 28 | 29 | moderator: { 30 | type: String, 31 | required: true, 32 | }, 33 | })); -------------------------------------------------------------------------------- /Src/Scripts/Events.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('node:fs'); 2 | const { join } = require('path'); 3 | /** 4 | * @param {import('../Saavan')} client 5 | */ 6 | module.exports = (client) => { 7 | let count = 0 8 | const eventFiles = readdirSync(join(__dirname, "..", "Events", "Client")).filter((files) => files.endsWith(".js")); 9 | for (const files of eventFiles) { 10 | const event = require(`../Events/Client/${files}`); 11 | if (event.once) { 12 | client.once(event.name, (...args) => event.execute(client, ...args)); 13 | } else { client.on(event.name, (...args) => event.execute(client, ...args)) }; 14 | count++ 15 | }; 16 | client.console.log(`Loaded: ${count}`, "client"); 17 | } -------------------------------------------------------------------------------- /Src/Models/Setup.js: -------------------------------------------------------------------------------- 1 | const { model, Schema } = require('mongoose'); 2 | 3 | module.exports = model('setup-schema', new Schema({ 4 | _id: { 5 | type: String, 6 | required: true, 7 | }, 8 | 9 | channel: { 10 | type: String, 11 | required: true, 12 | }, 13 | 14 | setuped: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | 19 | message: { 20 | type: String, 21 | required: true, 22 | }, 23 | 24 | moderator: { 25 | type: String, 26 | required: true, 27 | }, 28 | 29 | lastUpdated: { 30 | type: String, 31 | default: new Date().getDate(), 32 | }, 33 | 34 | logs: { 35 | type: Array, 36 | default: null, 37 | }, 38 | })); -------------------------------------------------------------------------------- /Src/Handler/Emoji.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | progress1: '', 3 | progress2: '', 4 | progress3: '', 5 | progress4: '', 6 | progress5: '', 7 | progress6: '', 8 | progress7: '', 9 | progress8: '', 10 | spotify: '', 11 | tick: '', 12 | cross: '', 13 | delete: '', 14 | yes: '<:q_online:1118882620936290395>', 15 | no: '<:q_offline:1118882501121802240>', 16 | saavan : '<:vr_galxy:1077449151995973704>' 17 | }; -------------------------------------------------------------------------------- /Src/Events/Client/VoiceStateUpdate.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "voiceStateUpdate", 3 | /** 4 | * @param {import("../../Saavan")} client 5 | * @param {import("discord.js").VoiceState} oldState 6 | * @param {import("discord.js").VoiceState} newState 7 | * @returns {Promise} 8 | */ 9 | async execute(client, oldState, newState) { 10 | const dispatcher = client.dispatcher.players.get(oldState.guild.id); 11 | if (newState.id === client.user.id &&newState.serverMute == true && oldState.serverMute == false) { 12 | dispatcher.pause(true) 13 | await client.util.update(dispatcher, client) 14 | } 15 | if (newState.id === client.user.id && newState.serverMute == false && oldState.serverMute == true) { 16 | dispatcher.pause(false) 17 | await client.util.update(dispatcher, client) 18 | } 19 | } 20 | }) -------------------------------------------------------------------------------- /Src/Components/Stop.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'stop', 3 | id: 'stop_but', 4 | permissions: { 5 | client: [], 6 | user: [], 7 | dev: false, 8 | 9 | }, 10 | player: { voice: true, active: true, dj: true, }, 11 | cooldown: 5, 12 | /** 13 | * @param {import("../Saavan")} client 14 | * @param {import("discord.js").CommandInteraction} interaction 15 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 16 | */ 17 | execute: async (client, interaction, color, dispatcher) => { 18 | const autoplay = dispatcher.data.get('autoplay'); 19 | if (autoplay) dispatcher.data.set('autoplay', false); 20 | if (dispatcher.paused) dispatcher.pause(false) 21 | dispatcher.queue.clear(); 22 | dispatcher.destroy(); 23 | return await client.util.buttonReply(interaction, `${client.emoji.tick} Player has been stopped/destroyed.`, color); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /Src/Scripts/Message.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('node:fs'); 2 | const { join } = require('path'); 3 | /** 4 | * @param {import('../Saavan')} client 5 | */ 6 | module.exports = (client) => { 7 | let count = 0 8 | readdirSync(join(__dirname, "..", "Commands", "Message")).forEach((folder) => { 9 | const commandFiles = readdirSync(join(__dirname, "..", "Commands", "Message", `${folder}`)).filter((files) => files.endsWith(".js")); 10 | for (const files of commandFiles) { 11 | const command = require(`../Commands/Message/${folder}/${files}`); 12 | if (command.category && command.category !== folder) command.category = folder; 13 | client.Commands.set(command.name, command); 14 | if (command.aliases && Array.isArray(command.aliases)) for (const i of command.aliases) client.Aliases.set(i, command.name); 15 | count++ 16 | }; 17 | }); 18 | client.console.log(`Command Loaded: ${count}`, "cmd"); 19 | } -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Stop.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "stop", 3 | description: "Stops the song and clear the queue.", 4 | category: "Music", 5 | cooldown: 20, 6 | usage: '', 7 | aliases: ['end'], 8 | examples: [''], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | dispatcher.queue.clear(); 30 | dispatcher.destroy(); 31 | return await client.util.msgReply(message, `${client.emoji.tick} Stopped the music and cleared the queue.`, color); 32 | } 33 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Misc/Invite.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "invite", 3 | description: "Get a link to invite.", 4 | category: "Misc", 5 | usage: "", 6 | cooldown: 10, 7 | usage: '', 8 | aliases: ['addme', 'add'], 9 | examples: [''], 10 | sub_commands: [], 11 | args: false, 12 | permissions: { 13 | client: [], 14 | user: [], 15 | dev: false, 16 | }, 17 | player: { voice: false, active: false, dj: false, }, 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | */ 26 | async execute(client, message, args, prefix, color) { 27 | return message.reply({ 28 | embeds: [ 29 | client.embed() 30 | .setDescription(`[Click here](${client.config.links.invite}) to invite the bot.`) 31 | .setColor(color), 32 | ], 33 | }); 34 | }, 35 | }); -------------------------------------------------------------------------------- /Src/Commands/Message/Music/leave.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "leave", 3 | description: "Disconnect the bot from the VC.", 4 | category: "Music", 5 | cooldown: 60, 6 | usage: '', 7 | aliases: ["destroy", "disconnect", "dc"], 8 | examples: ["leave", "destroy", "disconnect", "dc"], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: false, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | if (dispatcher) dispatcher.destroy(); 30 | return await client.util.msgReply(message, `${client.emoji.tick} Player is now destroyed.`, color); 31 | } 32 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Misc/Support.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "support", 3 | description: "Get a link to support server .", 4 | category: "Misc", 5 | usage: "", 6 | cooldown: 10, 7 | usage: '', 8 | aliases: ['support', 'su'], 9 | examples: [''], 10 | sub_commands: [], 11 | args: false, 12 | permissions: { 13 | client: [], 14 | user: [], 15 | dev: false, 16 | }, 17 | player: { voice: false, active: false, dj: false, }, 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | */ 26 | async execute(client, message, args, prefix, color) { 27 | return message.reply({ 28 | embeds: [ 29 | client.embed() 30 | .setDescription(`[Support Server ](${client.config.links.support}) join support server.`) 31 | .setColor(color), 32 | ], 33 | }); 34 | }, 35 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ₦ł₵₭ ₣ɄⱤɎ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Src/Components/Pause.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'pause', 3 | id: 'pause_but', 4 | permissions: { 5 | client: [], 6 | user: [], 7 | dev: false, 8 | 9 | }, 10 | player: { voice: true, active: true, dj: true, }, 11 | cooldown: 5, 12 | /** 13 | * @param {import("../Saavan")} client 14 | * @param {import("discord.js").CommandInteraction} interaction 15 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 16 | */ 17 | execute: async (client, interaction, color, dispatcher) => { 18 | if (dispatcher.paused) { 19 | dispatcher.pause(false); 20 | await client.util.update(dispatcher, client); 21 | return await client.util.buttonReply(interaction, `${client.emoji.tick} ${interaction.member} has resumed the music.`, color); 22 | } else { 23 | dispatcher.pause(true); 24 | await client.util.update(dispatcher, client); 25 | return await client.util.buttonReply(interaction, `${client.emoji.tick} ${interaction.member} has paused the music.`, color); 26 | } 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Autoplay.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "autoplay", 3 | description: "Toggles Autoplay.", 4 | category: "Music", 5 | cooldown: 60, 6 | usage: '', 7 | aliases: ['ap'], 8 | examples: [''], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | dispatcher.data.set('autoplay', !dispatcher.data.get('autoplay')); 30 | await client.util.update(dispatcher, client); 31 | return await client.util.msgReply(message, `${client.emoji.tick} Autoplay is now ${dispatcher.data.get('autoplay') ? '*`enabled`*' : '*`disabled`*'}.`, color); 32 | } 33 | }) -------------------------------------------------------------------------------- /.github/workflows/deno.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow will install Deno then run `deno lint` and `deno test`. 7 | # For more information see: https://github.com/denoland/setup-deno 8 | 9 | name: Deno 10 | 11 | on: 12 | push: 13 | branches: ["main"] 14 | pull_request: 15 | branches: ["main"] 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | test: 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - name: Setup repo 26 | uses: actions/checkout@v3 27 | 28 | - name: Setup Deno 29 | # uses: denoland/setup-deno@v1 30 | uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31 # v1.1.2 31 | with: 32 | deno-version: v1.x 33 | 34 | # Uncomment this step to verify the use of 'deno fmt' on each commit. 35 | # - name: Verify formatting 36 | # run: deno fmt --check 37 | 38 | - name: Run linter 39 | run: deno lint 40 | 41 | - name: Run tests 42 | run: deno test -A 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Lyricloom", 3 | "version": "1.0.0", 4 | "description": "LyricLoom is an advanced Discord music bot that takes your server's audio experience to the next level. With a robust DJ system, it's the perfect companion for music enthusiasts who want to create memorable playlists and host engaging DJ sessions within their Discord communities.", 5 | "main": "Src/Shard.js", 6 | "scripts": { 7 | "start": "node Src/Shard.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/" 13 | }, 14 | "keywords": [], 15 | "author": "NICK FURY", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/NICK-FURY-6023" 19 | }, 20 | "homepage": "https://github.com/NICK-FURY-6023", 21 | "dependencies": { 22 | "@top-gg/sdk": "^3.1.6", 23 | "discord.js": "^14.15.2", 24 | "i": "^0.3.7", 25 | "install": "^0.13.0", 26 | "kazagumo": "^3.0.4", 27 | "kazagumo-spotify": "^2.1.0", 28 | "mongoose": "^8.5.3", 29 | "npm": "^10.8.2", 30 | "shoukaku": "^4.1.0", 31 | "soundcloud": "^3.3.2", 32 | "systeminformation": "^5.23.2", 33 | "undici": "^6.18.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Src/Components/Shuffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'Shuffle', 3 | id: 'shuffle_but', 4 | permissions: { 5 | client: [], 6 | user: [], 7 | dev: false, 8 | 9 | }, 10 | player: { voice: true, active: true, dj: true, }, 11 | cooldown: 5, 12 | /** 13 | * @param {import("../Saavan")} client 14 | * @param {import("discord.js").CommandInteraction} interaction 15 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 16 | */ 17 | execute: async (client, interaction, color, dispatcher) => { 18 | if (dispatcher.queue.size < 3) return await client.util.buttonReply(interaction, `${client.emoji.cross} Not enough songs in the queue to shuffle.`, color); 19 | if (dispatcher.shuffle) { 20 | dispatcher.setUnshuffle(); 21 | client.util.update(dispatcher, client); 22 | return await client.util.buttonReply(interaction, `${client.emoji.tick} Unshuffled the queue.`, color); 23 | } else { 24 | dispatcher.setShuffle(); 25 | client.util.update(dispatcher, client); 26 | return await client.util.buttonReply(interaction, `${client.emoji.tick} Shuffled the queue.`, color); 27 | } 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Replay.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "replay", 3 | description: "Replays the current playing track.", 4 | category: "Music", 5 | cooldown: 10, 6 | usage: '', 7 | aliases: ['rep'], 8 | examples: [''], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | const { tracks } = await dispatcher.search(dispatcher.queue.current.title, { requester: message.author, engine: 'spotify' }) 30 | dispatcher.queue.add(tracks[0]) 31 | dispatcher.skip() 32 | await client.util.update(dispatcher, client); 33 | return await client.util.msgReply(message, ` ${client.emoji.tick} Replaying the Current Song`, color); 34 | } 35 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Filters/NightCore.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "nightcore", 3 | description: "Toggles Nightcore filter.", 4 | category: "Filters", 5 | cooldown: 20, 6 | usage: '', 7 | aliases: [], 8 | examples: [""], 9 | sub_commands: [""], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | 16 | }, 17 | player: { voice: true, active: true, dj: true, }, 18 | 19 | /** 20 | * 21 | * @param {import("../../../Saavan")} client 22 | * @param {import("discord.js").Message} message 23 | * @param {String[]} args 24 | * @param {String} prefix 25 | * @param {String} color 26 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 27 | */ 28 | 29 | async execute(client, message, args, prefix, color, dispatcher) { 30 | if (dispatcher.nightcore) { 31 | dispatcher.setNightCore(false); 32 | return await client.util.msgReply(message, `${client.emoji.tick} Nightcore filter/effect is now disabled.`, color); 33 | } else { 34 | dispatcher.setNightCore(true); 35 | return await client.util.msgReply(message, `${client.emoji.tick} Nightcore filter/effect is now enabled.`, color); 36 | } 37 | }, 38 | }); -------------------------------------------------------------------------------- /Src/Commands/Message/Filters/VaporWave.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "vaporwave", 3 | description: "Toggles Vaporwave filter.", 4 | category: "Filters", 5 | cooldown: 20, 6 | usage: '', 7 | aliases: [], 8 | examples: [""], 9 | sub_commands: [""], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | 16 | }, 17 | player: { voice: true, active: true, dj: true, }, 18 | 19 | /** 20 | * 21 | * @param {import("../../../Saavan")} client 22 | * @param {import("discord.js").Message} message 23 | * @param {String[]} args 24 | * @param {String} prefix 25 | * @param {String} color 26 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 27 | */ 28 | 29 | async execute(client, message, args, prefix, color, dispatcher) { 30 | if (dispatcher.vaporwave) { 31 | dispatcher.setVaporwave(false); 32 | return await client.util.msgReply(message, `${client.emoji.tick} Vaporwave filter/effect is now disabled.`, color); 33 | } else { 34 | dispatcher.setVaporwave(true); 35 | return await client.util.msgReply(message, `${client.emoji.tick} Vaporwave filter/effect is now enabled.`, color); 36 | } 37 | }, 38 | }); -------------------------------------------------------------------------------- /Src/Commands/Message/Filters/TrebleBass.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "treblebass", 3 | description: "Toggle Treblebass effect.", 4 | category: "Filters", 5 | cooldown: 20, 6 | usage: '', 7 | aliases: [], 8 | examples: [""], 9 | sub_commands: [""], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | 16 | }, 17 | player: { voice: true, active: true, dj: true, }, 18 | 19 | /** 20 | * 21 | * @param {import("../../../Saavan")} client 22 | * @param {import("discord.js").Message} message 23 | * @param {String[]} args 24 | * @param {String} prefix 25 | * @param {String} color 26 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 27 | */ 28 | 29 | async execute(client, message, args, prefix, color, dispatcher) { 30 | if (dispatcher.treblebass) { 31 | dispatcher.setTreblebass(false); 32 | return await client.util.msgReply(message, `${client.emoji.tick} Treblebass filter/effect is now disabled.`, color); 33 | } else { 34 | dispatcher.setTreblebass(true); 35 | return await client.util.msgReply(message, `${client.emoji.tick} Treblebass filter/effect is now enabled.`, color); 36 | } 37 | }, 38 | }); -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Resume.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "resume", 3 | description: "Resumes the current paused track.", 4 | category: "Music", 5 | cooldown: 10, 6 | usage: '', 7 | aliases: ['res'], 8 | examples: [''], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | if (dispatcher.paused) { 30 | await client.util.update(dispatcher, client); 31 | await client.util.msgReply(message, `${client.emoji.tick} Resumed the song at ${dispatcher.shoukaku.position}.`, color).catch(() => { }); 32 | dispatcher.pause(false); 33 | } else { 34 | return await client.util.msgReply(message, `${client.emoji.cross} The song is not paused.`, color).catch(() => { }); 35 | } 36 | } 37 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Pause.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "pause", 3 | description: "Pauses the current track.", 4 | category: "Music", 5 | cooldown: 10, 6 | usage: '', 7 | aliases: ['pau'], 8 | examples: [''], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | if (dispatcher.paused) { 30 | return await client.util.msgReply(message, `${client.emoji.cross} <:vr_pause:1079900527791452312> The song is already paused.`, color); 31 | } else { 32 | dispatcher.pause(true); 33 | await client.util.update(dispatcher, client); 34 | await client.util.msgReply(message, `${client.emoji.tick} <:vr_pause:1079900527791452312> Paused the song at ${dispatcher.shoukaku.position}.`, color); 35 | dispatcher.pause(true); 36 | } 37 | } 38 | }) -------------------------------------------------------------------------------- /Src/Events/Client/Ready.js: -------------------------------------------------------------------------------- 1 | const db = require('../../Models/247'); 2 | module.exports = new Object({ 3 | name: "ready", 4 | /** 5 | * @param {import("../../Saavan")} client 6 | */ 7 | async execute(client) { 8 | client.console.log(`Logged in as ${client.user.tag}`, "api"); 9 | await client.guilds.fetch({ cache: true }); 10 | const maindata = await db.find(); 11 | client.console.log(`Auto Reconnect found ${maindata.length ? `${maindata.length} queue${maindata.length > 1 ? 's' : ''}. Resuming all auto reconnect queue` : '0 queue'}`, 'player'); 12 | for (const data of maindata) { 13 | const index = maindata.indexOf(data); 14 | setTimeout(async () => { 15 | const text = client.channels.cache.get(data.textChannel); 16 | const guild = client.guilds.cache.get(data._id); 17 | const voice = client.channels.cache.get(data.voiceChannel); 18 | if (!guild || !text || !voice) return data.delete(); 19 | const player = client.dispatcher.createPlayer({ 20 | guildId: guild.id, 21 | textId: text.id, 22 | voiceId: voice.id, 23 | deaf: true, 24 | shardId: guild.shardId, 25 | }); 26 | }, 27 | ), index * 5000; 28 | } 29 | } 30 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Misc/Ping.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "ping", 3 | description: "Shows the latency of the bot.", 4 | category: "Misc", 5 | usage: "", 6 | cooldown: 10, 7 | usage: '', 8 | aliases: ['pong'], 9 | examples: [''], 10 | sub_commands: [], 11 | args: false, 12 | permissions: { 13 | client: [], 14 | user: [], 15 | dev: false, 16 | }, 17 | player: { voice: false, active: false, dj: false, }, 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | */ 26 | async execute(client, message, args, prefix, color) { 27 | 28 | let ping = Math.floor(client.ws.ping); 29 | if (ping === 0) { 30 | ping = '⚫ `' + Math.floor(client.ws.ping) + ' ms`'; 31 | } else if (ping < 100) { 32 | ping = '🟢 `' + Math.floor(client.ws.ping) + ' ms`'; 33 | } else if (ping < 180) { 34 | ping = '🟡 `' + Math.floor(client.ws.ping) + ' ms`'; 35 | } else ping = '🔴 `' + Math.floor(client.ws.ping) + ' ms`'; 36 | const embed = client.embed() 37 | .setColor(color) 38 | .setDescription(ping) 39 | return message.reply({ embeds: [embed] }) 40 | } 41 | }) -------------------------------------------------------------------------------- /Src/Utility/Console.js: -------------------------------------------------------------------------------- 1 | module.exports = class Console { 2 | static log(content, type = "log") { 3 | 4 | switch (type) { 5 | case "log": { return console.log(`• [ Log ] ` + " => " + content) } 6 | case "warn": { return console.log(`• [ Warn ] ` + " => " + content) } 7 | case "error": { return console.log(`• [ Error ] ` + "=> " + content) } 8 | case "debug": { return console.log(`• [ Debug ] ` + "=> " + content) } 9 | case "cmd": { return console.log(`• [ Commands ] ` + " => " + content) } 10 | case "Scmd": { return console.log(`• [ Slash ] ` + " => " + content) } 11 | case "button": { return console.log(`• [ Button ] ` + " => " + content) } 12 | case "event": { return console.log(`• [ Events ] ` + "=> " + content) } 13 | case "lavalink": { return console.log(`• [ Lavalink ] ` + "=> " + content) } 14 | case "client": { return console.log(`• [ Client ] ` + " => " + content) } 15 | case "api": { return console.log(`• [ Api ] ` + " => " + content) } 16 | case "player": { return console.log(`• [ Player ] ` + " => " + content) } 17 | case "node": { return console.log(`• [ Node ] ` + " => " + content) } 18 | default: throw new TypeError("Logger type must be either warn, debug, log, ready, cmd or error."); 19 | } 20 | } 21 | }; -------------------------------------------------------------------------------- /Src/Components/Skip.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'skip', 3 | id: 'skipbut_but', 4 | permissions: { 5 | client: [], 6 | user: [], 7 | dev: false, 8 | 9 | }, 10 | player: { voice: true, active: true, dj: true, }, 11 | cooldown: 5, 12 | /** 13 | * @param {import("../Saavan")} client 14 | * @param {import("discord.js").CommandInteraction} interaction 15 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 16 | */ 17 | execute: async (client, interaction, color, dispatcher) => { 18 | const { title, uri } = dispatcher.queue.current; 19 | if (dispatcher.data.get('autoplay')) { 20 | if (dispatcher.paused) dispatcher.pause(false) 21 | await client.util.autoplay(client, dispatcher, "skip") 22 | await client.util.update(dispatcher, client); 23 | return await client.util.buttonReply(interaction, `${interaction.member} has skipped [${title}](${uri})`, color); 24 | } else if (dispatcher.queue.size === 0) return await client.util.buttonReply(interaction, 'No more songs left in the queue to skip.', color); 25 | if (dispatcher.paused) dispatcher.pause(false) 26 | dispatcher.skip(); 27 | await client.util.update(dispatcher, client); 28 | return await client.util.buttonReply(interaction, `${client.emoji.tick} ${interaction.member} has skipped [${title}](${uri})`, color); 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /Src/Components/Loop.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'loop', 3 | id: 'loopmodesbut_but', 4 | permissions: { 5 | client: [], 6 | user: [], 7 | dev: false, 8 | 9 | }, 10 | player: { voice: true, active: true, dj: true, }, 11 | cooldown: 5, 12 | /** 13 | * @param {import("../Saavan")} client 14 | * @param {import("discord.js").CommandInteraction} interaction 15 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 16 | */ 17 | execute: async (client, interaction, color, dispatcher) => { 18 | if (dispatcher.loop == 'none') { 19 | dispatcher.setLoop('track'); 20 | await client.util.update(dispatcher, client); 21 | return await client.util.buttonReply(interaction, `${client.emoji.tick} ${interaction.member} has enabled **track** loop`, color); 22 | } else if (dispatcher.loop == 'track') { 23 | dispatcher.setLoop('queue'); 24 | await client.util.update(dispatcher, client); 25 | return await client.util.buttonReply(interaction, `${client.emoji.tick} ${interaction.member} has enabled **queue** loop`, color); 26 | } else { 27 | dispatcher.setLoop('none'); 28 | await client.util.update(dispatcher, client); 29 | return await client.util.buttonReply(interaction, `${client.emoji.tick} ${interaction.member} has **disabled** looping`, color); 30 | } 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Shuffle.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "shuffle", 3 | description: "Toggle Shuffle/Unshuffle the queue.", 4 | category: "Music", 5 | cooldown: 15, 6 | usage: '', 7 | aliases: ['mix'], 8 | examples: [''], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | if (dispatcher.queue.size < 3) return await client.util.msgReply(message, `${client.emoji.cross} Not enough songs in the queue to shuffle.`, color); 30 | if (dispatcher.shuffle) { 31 | dispatcher.setUnshuffle(); 32 | client.util.update(dispatcher, client); 33 | return await client.util.msgReply(message, `${client.emoji.tick} Unshuffled the queue.`, color); 34 | } else { 35 | dispatcher.setShuffle(); 36 | client.util.update(dispatcher, client); 37 | return await client.util.msgReply(message, `${client.emoji.tick} Shuffled the queue.`, color); 38 | } 39 | } 40 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Developers/GuildInvite.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "getinvite", 3 | description: "Evals the code.", 4 | category: "Developers", 5 | usage: "", 6 | cooldown: 10, 7 | usage: '', 8 | aliases: ['gi'], 9 | examples: [''], 10 | sub_commands: [], 11 | args: false, 12 | permissions: { 13 | client: [], 14 | user: [], 15 | dev: true, 16 | 17 | }, 18 | player: { voice: false, active: false, dj: false, }, 19 | 20 | /** 21 | * 22 | * @param {import("../../../Saavan")} client 23 | * @param {import("discord.js").Message} message 24 | * @param {String[]} args 25 | * @param {String} prefix 26 | * @param {String} color 27 | */ 28 | 29 | async execute(client, message, args, prefix, color) { 30 | const guild = client.guilds.fetch(args[0]); 31 | if (!guild) return await client.util.replyOops(message, 'Guild not found', color); 32 | let text; 33 | (await guild).channels.cache.forEach((channel) => { 34 | if (channel.type === require('discord.js').ChannelType.GuildText) { 35 | text = channel; 36 | } 37 | }); 38 | if (!text) return await client.util.replyOops(message, "No text channel found", color); 39 | try { 40 | const invite = await text.createInvite(); 41 | await message.reply({ content: `https://discord.gg/${invite.code}`, ephemeral: true }); 42 | } catch (e) { 43 | client.console.log(e, 'error'); 44 | } 45 | } 46 | }) -------------------------------------------------------------------------------- /Src/Events/Dispatcher/playerMoved.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: 'playerMoved', 3 | /** 4 | * 5 | * @param {import("../../Saavan")} client 6 | * @param {import("kazagumo").KazagumoPlayer} dispatcher 7 | * @param {import("kazagumo").PlayerMovedState} state 8 | * @param {import("kazagumo").PlayerMovedChannels} channel 9 | */ 10 | async execute(client, dispatcher, state, channel) { 11 | 12 | const guild = client.guilds.cache.get(dispatcher.guildId); 13 | if (!guild) return; 14 | const chn = client.channels.cache.get(dispatcher.textId); 15 | if (channel.newChannelId === channel.oldChannelId) return; 16 | if (channel.newChannelId === null || !channel.newChannelId) { 17 | if (!dispatcher) return; 18 | dispatcher.destroy(); 19 | if (chn) return await chn.send({ embeds: [client.embed().setDescription(`${client.emoji.cross} Someone has disconnected me from <#${channel.oldChannelId}>.`).setColor(client.color)] }).then((a) => setTimeout(async () => await a.delete().catch(() => { }), 12000)).catch(() => { }); 20 | } else { 21 | if (!dispatcher) return; 22 | dispatcher.setVoiceChannel(channel.newChannelId); 23 | if (chn) await chn.send({ embeds: [client.embed().setDescription(`${client.emoji.tick} Successfully locomoted player voice channel to <#${dispatcher.voiceId}>.`).setColor(client.color)] }).then((a) => setTimeout(async () => await a.delete().catch(() => { }), 12000)).catch(() => { }); 24 | if (dispatcher.paused) dispatcher.pause(false); 25 | } 26 | }, 27 | }); -------------------------------------------------------------------------------- /Src/Commands/Message/Developers/Node.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "node", 3 | description: "Get the node stats", 4 | category: "Developers", 5 | usage: "", 6 | cooldown: 10, 7 | usage: '', 8 | aliases: ['lavalink'], 9 | examples: [''], 10 | sub_commands: [], 11 | args: false, 12 | permissions: { 13 | client: [], 14 | user: [], 15 | dev: true, 16 | 17 | }, 18 | player: { voice: false, active: false, dj: false, }, 19 | /** 20 | * 21 | * @param {import("../../../Saavan")} client 22 | * @param {import("discord.js").Message} message 23 | * @param {String[]} args 24 | * @param {String} prefix 25 | * @param {String} color 26 | */ 27 | async execute(client, message, args, prefix, color) { 28 | return message.channel.send({ 29 | embeds: [ 30 | client.embed() 31 | .setColor(color) 32 | .setAuthor({ name: "Node Statistics", url: client.config.links.support, iconURL: client.user.displayAvatarURL() }) 33 | .setTimestamp() 34 | .setDescription(`\`\`\`nim\n${[...client.dispatcher.shoukaku.nodes.values()].map((node) => `Node :: ${node.state === 1 ? "🟢" : "🔴"} ${node.name}\nMemory Usage :: ${client.util.formatBytes(node.stats.memory.allocated)} - ${node.stats.cpu.lavalinkLoad.toFixed(2)}%\nConnections :: ${client.dispatcher.players.size}\nUptime :: ${client.util.msToTime(node.stats.uptime)}`).join("\n\n------------------------------------------------------------\n\n")}\`\`\``), 35 | ], 36 | }); 37 | }, 38 | }); -------------------------------------------------------------------------------- /Src/Events/Client/GuildDelete.js: -------------------------------------------------------------------------------- 1 | const { WebhookClient } = require('discord.js'); 2 | 3 | module.exports = new Object({ 4 | name: 'guildDelete', 5 | /** 6 | * @param {import("../../Saavan")} client 7 | * @param {import("discord.js").Guild} guild 8 | */ 9 | async execute(client, guild) { 10 | const hook = new WebhookClient({ url: client.config.hooks.guildRemove }); 11 | const embed = client.embed() 12 | .setThumbnail(guild.iconURL({ dynamic: true, size: 1024 })) 13 | .setTitle(`📤 Left a Guild From ${guild.name}`) 14 | .addFields([ 15 | { 16 | name: 'Created On', 17 | value: ``, 18 | inline: false, 19 | }, 20 | { 21 | name: 'Added On', 22 | value: ``, 23 | inline: false, 24 | }, 25 | { 26 | name: 'Guild Id', 27 | value: `\`${guild.id}\``, 28 | inline: false, 29 | }, 30 | { 31 | name: 'Owner', 32 | value: `<@${guild.ownerId}> (\`id: ${guild.ownerId}\`)`, 33 | inline: false, 34 | }, 35 | { 36 | name: 'Total Members Count', 37 | value: `\`[ ${guild.memberCount} ]\``, 38 | inline: false, 39 | }, 40 | ]) 41 | .setColor(client.color) 42 | if (hook) await hook.send({ embeds: [embed] }) 43 | else return; 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Forward.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "forward", 3 | description: "Forwards the track to given position.", 4 | category: "Music", 5 | cooldown: 10, 6 | usage: '[position]', 7 | aliases: ['f'], 8 | examples: ["forward", "forward 3", "f", "f 10"], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | if (!dispatcher.queue.current.isSeekable) return await client.util.msgReply(message, `${client.emoji.cross} Unable to forward this track.`, color); 30 | let position = 10000; 31 | if(args[0]) position = parseInt(args[0])*1000; 32 | let seekPosition = dispatcher.shoukaku.position + position; 33 | if(seekPosition >= dispatcher.queue.current.length) return await client.util.msgReply(message.channel, `${client.emoji.cross} Cannot forward any futher more of this track.`, color); 34 | dispatcher.shoukaku.seekTo(seekPosition); 35 | return await client.util.msgReply(message, `${client.emoji.tick} Forwarded \`[ ${client.util.msToTime(Number(position))} ]\` to \`[ ${client.util.msToTime(Number(dispatcher.shoukaku.position))} / ${client.util.msToTime(Number(dispatcher.queue.current.length))} ]\``, color); 36 | } 37 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Rewind.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "rewind", 3 | description: "Rewind the track to given position.", 4 | category: "Music", 5 | cooldown: 10, 6 | usage: "[position]", 7 | aliases: ['backward'], 8 | examples: ["rewind", "rewind 3", "backward", "backward 5"], 9 | sub_commands: [], 10 | args: false, 11 | permissions: { 12 | client: [], 13 | user: [], 14 | dev: false, 15 | }, 16 | player: { voice: true, active: true, dj: true, }, 17 | 18 | /** 19 | * 20 | * @param {import("../../../Saavan")} client 21 | * @param {import("discord.js").Message} message 22 | * @param {String[]} args 23 | * @param {String} prefix 24 | * @param {String} color 25 | * @param {import('kazagumo').KazagumoPlayer} dispatcher 26 | */ 27 | 28 | async execute(client, message, args, prefix, color, dispatcher) { 29 | if (!dispatcher.queue.current.isSeekable) return await client.util.msgReply(message, `${client.emoji.cross} Unable to Rewind this track.`, color); 30 | let position = 10000; 31 | if(args[0]) position = parseInt(args[0])*1000; 32 | let seekPosition = dispatcher.shoukaku.position - position; 33 | if(seekPosition >= dispatcher.queue.current.length) return await client.util.msgReply(message.channel, `${client.emoji.cross} Cannot Rewind any futher more of this track.`, color); 34 | dispatcher.shoukaku.seekTo(seekPosition); 35 | return await client.util.msgReply(message, `${client.emoji.tick} Rewinded \`[ ${client.util.msToTime(Number(position))} ]\` to \`[ ${client.util.msToTime(Number(dispatcher.shoukaku.position))} / ${client.util.msToTime(Number(dispatcher.queue.current.length))} ]\``, color); 36 | } 37 | }) -------------------------------------------------------------------------------- /Src/Commands/Message/Music/Seek.js: -------------------------------------------------------------------------------- 1 | module.exports = new Object({ 2 | name: "seek", 3 | description: "Seeks the current playing track to given time.", 4 | category: "Music", 5 | cooldown: 15, 6 | usage: '