diff --git a/.replit b/.replit
index eb388a44e..95fd78844 100644
--- a/.replit
+++ b/.replit
@@ -1,2 +1,24 @@
-language="nodejs"
-run="npm start"
+run = "npm run start"
+
+[languages.typescript]
+pattern = "**/{*.ts,*.js,*.tsx,*.jsx}"
+syntax = "typescript"
+
+[languages.typescript.languageServer]
+start = [ "typescript-language-server", "--stdio" ]
+
+[packager]
+language = "nodejs"
+
+[packager.features]
+packageSearch = true
+guessImports = true
+
+[env]
+XDG_CONFIG_HOME = "/home/runner/.config"
+
+[nix]
+channel = "stable-21_11"
+
+[gitHubImport]
+requiredFiles = [".replit", "replit.nix", ".config"]
diff --git a/.swcrc b/.swcrc
index dc76be63b..7970a7082 100644
--- a/.swcrc
+++ b/.swcrc
@@ -1,4 +1,5 @@
{
+ "$schema": "https://json.schemastore.org/swcrc",
"jsc": {
"parser": {
"syntax": "typescript",
diff --git a/Procfile b/Procfile
deleted file mode 100644
index 9ebe8e88e..000000000
--- a/Procfile
+++ /dev/null
@@ -1 +0,0 @@
-worker: npm start
diff --git a/README.md b/README.md
index f158aab46..accfe26ae 100644
--- a/README.md
+++ b/README.md
@@ -34,10 +34,9 @@ $ npm start
## Hosting Setup
-### Heroku
-You can host this bot to make it stay online on Heroku.
-
-
+
+
+
### Glitch
You can use Glitch too for this project, featured with its code editor.
@@ -46,7 +45,7 @@ You can use Glitch too for this project, featured with its code editor.
2. Go to [glitch.com](https://glitch.com) and make an account
3. Click **New Project** then **Import from GitHub**, specify the pop-up field with `https://github.com//rawon` (without `<>`)
4. Please wait for a while, this process takes some minutes
-5. Find `.env` file and delete it, find `.env_example` file and rename it back to `.env`
+5. Find `.env` file and delete it, then find `.env_example` file and rename it to `.env`
6. After specifying `.env`, open **Tools** > **Terminal**
7. Type `refresh`, and track the process from **Logs**
diff --git a/app.json b/app.json
deleted file mode 100644
index 546d4c450..000000000
--- a/app.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "name": "Rawon",
- "description": "A simple powerful Discord music bot built to fulfill your production desires. Easy to use, with no coding required.",
- "logo": "https://api.clytage.org/assets/images/rawon.png",
- "env": {
- "DISCORD_TOKEN": {
- "description": "What is your Discord bot's token? | Example: NTE5NjQ2MjIxNTU2Nzc2OTcw.XAcEQQ.0gjhNbGeWBsKP6FVuIyZWlG2cMd",
- "required": true
- },
- "MAIN_PREFIX": {
- "description": "What should be the main prefix of your bot? | Example: !",
- "required": true,
- "value": "!"
- },
- "ALT_PREFIX": {
- "description": "What should be the alternative prefixes of your bot? | Example: \"?, {mention}\" | Formats: {mention} = @bot mention",
- "required": false,
- "value": "{mention}"
- },
- "EMBED_COLOR": {
- "description": "What should be your bot's embed color code? (hex) | Example: 22C9FF",
- "required": false,
- "value": "22C9FF"
- },
- "LOCALE": {
- "description": "What should be the language of your bot? | Example: en | Available: en, es, id",
- "required": false,
- "value": "en"
- },
- "ACTIVITIES": {
- "description": "Activity list, what text should be appear on your bot's status? | Example: \"Hello world!, My prefix is {prefix}\" | Formats: {prefix} = bot prefix, {userCount} = user amount, {textChannelCount} = text channel amount, {serverCount} = server amount, {playingCount} = amount of server playing music using the bot, {username} = bot username",
- "required": false,
- "value": "My default prefix is {prefix}, music with {userCount} users, {textChannelCount} text channels in {serverCount} guilds, 'Hello there, my name is {username}'"
- },
- "ACTIVITY_TYPES": {
- "description": "Activity type list. The order of this value is the same as ACTIVITIES. For example, first value of ACTIVITIES will use first value of this. | Example: \"PLAYING, COMPETING\" | Available: PLAYING, WATCHING, LISTENING, COMPETING",
- "required": false,
- "value": "PLAYING, LISTENING, WATCHING, PLAYING, COMPETING"
- },
- "MAIN_GUILD": {
- "description": "What is your server's ID? | Example: \"972407605295198258, 972407605295198258\"",
- "required": false
- },
- "STREAM_STRATEGY": {
- "description": "Which youtube downloader do you want to use? But if you use play-dl, it will support a few sites. | Example: play-dl | Available: play-dl, yt-dlp",
- "required": false,
- "value": "yt-dlp"
- },
- "ENABLE_SLASH_COMMAND": {
- "description": "Do you want to enable slash command support? | Example: yes",
- "required": false,
- "value": "yes"
- },
- "MUSIC_SELECTION_TYPE": {
- "description": "Which music selection type do you want to use? | Example: selectmenu | Available: message (just like in the previous version), selectmenu (uses discord selection menu)",
- "required": false,
- "value": "message"
- },
- "ENABLE_24_7_COMMAND": {
- "description": "Do you want to enable the 24/7 command? | Example: no",
- "required": false,
- "value": "no"
- },
- "STAY_IN_VC_AFTER_FINISHED": {
- "description": "Do you want to make your bot not leaving the voice channel after playing a song? | Example: no",
- "required": false,
- "value": "no"
- },
- "YES_EMOJI": {
- "description": "What should be your bot's emoji for every success sentence? | Example: ✅",
- "required": false,
- "value": "✅"
- },
- "NO_EMOJI": {
- "description": "What should be your bot's emoji for every failed sentence? | Example: ❌",
- "required": false,
- "value": "❌"
- }
- },
- "repository": "https://github.com/Clytage/rawon",
- "website": "https://rawon.clytage.org",
- "formation": {
- "worker": {
- "quantity": 1,
- "size": "free"
- }
- }
-}
diff --git a/index.js b/index.js
index a56b346cd..9da5e9cf7 100644
--- a/index.js
+++ b/index.js
@@ -1,52 +1,37 @@
import { downloadExecutable } from "./yt-dlp-utils";
+import { existsSync, readFileSync, writeFileSync, rmSync } from "fs";
import { execSync } from "child_process";
-import { existsSync, rmSync } from "fs";
import { resolve } from "path";
import { Server } from "https";
import module from "module";
-const isGlitch = (
- process.env.PROJECT_DOMAIN !== undefined &&
- process.env.PROJECT_INVITE_TOKEN !== undefined &&
- process.env.API_SERVER_EXTERNAL !== undefined &&
- process.env.PROJECT_REMIX_CHAIN !== undefined);
+const ensureEnv = arr => arr.every(x => process.env[x] !== undefined);
-const isReplit = (
- process.env.REPLIT_DB_URL !== undefined &&
- process.env.REPL_ID !== undefined &&
- process.env.REPL_IMAGE !== undefined &&
- process.env.REPL_LANGUAGE !== undefined &&
- process.env.REPL_OWNER !== undefined &&
- process.env.REPL_PUBKEYS !== undefined &&
- process.env.REPL_SLUG !== undefined)
+const isGlitch = ensureEnv([
+ "PROJECT_DOMAIN",
+ "PROJECT_INVITE_TOKEN",
+ "API_SERVER_EXTERNAL",
+ "PROJECT_REMIX_CHAIN"
+]);
-const isGitHub = (
- process.env.GITHUB_ENV !== undefined &&
- process.env.GITHUB_EVENT_PATH !== undefined &&
- process.env.GITHUB_REPOSITORY_OWNER !== undefined &&
- process.env.GITHUB_RETENTION_DAYS !== undefined &&
- process.env.GITHUB_HEAD_REF !== undefined &&
- process.env.GITHUB_GRAPHQL_URL !== undefined &&
- process.env.GITHUB_API_URL !== undefined &&
- process.env.GITHUB_WORKFLOW !== undefined &&
- process.env.GITHUB_RUN_ID !== undefined &&
- process.env.GITHUB_BASE_REF !== undefined &&
- process.env.GITHUB_ACTION_REPOSITORY !== undefined &&
- process.env.GITHUB_ACTION !== undefined &&
- process.env.GITHUB_RUN_NUMBER !== undefined &&
- process.env.GITHUB_REPOSITORY !== undefined &&
- process.env.GITHUB_ACTION_REF !== undefined &&
- process.env.GITHUB_ACTIONS !== undefined &&
- process.env.GITHUB_WORKSPACE !== undefined &&
- process.env.GITHUB_JOB !== undefined &&
- process.env.GITHUB_SHA !== undefined &&
- process.env.GITHUB_RUN_ATTEMPT !== undefined &&
- process.env.GITHUB_REF !== undefined &&
- process.env.GITHUB_ACTOR !== undefined &&
- process.env.GITHUB_PATH !== undefined &&
- process.env.GITHUB_EVENT_NAME !== undefined &&
- process.env.GITHUB_SERVER_URL !== undefined
-)
+const isReplit = ensureEnv([
+ "REPLIT_DB_URL",
+ "REPL_ID",
+ "REPL_IMAGE",
+ "REPL_LANGUAGE",
+ "REPL_OWNER",
+ "REPL_PUBKEYS",
+ "REPL_SLUG"
+]);
+
+const isGitHub = ensureEnv([
+ "GITHUB_ENV",
+ "GITHUB_REPOSITORY_OWNER",
+ "GITHUB_HEAD_REF",
+ "GITHUB_API_URL",
+ "GITHUB_REPOSITORY",
+ "GITHUB_SERVER_URL"
+]);
function npmInstall(deleteDir = false, forceInstall = false, additionalArgs = []) {
if (deleteDir) {
@@ -54,7 +39,8 @@ function npmInstall(deleteDir = false, forceInstall = false, additionalArgs = []
if (existsSync(modulesPath)) {
rmSync(modulesPath, {
- recursive: true
+ recursive: true,
+ force: true
});
}
}
@@ -63,6 +49,17 @@ function npmInstall(deleteDir = false, forceInstall = false, additionalArgs = []
}
if (isGlitch) {
+ const gitIgnorePath = resolve(process.cwd(), ".gitignore");
+ try {
+ const data = readFileSync(gitIgnorePath, "utf8").toString();
+ if (data.includes("dev.env")) {
+ writeFileSync(gitIgnorePath, data.replace("\ndev.env", ""));
+ console.info("Removed dev.env from .gitignore");
+ }
+ } catch {
+ console.error("Failed to remove dev.env from .gitignore");
+ }
+
try {
console.info("[INFO] Trying to re-install modules...");
npmInstall();
@@ -84,24 +81,13 @@ if (isGlitch) {
}
}
-if (isReplit) {
- console.warn("[WARN] We haven't added stable support for running this bot using Replit, bugs and errors may come up.");
-
- if (Number(process.versions.node.split(".")[0]) < 16) {
- console.info("[INFO] This Replit doesn't use Node.js v16 or newer, trying to install Node.js v16...");
- execSync(`npm i --save-dev node@16.6.1 && npm config set prefix=$(pwd)/node_modules/node && export PATH=$(pwd)/node_modules/node/bin:$PATH`);
- console.info("[INFO] Node.js v16 has been installed, please restart the bot.");
- process.exit(0);
- }
-}
-
if (isGitHub) {
console.warn("[WARN] Running this bot using GitHub is not recommended.");
}
const require = module.createRequire(import.meta.url);
-if (!isGlitch) {
+if (!isGlitch && !isReplit) {
try {
require("ffmpeg-static");
} catch {
diff --git a/package-lock.json b/package-lock.json
index 79c36b41c..2dac8d875 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "rawon",
- "version": "3.0.0",
+ "version": "3.1.0-dev",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "rawon",
- "version": "3.0.0",
+ "version": "3.1.0-dev",
"license": "BSD-3-Clause",
"dependencies": {
"@discordjs/voice": "^0.11.0",
@@ -108,6 +108,11 @@
"node": ">=16.9.0"
}
},
+ "node_modules/@discordjs/voice/node_modules/discord-api-types": {
+ "version": "0.37.12",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.12.tgz",
+ "integrity": "sha512-SMBP4V6/A9mE7shBQAiTxNWnQlYTdiKMGvc7G23neayxaTJeFYh5FviJSWUa0BTdXcph1h/jT03Nbyv5XgZkzw=="
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@@ -2791,6 +2796,12 @@
"prism-media": "^1.3.4",
"tslib": "^2.4.0",
"ws": "^8.8.1"
+ },
+ "dependencies": {
+ "discord-api-types": {
+ "version": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.12.tgz",
+ "integrity": "sha512-SMBP4V6/A9mE7shBQAiTxNWnQlYTdiKMGvc7G23neayxaTJeFYh5FviJSWUa0BTdXcph1h/jT03Nbyv5XgZkzw=="
+ }
}
},
"@eslint/eslintrc": {
diff --git a/package.json b/package.json
index b32f49404..36d0e885d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rawon",
- "version": "3.0.0",
+ "version": "3.1.0",
"description": "A simple powerful Discord music bot built to fulfill your production desires. Easy to use, with no coding required.",
"main": "index.js",
"type": "module",
diff --git a/replit.nix b/replit.nix
new file mode 100644
index 000000000..6dd47d18d
--- /dev/null
+++ b/replit.nix
@@ -0,0 +1,12 @@
+{ pkgs }: {
+ deps = [
+ pkgs.python38
+ pkgs.ffmpeg.bin
+ pkgs.yarn
+ pkgs.esbuild
+ pkgs.nodejs-16_x
+
+ pkgs.nodePackages.typescript
+ pkgs.nodePackages.typescript-language-server
+ ];
+}
diff --git a/src/commands/moderation/ModLogsCommand.ts b/src/commands/moderation/ModLogsCommand.ts
index 950d35015..df36c95fb 100644
--- a/src/commands/moderation/ModLogsCommand.ts
+++ b/src/commands/moderation/ModLogsCommand.ts
@@ -103,7 +103,9 @@ export class ModLogsCommand extends BaseCommand {
ctx.reply({
embeds: [
createEmbed("info")
- .setAuthor(i18n.__("commands.moderation.modlogs.embedTitle"))
+ .setAuthor({
+ name: i18n.__("commands.moderation.modlogs.embedTitle")
+ })
.addField(
`${this.client.config.mainPrefix}modlogs enable`,
i18n.__("commands.moderation.modlogs.slashEnableDescription")
diff --git a/src/commands/music/DJCommand.ts b/src/commands/music/DJCommand.ts
index 597be4d3c..37f92c6d5 100644
--- a/src/commands/music/DJCommand.ts
+++ b/src/commands/music/DJCommand.ts
@@ -43,7 +43,9 @@ export class DJCommand extends BaseCommand {
ctx.reply({
embeds: [
createEmbed("info")
- .setAuthor(i18n.__("commands.music.dj.embedTitle"))
+ .setAuthor({
+ name: i18n.__("commands.music.dj.embedTitle")
+ })
.addField(
`${this.client.config.mainPrefix}dj enable`,
i18n.__("commands.music.dj.slashEnableDescription")
diff --git a/src/commands/music/NowPlayingCommand.ts b/src/commands/music/NowPlayingCommand.ts
index 541d8ddb2..71c266565 100644
--- a/src/commands/music/NowPlayingCommand.ts
+++ b/src/commands/music/NowPlayingCommand.ts
@@ -1,3 +1,5 @@
+import { createProgressBar } from "../../utils/functions/createProgressBar";
+import { normalizeTime } from "../../utils/functions/normalizeTime";
import { CommandContext } from "../../structures/CommandContext";
import { createEmbed } from "../../utils/functions/createEmbed";
import { haveQueue } from "../../utils/decorators/MusicUtil";
@@ -8,7 +10,7 @@ import i18n from "../../config";
import { MessageActionRow, MessageButton, MessageEmbed } from "discord.js";
import { AudioPlayerState, AudioResource } from "@discordjs/voice";
-@Command({
+@Command({
aliases: ["np"],
description: i18n.__("commands.music.nowplaying.description"),
name: "nowplaying",
@@ -21,22 +23,25 @@ export class NowPlayingCommand extends BaseCommand {
@haveQueue
public async execute(ctx: CommandContext): Promise {
function getEmbed(): MessageEmbed {
- const song = (
- (
- ctx.guild?.queue?.player.state as
- | (AudioPlayerState & {
- resource: AudioResource | undefined;
- })
- | undefined
- )?.resource?.metadata as QueueSong | undefined
- )?.song;
+ const res = (ctx.guild?.queue?.player.state as
+ | (AudioPlayerState & {
+ resource: AudioResource | undefined;
+ })
+ | undefined)?.resource;
+ const song = (res?.metadata as QueueSong | undefined)?.song;
- return createEmbed(
+ const embed = createEmbed(
"info",
- `${ctx.guild?.queue?.playing ? "▶" : "⏸"} **|** ${
- song ? `**[${song.title}](${song.url})**` : i18n.__("commands.music.nowplaying.emptyQueue")
- }`
+ `${ctx.guild?.queue?.playing ? "▶" : "⏸"} **|** `
).setThumbnail(song?.thumbnail ?? "https://api.clytage.org/assets/images/icon.png");
+
+ const curr = ~~(res!.playbackDuration / 1000);
+ embed.description += song
+ ? `**[${song.title}](${song.url})**\n` +
+ `${normalizeTime(curr)} ${createProgressBar(curr, song.duration)} ${normalizeTime(song.duration)}`
+ : i18n.__("commands.music.nowplaying.emptyQueue")
+
+ return embed;
}
const buttons = new MessageActionRow().addComponents(
diff --git a/src/commands/music/VolumeCommand.ts b/src/commands/music/VolumeCommand.ts
index a4a5a3d3f..4007910b0 100644
--- a/src/commands/music/VolumeCommand.ts
+++ b/src/commands/music/VolumeCommand.ts
@@ -1,10 +1,11 @@
+import { createProgressBar } from "../../utils/functions/createProgressBar";
import { inVC, sameVC, validVC } from "../../utils/decorators/MusicUtil";
import { CommandContext } from "../../structures/CommandContext";
import { createEmbed } from "../../utils/functions/createEmbed";
import { BaseCommand } from "../../structures/BaseCommand";
import { Command } from "../../utils/decorators/Command";
import i18n from "../../config";
-import { Message } from "discord.js";
+import { Message, MessageActionRow, MessageButton } from "discord.js";
@Command({
aliases: ["vol"],
@@ -26,21 +27,83 @@ export class VolumeCommand extends BaseCommand {
@inVC
@validVC
@sameVC
- public execute(ctx: CommandContext): Promise | undefined {
+ public async execute(ctx: CommandContext): Promise {
const volume = Number(ctx.args[0] ?? ctx.options?.getNumber("volume", false));
const current = ctx.guild!.queue!.volume;
if (isNaN(volume)) {
- return ctx.reply({
+ const buttons = new MessageActionRow().addComponents(
+ new MessageButton()
+ .setCustomId("10")
+ .setLabel("10%")
+ .setStyle("PRIMARY"),
+ new MessageButton()
+ .setCustomId("25")
+ .setLabel("25%")
+ .setStyle("PRIMARY"),
+ new MessageButton()
+ .setCustomId("50")
+ .setLabel("50%")
+ .setStyle("PRIMARY"),
+ new MessageButton()
+ .setCustomId("75")
+ .setLabel("75%")
+ .setStyle("PRIMARY"),
+ new MessageButton()
+ .setCustomId("100")
+ .setLabel("100%")
+ .setStyle("PRIMARY")
+ );
+
+ const msg = await ctx.reply({
embeds: [
createEmbed(
"info",
`🔊 **|** ${i18n.__mf("commands.music.volume.currentVolume", {
volume: `\`${current}\``
- })}`
+ })}\n${current}% ${createProgressBar(current, 100)} 100%`
).setFooter({ text: i18n.__("commands.music.volume.changeVolume") })
- ]
+ ],
+ components: [buttons]
});
+
+ const collector = msg.createMessageComponentCollector({
+ filter: i => i.isButton() && i.user.id === ctx.author.id,
+ idle: 30000
+ });
+
+ collector.on("collect", async i => {
+ const newContext = new CommandContext(i, [i.customId]);
+ const newVolume = Number(i.customId);
+ await this.execute(newContext);
+
+ void msg.edit({
+ embeds: [
+ createEmbed(
+ "info",
+ `🔊 **|** ${i18n.__mf("commands.music.volume.currentVolume", {
+ volume: `\`${newVolume}\``
+ })}\n${newVolume}% ${createProgressBar(newVolume, 100)} 100%`
+ ).setFooter({ text: i18n.__("commands.music.volume.changeVolume") })
+ ],
+ components: [buttons]
+ });
+ })
+ .on("end", () => {
+ const cur = ctx.guild!.queue!.volume;
+ void msg.edit({
+ embeds: [
+ createEmbed(
+ "info",
+ `🔊 **|** ${i18n.__mf("commands.music.volume.currentVolume", {
+ volume: `\`${cur}\``
+ })}\n${cur}% ${createProgressBar(cur, 100)} 100%`
+ ).setFooter({ text: i18n.__("commands.music.volume.changeVolume") })
+ ],
+ components: []
+ });
+ });
+ return;
}
if (volume <= 0) {
return ctx.reply({
diff --git a/src/structures/ServerQueue.ts b/src/structures/ServerQueue.ts
index 86a3de700..510734705 100644
--- a/src/structures/ServerQueue.ts
+++ b/src/structures/ServerQueue.ts
@@ -47,7 +47,6 @@ export class ServerQueue {
});
this.player
- // @ts-expect-error: Ignore a compile error due to typed emitter error
.on("stateChange", (oldState, newState) => {
if (newState.status === AudioPlayerStatus.Playing && oldState.status !== AudioPlayerStatus.Paused) {
newState.resource.volume?.setVolumeLogarithmic(this.volume / 100);
diff --git a/src/utils/functions/createProgressBar.ts b/src/utils/functions/createProgressBar.ts
new file mode 100644
index 000000000..91d408838
--- /dev/null
+++ b/src/utils/functions/createProgressBar.ts
@@ -0,0 +1,5 @@
+export function createProgressBar(current: number, total: number): string {
+ const pos = Math.ceil(current / total * 10) || 1;
+
+ return `${"━".repeat(pos - 1)}⬤${"─".repeat(10 - pos)}`;
+}
diff --git a/src/utils/functions/normalizeTime.ts b/src/utils/functions/normalizeTime.ts
new file mode 100644
index 000000000..2928b4e73
--- /dev/null
+++ b/src/utils/functions/normalizeTime.ts
@@ -0,0 +1,12 @@
+function tS(num: number): string {
+ const s = num.toString();
+ return s.length > 1 ? s : `0${s}`;
+}
+
+export function normalizeTime(second: number): string {
+ const h = Math.floor(second / 3600);
+ const m = Math.floor((second % 3600) / 60);
+ const s = Math.floor(second % 60);
+
+ return `${h > 0 ? `${tS(h)}:` : ""}${tS(m)}:${tS(s)}`;
+}
diff --git a/src/utils/handlers/general/handleVideos.ts b/src/utils/handlers/general/handleVideos.ts
index c8a7d12da..51b5952a4 100644
--- a/src/utils/handlers/general/handleVideos.ts
+++ b/src/utils/handlers/general/handleVideos.ts
@@ -44,7 +44,9 @@ export async function handleVideos(
author: ctx.author.id,
edit: (i, e, p) => {
e.setDescription(`\`\`\`\n${p}\`\`\``)
- .setAuthor(opening)
+ .setAuthor({
+ name: opening
+ })
.setFooter({
text: `• ${i18n.__mf("reusable.pageFooter", { actual: i + 1, total: pages.length })}`
});
diff --git a/src/utils/structures/JSONDataManager.ts b/src/utils/structures/JSONDataManager.ts
index 5993a47b9..e93837d53 100644
--- a/src/utils/structures/JSONDataManager.ts
+++ b/src/utils/structures/JSONDataManager.ts
@@ -16,7 +16,7 @@ export class JSONDataManager {
public async save(data: () => T): Promise {
await this.manager.add(async () => {
const dat = data();
- await writeFile(this.fileDir, JSON.stringify(dat, null, 4));
+ await writeFile(this.fileDir, JSON.stringify(dat));
return undefined;
});
diff --git a/src/utils/structures/SongManager.ts b/src/utils/structures/SongManager.ts
index 5f3210394..c51d5afdc 100644
--- a/src/utils/structures/SongManager.ts
+++ b/src/utils/structures/SongManager.ts
@@ -3,6 +3,8 @@ import { Rawon } from "../../structures/Rawon";
import { Collection, GuildMember, Snowflake, SnowflakeUtil } from "discord.js";
export class SongManager extends Collection {
+ private id = 0;
+
public constructor(public readonly client: Rawon, public readonly guild: GuildMember["guild"]) {
super();
}
@@ -10,7 +12,7 @@ export class SongManager extends Collection {
public addSong(song: Song, requester: GuildMember): Snowflake {
const key = SnowflakeUtil.generate();
const data: QueueSong = {
- index: Date.now(),
+ index: this.id++,
key,
requester,
song