From 6f3847138bf73c4fc3e652ce957446b9266ca990 Mon Sep 17 00:00:00 2001 From: Raphix Date: Tue, 25 Feb 2025 16:39:18 +0100 Subject: [PATCH 1/6] Version 0.2.0-alpha - Ajout du Player --- backend/package-lock.json | 4596 ++++++++++++++++++++++- backend/package.json | 12 +- backend/src/discord/Command.js | 8 + backend/src/discord/CommandUpdater.js | 4 - backend/src/discord/Commands/Help.js | 2 +- backend/src/discord/Commands/Media.js | 51 + backend/src/discord/Commands/Pause.js | 24 + backend/src/discord/Commands/Play.js | 15 + backend/src/discord/Commands/Restart.js | 20 + backend/src/discord/Embed.js | 12 +- backend/src/player/Finder.js | 0 backend/src/player/List.js | 173 + backend/src/player/Method/Media.js | 18 + backend/src/player/Player.js | 126 + backend/src/player/Song.js | 77 + backend/src/utils/Database/Database.js | 3 + backend/src/utils/GlobalVars.js | 3 +- backend/src/utils/Maintenance.js | 11 + backend/src/utils/TimeConverter.js | 32 + 19 files changed, 5175 insertions(+), 12 deletions(-) create mode 100644 backend/src/discord/Commands/Media.js create mode 100644 backend/src/discord/Commands/Pause.js create mode 100644 backend/src/discord/Commands/Play.js create mode 100644 backend/src/discord/Commands/Restart.js create mode 100644 backend/src/player/Finder.js create mode 100644 backend/src/player/List.js create mode 100644 backend/src/player/Method/Media.js create mode 100644 backend/src/player/Player.js create mode 100644 backend/src/player/Song.js create mode 100644 backend/src/utils/Maintenance.js create mode 100644 backend/src/utils/TimeConverter.js diff --git a/backend/package-lock.json b/backend/package-lock.json index 6c8dc6d..4965292 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,22 +1,87 @@ { "name": "chopin-backend", - "version": "0.1.0", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "chopin-backend", - "version": "0.1.0-alpha1", + "version": "0.2.0", "license": "ISC", "dependencies": { + "@discordjs/voice": "^0.18.0", "cors": "^2.8.5", + "discord-player": "^7.1.0", "discord.js": "^14.18.0", "express": "^4.21.2", + "ffmpeg-static": "^5.2.0", + "ffprobe": "^1.1.2", + "ffprobe-static": "^3.1.0", + "libsodium-wrappers": "^0.7.15", "loguix": "^1.4.2", "nodemon": "^3.1.9", + "pm2": "^5.4.3", "socket.io": "^4.8.1", "uuid": "^11.1.0", - "webmetrik": "^0.1.4" + "webmetrik": "^0.1.4", + "ytdl-core": "^4.11.5" + } + }, + "node_modules/@derhuerst/http-basic": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.4.tgz", + "integrity": "sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==", + "license": "MIT", + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^2.0.0", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@discord-player/equalizer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@discord-player/equalizer/-/equalizer-7.1.0.tgz", + "integrity": "sha512-bF5MRDDcm0BeZbTHMcG3UHdTZKHC7w21iEqrjt89KDzis6qz9oRsRWIG1w0NH3UYSCf1X3jdS/WiKdMqGHmmiA==", + "license": "MIT" + }, + "node_modules/@discord-player/extractor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@discord-player/extractor/-/extractor-7.1.0.tgz", + "integrity": "sha512-/ttNFkN0hacSS/KJNcPP8Dvk1W8+QGbdlbtJNIPHO1oBfEMazs6BimokMG5eCVmSLPb2MaWPGKTjhoQzHLlBlw==", + "license": "MIT", + "peer": true, + "dependencies": { + "file-type": "^16.5.4", + "isomorphic-unfetch": "^4.0.2", + "node-html-parser": "^6.1.4", + "reverbnation-scraper": "^2.0.0", + "soundcloud.ts": "^0.5.2", + "spotify-url-info": "^3.2.6" + } + }, + "node_modules/@discord-player/ffmpeg": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@discord-player/ffmpeg/-/ffmpeg-7.1.0.tgz", + "integrity": "sha512-4pKY6S5AwrM2aUWLklELOljKH1S2M2CN4vcel/15U6OGmg1sCJEWWVxLNvWIek/zH5Ua2yU4EN8gNxzZbjq/pw==", + "license": "MIT" + }, + "node_modules/@discord-player/opus": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@discord-player/opus/-/opus-7.1.0.tgz", + "integrity": "sha512-kQdkiCdyPKiKt+2YRgYfx8ymS8ZesvRZXC5Ok8UUoSYVl658yAxwLPlDrziZnVqcuSvGjnAFTcwAZcU00iuRZg==", + "license": "MIT" + }, + "node_modules/@discord-player/utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@discord-player/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-Glaj91FRoi6GRHLQ+rDZWmWL8GEnnUl1OXotIZ1A66flk/C+p99KZahBdHV9u24QZrU5mL+yqGYxqqIQYf4rxQ==", + "license": "MIT", + "dependencies": { + "@discordjs/collection": "^1.1.0" } }, "node_modules/@discordjs/builders": { @@ -111,6 +176,46 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@discordjs/voice": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.18.0.tgz", + "integrity": "sha512-BvX6+VJE5/vhD9azV9vrZEt9hL1G+GlOdsQaVl5iv9n87fkXjf3cSwllhR3GdaUC8m6dqT8umXIWtn3yCu4afg==", + "license": "Apache-2.0", + "dependencies": { + "@types/ws": "^8.5.12", + "discord-api-types": "^0.37.103", + "prism-media": "^1.3.5", + "tslib": "^2.6.3", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/voice/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@discordjs/ws": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.1.tgz", @@ -146,6 +251,1023 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pm2/agent": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.4.tgz", + "integrity": "sha512-n7WYvvTJhHLS2oBb1PjOtgLpMhgImOq8sXkPBw6smeg9LJBWZjiEgPKOpR8mn9UJZsB5P3W4V/MyvNnp31LKeA==", + "license": "AGPL-3.0", + "dependencies": { + "async": "~3.2.0", + "chalk": "~3.0.0", + "dayjs": "~1.8.24", + "debug": "~4.3.1", + "eventemitter2": "~5.0.1", + "fast-json-patch": "^3.0.0-1", + "fclone": "~1.0.11", + "nssocket": "0.6.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.0", + "proxy-agent": "~6.3.0", + "semver": "~7.5.0", + "ws": "~7.5.10" + } + }, + "node_modules/@pm2/agent/node_modules/dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==", + "license": "MIT" + }, + "node_modules/@pm2/agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@pm2/agent/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pm2/agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@pm2/agent/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pm2/agent/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@pm2/io": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-6.0.1.tgz", + "integrity": "sha512-KiA+shC6sULQAr9mGZ1pg+6KVW9MF8NpG99x26Lf/082/Qy8qsTCtnJy+HQReW1A9Rdf0C/404cz0RZGZro+IA==", + "license": "Apache-2", + "dependencies": { + "async": "~2.6.1", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "require-in-the-middle": "^5.0.0", + "semver": "~7.5.4", + "shimmer": "^1.2.0", + "signal-exit": "^3.0.3", + "tslib": "1.9.3" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@pm2/io/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@pm2/io/node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, + "node_modules/@pm2/io/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pm2/io/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@pm2/io/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pm2/io/node_modules/tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "license": "Apache-2.0" + }, + "node_modules/@pm2/js-api": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.8.0.tgz", + "integrity": "sha512-nmWzrA/BQZik3VBz+npRcNIu01kdBhWL0mxKmP1ciF/gTcujPTQqt027N9fc1pK9ERM8RipFhymw7RcmCyOEYA==", + "license": "Apache-2", + "dependencies": { + "async": "^2.6.3", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "extrareqp2": "^1.0.0", + "ws": "^7.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@pm2/js-api/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/js-api/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@pm2/js-api/node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, + "node_modules/@pm2/js-api/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@pm2/js-api/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@pm2/pm2-version-check": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", + "integrity": "sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.1" + } + }, + "node_modules/@pm2/pm2-version-check/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@pm2/pm2-version-check/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", + "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sapphire/async-queue": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", @@ -185,6 +1307,19 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT", + "peer": true + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", @@ -194,6 +1329,12 @@ "@types/node": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.13.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", @@ -222,6 +1363,28 @@ "npm": ">=7.0.0" } }, + "node_modules/@web-scrobbler/metadata-filter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@web-scrobbler/metadata-filter/-/metadata-filter-3.2.0.tgz", + "integrity": "sha512-K2Wkq9AOJkgj4Hk9g0flKnNWYkJy1GTPpHTgpNLU5OXaXgqPKLyrtb62M1cIxMN3ESH6XGvPKM92VEl/Gc3Rog==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "peer": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -235,6 +1398,72 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/amp": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", + "integrity": "sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==", + "license": "MIT" + }, + "node_modules/amp-message": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", + "integrity": "sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==", + "license": "MIT", + "dependencies": { + "amp": "0.3.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -248,18 +1477,62 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -269,6 +1542,15 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -281,6 +1563,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==", + "license": "MIT", + "bin": { + "blessed": "bin/tput.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/bodec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", + "integrity": "sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==", + "license": "MIT" + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -305,6 +1616,13 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC", + "peer": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -327,6 +1645,51 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -336,6 +1699,15 @@ "node": ">= 0.8" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -365,6 +1737,52 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "license": "Apache-2.0" + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==", + "license": "MIT/X11" + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -389,12 +1807,71 @@ "fsevents": "~2.3.2" } }, + "node_modules/cli-tableau": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", + "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", + "dependencies": { + "chalk": "3.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -444,6 +1921,77 @@ "node": ">= 0.10" } }, + "node_modules/croner": { + "version": "4.1.97", + "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", + "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/culvert": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", + "integrity": "sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -453,6 +2001,29 @@ "ms": "2.0.0" } }, + "node_modules/deferential": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/deferential/-/deferential-1.0.0.tgz", + "integrity": "sha512-QyFNvptDP8bypD6WK6ZOXFSBHN6CFLZmQ59QyvRGDvN9+DoX01mxw28QrJwSVPrrwnMWqHgTRiXybH6Y0cBbWw==", + "license": "BSD-3-Clause", + "dependencies": { + "native-promise-only": "^0.8.1" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -478,6 +2049,41 @@ "integrity": "sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg==", "license": "MIT" }, + "node_modules/discord-player": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/discord-player/-/discord-player-7.1.0.tgz", + "integrity": "sha512-bnEfvx5Ui0jLQjBw/17q8iYlw9C5aAjLiJ8379GQeF3Ln8ddeKRphAvthlKHBmq48aMySARwSxxL8147kQykyA==", + "license": "MIT", + "dependencies": { + "@discord-player/equalizer": "^7.1.0", + "@discord-player/ffmpeg": "^7.1.0", + "@discord-player/utils": "^7.1.0", + "@web-scrobbler/metadata-filter": "^3.1.0", + "discord-voip": "^7.1.0", + "libsodium-wrappers": "^0.7.13" + }, + "funding": { + "url": "https://github.com/Androz2091/discord-player?sponsor=1" + }, + "peerDependencies": { + "@discord-player/extractor": "^7.1.0", + "mediaplex": "^1" + } + }, + "node_modules/discord-voip": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/discord-voip/-/discord-voip-7.1.0.tgz", + "integrity": "sha512-6aQgI3QUj0Ee5tqaAV+pgBcOrgnkBh5/1UxAqbKMYQinQNs9LEZA7OoCxlWdiJVpVM2c1AxCdqhfryQMvM10+A==", + "license": "MIT", + "dependencies": { + "@discord-player/ffmpeg": "^7.1.0", + "@discord-player/opus": "^7.1.0", + "@discord-player/utils": "^7.1.0", + "@types/ws": "^8.5.10", + "tsup": "^8.3.5", + "typescript": "^5.5.4" + } + }, "node_modules/discord.js": { "version": "14.18.0", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.18.0.tgz", @@ -504,6 +2110,65 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -518,12 +2183,24 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -594,6 +2271,40 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -624,12 +2335,116 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -639,6 +2454,32 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/express": { "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", @@ -685,12 +2526,156 @@ "url": "https://opencollective.com/express" } }, + "node_modules/extrareqp2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extrareqp2/-/extrareqp2-1.0.0.tgz", + "integrity": "sha512-Gum0g1QYb6wpPJCVypWP3bbIuaibcFiJcpuPM10YSXp/tzqi84x9PJageob+eN4xVRIOto4wjSGNLyMD54D2xA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" + }, + "node_modules/fclone": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", + "integrity": "sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/ffmpeg-static": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz", + "integrity": "sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==", + "hasInstallScript": true, + "license": "GPL-3.0-or-later", + "dependencies": { + "@derhuerst/http-basic": "^8.2.0", + "env-paths": "^2.2.0", + "https-proxy-agent": "^5.0.0", + "progress": "^2.0.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/ffmpeg-static/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ffmpeg-static/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ffmpeg-static/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ffmpeg-static/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/ffprobe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ffprobe/-/ffprobe-1.1.2.tgz", + "integrity": "sha512-a+oTbhyeM7Z8PRy+mpzmVUAnATZT7z4BO94HSKeqHupdmjiKZ1djzcZkyoyXA21zCOCG7oVRrsBMmvvtmzoz4g==", + "license": "BSD-3-Clause", + "dependencies": { + "bl": "^4.0.3", + "deferential": "^1.0.0", + "JSONStream": "^1.3.5" + } + }, + "node_modules/ffprobe-static": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ffprobe-static/-/ffprobe-static-3.1.0.tgz", + "integrity": "sha512-Dvpa9uhVMOYivhHKWLGDoa512J751qN1WZAIO+Xw4L/mrUSPxS4DApzSUDbCFE/LUq2+xYnznEahTd63AqBSpA==", + "license": "MIT" + }, + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "license": "MIT", + "peer": true, + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -721,6 +2706,67 @@ "node": ">= 0.8" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -799,6 +2845,75 @@ "node": ">= 0.4" } }, + "node_modules/get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/get-uri/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/git-node-fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", + "integrity": "sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ==", + "license": "MIT" + }, + "node_modules/git-sha1": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", + "integrity": "sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -811,6 +2926,30 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -856,6 +2995,23 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "peer": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/himalaya": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.0.tgz", + "integrity": "sha512-LLase1dHCRMel68/HZTFft0N0wti0epHr3nNY7ynpLbyZpmrKMQ8YIpiOV77TM97cNpC8Wb2n6f66IRggwdWPw==", + "license": "ISC", + "peer": true + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -872,6 +3028,93 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "license": "MIT", + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -884,6 +3127,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -896,6 +3159,31 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -917,6 +3205,21 @@ "node": ">=8" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -926,6 +3229,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -947,6 +3259,160 @@ "node": ">=0.12.0" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isomorphic-unfetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-4.0.2.tgz", + "integrity": "sha512-1Yd+CF/7al18/N2BDbsLBcp6RO3tucSW+jcLq24dqdX5MNbCNTw1z4BsGsp4zNmjr/Izm2cs/cEqZPp4kvWSCA==", + "license": "MIT", + "peer": true, + "dependencies": { + "node-fetch": "^3.2.0", + "unfetch": "^5.0.0" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-git": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", + "integrity": "sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==", + "license": "MIT", + "dependencies": { + "bodec": "^0.1.0", + "culvert": "^0.1.2", + "git-sha1": "^0.1.2", + "pako": "^0.2.5" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC", + "optional": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==", + "license": "MIT", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/libsodium": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.15.tgz", + "integrity": "sha512-sZwRknt/tUpE2AwzHq3jEyUU5uvIZHtSssktXq7owd++3CSgn8RGrv6UZJJBpP7+iBghBqe7Z06/2M31rI2NKw==", + "license": "ISC" + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.15.tgz", + "integrity": "sha512-E4anqJQwcfiC6+Yrl01C1m8p99wEhLmJSs0VQqST66SbQXXBoaJY0pF4BNjRYa/sOQAxx6lXAaAFIlx+15tXJQ==", + "license": "ISC", + "dependencies": { + "libsodium": "^0.7.15" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -959,12 +3425,40 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "license": "MIT" }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "license": "MIT" + }, "node_modules/loguix": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/loguix/-/loguix-1.4.2.tgz", "integrity": "sha512-fWp699F5Dqszpnriwotr3XvsaPXYAjmV3X2L4tmqUXgwHggvx1Fak1z3Ac7CeuVdIdYY5l85UQrEYPmhAb+IUw==", "license": "ISC" }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/m3u8stream": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz", + "integrity": "sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==", + "license": "MIT", + "dependencies": { + "miniget": "^4.2.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/magic-bytes.js": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", @@ -989,6 +3483,303 @@ "node": ">= 0.6" } }, + "node_modules/mediaplex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex/-/mediaplex-1.0.0.tgz", + "integrity": "sha512-2vj7Px34rNUmHKilpAagU7jNhKIyoG8/wZ/cvJQzUdhvul8ef03NOK3No3LWVZEF1Pi27VSFOwBvawli/B86hA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "mediaplex-android-arm-eabi": "1.0.0", + "mediaplex-android-arm64": "1.0.0", + "mediaplex-darwin-arm64": "1.0.0", + "mediaplex-darwin-universal": "1.0.0", + "mediaplex-darwin-x64": "1.0.0", + "mediaplex-freebsd-x64": "1.0.0", + "mediaplex-linux-arm-gnueabihf": "1.0.0", + "mediaplex-linux-arm-musleabihf": "1.0.0", + "mediaplex-linux-arm64-gnu": "1.0.0", + "mediaplex-linux-arm64-musl": "1.0.0", + "mediaplex-linux-riscv64-gnu": "1.0.0", + "mediaplex-linux-x64-gnu": "1.0.0", + "mediaplex-linux-x64-musl": "1.0.0", + "mediaplex-win32-arm64-msvc": "1.0.0", + "mediaplex-win32-ia32-msvc": "1.0.0", + "mediaplex-win32-x64-msvc": "1.0.0" + } + }, + "node_modules/mediaplex-android-arm-eabi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-android-arm-eabi/-/mediaplex-android-arm-eabi-1.0.0.tgz", + "integrity": "sha512-/Ec33NNTeYxDLePRewOnjt82yVjwFy2monHk4OFk/wov7gDXvNCwSsLVRzgQgVQ2QAxmEND75Cx1nlyMWRjfFQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-android-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-android-arm64/-/mediaplex-android-arm64-1.0.0.tgz", + "integrity": "sha512-qisiHCK6HiRhw9qKr99yGFqtJHV9w///Vg5sc3RCA5FpEZOgK/EPkE3XEyVaBXux6XzU9lF5KeCfHuWW/rZEGQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-darwin-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-darwin-arm64/-/mediaplex-darwin-arm64-1.0.0.tgz", + "integrity": "sha512-uux5Lb2RfE+51Xz+wf0fwBpx14k66eexeMjw2IWpEK5LMIU8QI1AU+ag/ocIxEf6yIdu/Dj8b4zaxxfr2B7usw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-darwin-universal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-darwin-universal/-/mediaplex-darwin-universal-1.0.0.tgz", + "integrity": "sha512-dwFIEZHuH7zsnAhAqP77Pc7i/YWMgXnDT2hBxF9/K5/wGxlV1HtdpJfY9Pug3A5SiCpb9YwQy5VGhW0se/aqIw==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-darwin-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-darwin-x64/-/mediaplex-darwin-x64-1.0.0.tgz", + "integrity": "sha512-pAiCp8vPNb1b103v2xV3x6W9SQZifg6+5TGZOczlltpEbANWSy5112MqEwCM3XBohOHcal1zLC2qxdaHM8edhw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-freebsd-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-freebsd-x64/-/mediaplex-freebsd-x64-1.0.0.tgz", + "integrity": "sha512-9lRsE3GumCRODm6OWBtfRyFCgC5mfLPVl+4miR52/+PVw2ABrdV+lnz2cKZDUfnmwxDGV1fTG6QMxs5D3xcuZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-arm-gnueabihf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-arm-gnueabihf/-/mediaplex-linux-arm-gnueabihf-1.0.0.tgz", + "integrity": "sha512-mDBD2d/87CdmR4P0IUYyznzEmBoar7p4cbQiyT44voZ8LIG9w0RWHpP1r5zprbnt73YRrZwJTYhurF7mVixgRQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-arm-musleabihf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-arm-musleabihf/-/mediaplex-linux-arm-musleabihf-1.0.0.tgz", + "integrity": "sha512-Jzu8hRxS9vjbgRh92sfPV++wHHUHVGMRmHS0YAxzLso73IAVKMArhsVIEcTDVVN4/yF4D0HzD63AX6M3dgeoCA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-arm64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-arm64-gnu/-/mediaplex-linux-arm64-gnu-1.0.0.tgz", + "integrity": "sha512-y6NXkTtjFSDqd6cXliZ8QYcQuHcVCk9MYHIHRNpPJU30M0CUvFx5Itgaemr/Si4Pl+VbU+UGHsoY7O1yoT7xEQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-arm64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-arm64-musl/-/mediaplex-linux-arm64-musl-1.0.0.tgz", + "integrity": "sha512-7bpJG5wILQXLAEUAcFafMtlZmNZXKRFXaiMGKWSj29YZnyEwSHRiQEyemxu72SEYQibfwyq9Ah830pZAcfnIsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-riscv64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-riscv64-gnu/-/mediaplex-linux-riscv64-gnu-1.0.0.tgz", + "integrity": "sha512-p0m6R5O/jSg3w6u7LCw2bwCDeXKKeYEmIqy9ORvOVZT6Cin96ojhj6ELj8/spRh8Uox1DUxiPkBJrTEzeNWugA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-x64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-x64-gnu/-/mediaplex-linux-x64-gnu-1.0.0.tgz", + "integrity": "sha512-8piBl1DmEeRtElr+aG8OgC7cszzhQN8jGh+ClB6FKIZ2uiRf9SQ9tWH4hsE+qm17SamOekiibG5kXDLNAtPrtg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-linux-x64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-linux-x64-musl/-/mediaplex-linux-x64-musl-1.0.0.tgz", + "integrity": "sha512-9hZvUDxPHIuFI+Y4bT3io/TnDK1fnXbfAMWhObWd5qx7YyZJcvgS2M4p0x9a57dZnLSPc7sbNov1tQTqMm03RQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-win32-arm64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-win32-arm64-msvc/-/mediaplex-win32-arm64-msvc-1.0.0.tgz", + "integrity": "sha512-R2cQlKR+AjbafdtVnyPftkALxeam4XPEanT5SBo/IO1WmglC5MzppqHm8Gto5NleE16AqXHRPanQoi53fK49xg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-win32-ia32-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-win32-ia32-msvc/-/mediaplex-win32-ia32-msvc-1.0.0.tgz", + "integrity": "sha512-CWvcvHw4x0moo2gJeDZEbar39TbCeZ0bV3Vu0n+DWzFEDxl5p3iIeZqlDsHbSvNQeU0iKVCQOgatxvUly3E/4g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/mediaplex-win32-x64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mediaplex-win32-x64-msvc/-/mediaplex-win32-x64-msvc-1.0.0.tgz", + "integrity": "sha512-yocvA647y6kAgBLpjllVjmp6ayvaBuqwrF+KhQnUnXbGH8celV0clJw9y7Ca8e38v89Yj4C73KpHxwGBk0sGqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -1040,6 +3831,15 @@ "node": ">= 0.6" } }, + "node_modules/miniget": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.3.tgz", + "integrity": "sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1052,12 +3852,94 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "license": "ISC" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", + "license": "MIT" + }, + "node_modules/needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "license": "MIT", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -1067,6 +3949,75 @@ "node": ">= 0.6" } }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "peer": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-fetch/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "license": "MIT", + "peer": true, + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, "node_modules/nodemon": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", @@ -1127,6 +4078,38 @@ "node": ">=0.10.0" } }, + "node_modules/nssocket": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", + "integrity": "sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==", + "license": "MIT", + "dependencies": { + "eventemitter2": "~0.4.14", + "lazy": "~1.0.11" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/nssocket/node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1160,6 +4143,78 @@ "node": ">= 0.8" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pac-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1169,12 +4224,69 @@ "node": ">= 0.8" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -1187,6 +4299,342 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidusage": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz", + "integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pm2": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.4.3.tgz", + "integrity": "sha512-4/I1htIHzZk1Y67UgOCo4F1cJtas1kSds31N8zN0PybO230id1nigyjGuGFzUnGmUFPmrJ0On22fO1ChFlp7VQ==", + "license": "AGPL-3.0", + "dependencies": { + "@pm2/agent": "~2.0.0", + "@pm2/io": "~6.0.1", + "@pm2/js-api": "~0.8.0", + "@pm2/pm2-version-check": "latest", + "async": "~3.2.0", + "blessed": "0.1.81", + "chalk": "3.0.0", + "chokidar": "^3.5.3", + "cli-tableau": "^2.0.0", + "commander": "2.15.1", + "croner": "~4.1.92", + "dayjs": "~1.11.5", + "debug": "^4.3.1", + "enquirer": "2.3.6", + "eventemitter2": "5.0.1", + "fclone": "1.0.11", + "js-yaml": "~4.1.0", + "mkdirp": "1.0.4", + "needle": "2.4.0", + "pidusage": "~3.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.1", + "pm2-deploy": "~1.0.2", + "pm2-multimeter": "^0.1.2", + "promptly": "^2", + "semver": "^7.2", + "source-map-support": "0.5.21", + "sprintf-js": "1.1.2", + "vizion": "~2.2.1" + }, + "bin": { + "pm2": "bin/pm2", + "pm2-dev": "bin/pm2-dev", + "pm2-docker": "bin/pm2-docker", + "pm2-runtime": "bin/pm2-runtime" + }, + "engines": { + "node": ">=12.0.0" + }, + "optionalDependencies": { + "pm2-sysmonit": "^1.2.8" + } + }, + "node_modules/pm2-axon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-4.0.1.tgz", + "integrity": "sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==", + "license": "MIT", + "dependencies": { + "amp": "~0.3.1", + "amp-message": "~0.1.1", + "debug": "^4.3.1", + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/pm2-axon-rpc": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz", + "integrity": "sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.1" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/pm2-axon-rpc/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pm2-axon-rpc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/pm2-axon/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pm2-axon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/pm2-deploy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-1.0.2.tgz", + "integrity": "sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==", + "license": "MIT", + "dependencies": { + "run-series": "^1.1.8", + "tv4": "^1.3.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pm2-multimeter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz", + "integrity": "sha512-S+wT6XfyKfd7SJIBqRgOctGxaBzUOmVQzTAS+cg04TsEUObJVreha7lvCfX8zzGVr871XwCSnHUU7DQQ5xEsfA==", + "license": "MIT/X11", + "dependencies": { + "charm": "~0.1.1" + } + }, + "node_modules/pm2-sysmonit": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz", + "integrity": "sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==", + "license": "Apache", + "optional": true, + "dependencies": { + "async": "^3.2.0", + "debug": "^4.3.1", + "pidusage": "^2.0.21", + "systeminformation": "^5.7", + "tx2": "~1.0.4" + } + }, + "node_modules/pm2-sysmonit/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pm2-sysmonit/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/pm2-sysmonit/node_modules/pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pm2/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pm2/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/prism-media": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz", + "integrity": "sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==", + "license": "Apache-2.0", + "peerDependencies": { + "@discordjs/opus": ">=0.8.0 <1.0.0", + "ffmpeg-static": "^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0", + "node-opus": "^0.3.3", + "opusscript": "^0.0.8" + }, + "peerDependenciesMeta": { + "@discordjs/opus": { + "optional": true + }, + "ffmpeg-static": { + "optional": true + }, + "node-opus": { + "optional": true + }, + "opusscript": { + "optional": true + } + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promptly": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", + "integrity": "sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA==", + "license": "MIT", + "dependencies": { + "read": "^1.0.4" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1200,12 +4648,69 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "license": "MIT" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -1245,6 +4750,91 @@ "node": ">= 0.8" } }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz", + "integrity": "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==", + "license": "MIT", + "peer": true, + "dependencies": { + "readable-stream": "^4.7.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "peer": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1257,6 +4847,161 @@ "node": ">=8.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", + "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/require-in-the-middle/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/require-in-the-middle/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reverbnation-scraper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reverbnation-scraper/-/reverbnation-scraper-2.0.0.tgz", + "integrity": "sha512-t1Mew5QC9QEVEry5DXyagvci2O+TgXTGoMHbNoW5NRz6LTOzK/DLHUpnrQwloX8CVX5z1a802vwHM3YgUVOvKg==", + "license": "MIT", + "peer": true, + "dependencies": { + "node-fetch": "^2.6.0" + } + }, + "node_modules/reverbnation-scraper/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/rollup": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", + "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1283,6 +5028,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -1355,6 +5106,33 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "license": "BSD-2-Clause" + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -1427,6 +5205,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -1439,6 +5223,16 @@ "node": ">=10" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -1549,6 +5343,116 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/soundcloud.ts": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.5.5.tgz", + "integrity": "sha512-bygjhC1w/w26Nk0Y+4D4cWSEJ1TdxLaE6+w4pCazFzPF+J4mzuB62ggWmFa7BiwnirzNf9lgPbjzrQYGege4Ew==", + "license": "MIT", + "peer": true, + "dependencies": { + "undici": "^6.17.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spotify-uri": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/spotify-uri/-/spotify-uri-4.1.0.tgz", + "integrity": "sha512-SFpBt8pQqO7DOFBsdUjv3GxGZAKYP7UqcTflfE7h3YL1lynl/6Motq7NERoJJR8eF9kXQRSpcdMmV5ou84rbng==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + } + }, + "node_modules/spotify-url-info": { + "version": "3.2.18", + "resolved": "https://registry.npmjs.org/spotify-url-info/-/spotify-url-info-3.2.18.tgz", + "integrity": "sha512-apL7H8i+zpj3gnVxXrhEa1H6uBORC2iTExjw808/13Z6mBHJvsF6Dt4ZZF9E+J54n2p7KyGRxnpgm4nEvxsxjQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "himalaya": "~1.1.0", + "spotify-uri": "~4.1.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "license": "BSD-3-Clause" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1558,6 +5462,160 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1570,6 +5628,120 @@ "node": ">=4" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/systeminformation": { + "version": "5.25.11", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.25.11.tgz", + "integrity": "sha512-jI01fn/t47rrLTQB0FTlMCC+5dYx8o0RRF+R4BPiUNsvg5OdY0s9DKMFmJGrx5SwMZQ4cag0Gl6v8oycso9b/g==", + "license": "MIT", + "optional": true, + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1591,6 +5763,24 @@ "node": ">=0.6" } }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -1600,6 +5790,28 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "peer": true + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", @@ -1612,6 +5824,174 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsup": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.6.tgz", + "integrity": "sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g==", + "license": "MIT", + "dependencies": { + "bundle-require": "^5.0.0", + "cac": "^6.7.14", + "chokidar": "^4.0.1", + "consola": "^3.2.3", + "debug": "^4.3.7", + "esbuild": "^0.24.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.24.0", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.1", + "tinyglobby": "^0.2.9", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/tsup/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsup/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tsup/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "license": "BSD-2-Clause" + }, + "node_modules/tsup/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==", + "license": [ + { + "type": "Public Domain", + "url": "http://geraintluff.github.io/tv4/LICENSE.txt" + }, + { + "type": "MIT", + "url": "http://jsonary.com/LICENSE.txt" + } + ], + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tx2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", + "integrity": "sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==", + "license": "MIT", + "optional": true, + "dependencies": { + "json-stringify-safe": "^5.0.1" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1625,6 +6005,25 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -1646,6 +6045,16 @@ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, + "node_modules/unfetch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-5.0.0.tgz", + "integrity": "sha512-3xM2c89siXg0nHvlmYsQ2zkLASvVMBisZm5lF3gFDqfF2xonNStDJyMpvaOBe0a1Edxmqrf2E0HBdmy9QyZaeg==", + "license": "MIT", + "peer": true, + "workspaces": [ + "./packages/isomorphic-unfetch" + ] + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1655,6 +6064,12 @@ "node": ">= 0.8" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1686,12 +6101,167 @@ "node": ">= 0.8" } }, + "node_modules/vizion": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-2.2.1.tgz", + "integrity": "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==", + "license": "Apache-2.0", + "dependencies": { + "async": "^2.6.3", + "git-node-fs": "^1.0.0", + "ini": "^1.3.5", + "js-git": "^0.7.8" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vizion/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "peer": true + }, "node_modules/webmetrik": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/webmetrik/-/webmetrik-0.1.4.tgz", "integrity": "sha512-Si3qMLvpXBd3N0KfSqF6pAwLDS+C4QLyXCgzjo6UpRWE1wXgkzRbUtTZSqh7n2p4uFzm9MRlz/biK+q//uTidw==", "license": "ISC" }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/ws": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", @@ -1712,6 +6282,26 @@ "optional": true } } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/ytdl-core": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.11.5.tgz", + "integrity": "sha512-27LwsW4n4nyNviRCO1hmr8Wr5J1wLLMawHCQvH8Fk0hiRqrxuIu028WzbJetiYH28K8XDbeinYW4/wcHQD1EXA==", + "license": "MIT", + "dependencies": { + "m3u8stream": "^0.8.6", + "miniget": "^4.2.2", + "sax": "^1.1.3" + }, + "engines": { + "node": ">=12" + } } } } diff --git a/backend/package.json b/backend/package.json index bb9b2fe..f883299 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "chopin-backend", - "version": "0.1.0", + "version": "0.2.0", "description": "Discord Bot for music - Fetching everywhere !", "main": "src/main.js", "nodemonConfig": { @@ -18,13 +18,21 @@ "author": "Raphix", "license": "ISC", "dependencies": { + "@discordjs/voice": "^0.18.0", "cors": "^2.8.5", + "discord-player": "^7.1.0", "discord.js": "^14.18.0", "express": "^4.21.2", + "ffmpeg-static": "^5.2.0", + "ffprobe": "^1.1.2", + "ffprobe-static": "^3.1.0", + "libsodium-wrappers": "^0.7.15", "loguix": "^1.4.2", "nodemon": "^3.1.9", + "pm2": "^5.4.3", "socket.io": "^4.8.1", "uuid": "^11.1.0", - "webmetrik": "^0.1.4" + "webmetrik": "^0.1.4", + "ytdl-core": "^4.11.5" } } diff --git a/backend/src/discord/Command.js b/backend/src/discord/Command.js index a531afa..73dc2f2 100644 --- a/backend/src/discord/Command.js +++ b/backend/src/discord/Command.js @@ -53,10 +53,18 @@ class Command { }) SlashCommand.addStringOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required).addChoices(choices)) } + if(SelOption.type === "FILE") { + SlashCommand.addAttachmentOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required)) + } }) } + /** + * @type {SlashCommandBuilder} + * @param {Client} client + * @param {Interaction} interaction + */ this.data = {data: SlashCommand, async execute(client, interaction) {callback(client, interaction)}} } diff --git a/backend/src/discord/CommandUpdater.js b/backend/src/discord/CommandUpdater.js index 705f0bf..484e55f 100644 --- a/backend/src/discord/CommandUpdater.js +++ b/backend/src/discord/CommandUpdater.js @@ -50,10 +50,6 @@ client.commands = new Collection() } - - - - dlog.step.end("d_commands_refresh") } catch (error) { // And of course, make sure you catch and log any errors! diff --git a/backend/src/discord/Commands/Help.js b/backend/src/discord/Commands/Help.js index 054521b..ca74872 100644 --- a/backend/src/discord/Commands/Help.js +++ b/backend/src/discord/Commands/Help.js @@ -18,7 +18,7 @@ const command = new Command("help", "Affiche la liste des commandes", (client, i option.choices.forEach(choice => { choices.push(choice.name) }) - CommandName += " " + choices.join(" | ") + CommandName += " <" + choices.join(" | ") +">" } }) } diff --git a/backend/src/discord/Commands/Media.js b/backend/src/discord/Commands/Media.js new file mode 100644 index 0000000..723f245 --- /dev/null +++ b/backend/src/discord/Commands/Media.js @@ -0,0 +1,51 @@ +const {Command} = require('../Command'); +const {Embed, EmbedError} = require('../Embed'); +const { Player } = require('../../player/Player'); +const { Song } = require('../../player/Song'); + +const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal", async (client, interaction) => { + + if(!interaction.member.voice.channel) return interaction.reply({content:"Vous devez rejoindre un salon vocal pour lire un(e) titre / playlist !", ephemeral: true}) + + const media = interaction.options.get("media") + const now = interaction.options.getBoolean("now") || false + + if(media.attachment.contentType != "audio/mpeg" && media.attachment.contentType != "audio/wav") return new EmbedError("Le média doit être un fichier audio MP3 ou WAV !").send(interaction) + + const channel = interaction.member.voice.channel + const song = new Song() + await song.processMedia(media, interaction.user.username) + + const player = new Player(channel.guildId) + player.join(channel) + + const embed = new Embed() + embed.setColor(0x15e6ed) + + + if(now) { + player.play(song) + embed.setTitle('**Lecture immédiate**') + + } else { + player.add(song) + embed.setTitle('**Ajout à liste de lecture**') + + } + + embed.setDescription('**Titre : **' + song.title) + embed.addField('**Durée : **'+ song.readduration, "") + embed.addField("**Artiste : **" + song.author, "") + embed.addField('**Demandé par **' + interaction.member.user.username,"") + embed.setThumbnail(song.thumbnail) + + + embed.send(interaction) + + + +}, [{type: "FILE", name: "media", description: "Fichier audio à lire", required: true}, + {type:"BOOLEAN", name: "now", description: "Lire le média maintenant", required: false}] +) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/Pause.js b/backend/src/discord/Commands/Pause.js new file mode 100644 index 0000000..6bba65f --- /dev/null +++ b/backend/src/discord/Commands/Pause.js @@ -0,0 +1,24 @@ +const {Command} = require("../Command") +const {Embed, EmbedError} = require("../Embed") +const { Player } = require("../../player/Player") + +const command = new Command("pause", "Mettre en pause la musique en cours", (client, interaction) => { + + + if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour mettre en pause la musique !").send(interaction) + + const channel = interaction.member.voice.channel + const player = new Player(channel.guildId) + player.pause() + + // Réponse en embed + + const embed = new Embed() + embed.setColor(0x00ff66) + embed.setTitle('Musique en pause') + embed.setDescription("La musique a été mise en pause") + embed.send(interaction) + +}) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/Play.js b/backend/src/discord/Commands/Play.js new file mode 100644 index 0000000..7d334a8 --- /dev/null +++ b/backend/src/discord/Commands/Play.js @@ -0,0 +1,15 @@ +const { Command } = require("../Command"); +const { Embed, EmbedError } = require("../Embed"); +const { Player } = require("../../player/Player"); + +const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", (client, interaction) => { + + if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer une musique !").send(interaction) + + const url = interaction.options.get("url") + const channel = interaction.member.voice.channel + +}, [{type: "STRING", name: "url", description: "Lien audio (Youtube / Soundclound / Spotify)", required: true}] +) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/Restart.js b/backend/src/discord/Commands/Restart.js new file mode 100644 index 0000000..7374f16 --- /dev/null +++ b/backend/src/discord/Commands/Restart.js @@ -0,0 +1,20 @@ +const {Embed} = require("../Embed") +const {Command} = require("../Command") +const {restart} = require("../../utils/Maintenance") + +// Nécéssite une raison pour redémarrer le bot + +const command = new Command("restart", "Redémarre le bot", (client, interaction) => { + const reason = interaction.options.getString("reason") + restart(reason) + const embed = new Embed() + embed.setColor(150, 20, 20) + embed.setTitle('Redémarrage') + embed.setDescription("Veuillez patientez, le bot va redémarrer dans un instant ! :arrows_counterclockwise:") + embed.addField('Raison', reason) + embed.send(interaction) +}, +[{type: "STRING", name: "reason", description: "Raison du redémarrage", required: true}] +) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Embed.js b/backend/src/discord/Embed.js index 012c833..f76f096 100644 --- a/backend/src/discord/Embed.js +++ b/backend/src/discord/Embed.js @@ -86,4 +86,14 @@ class Embed { } } -module.exports = {Embed} \ No newline at end of file +class EmbedError extends Embed { + constructor(message) { + super() + this.setColor(150, 20, 20) + this.setTitle('Erreur') + this.setThumbnail("https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/Dialog-error-round.svg/2048px-Dialog-error-round.svg.png") + this.setDescription(message) + } +} + +module.exports = {Embed, EmbedError} \ No newline at end of file diff --git a/backend/src/player/Finder.js b/backend/src/player/Finder.js new file mode 100644 index 0000000..e69de29 diff --git a/backend/src/player/List.js b/backend/src/player/List.js new file mode 100644 index 0000000..71de905 --- /dev/null +++ b/backend/src/player/List.js @@ -0,0 +1,173 @@ +const { Database } = require('../utils/Database/Database') +const { __glob } = require('../utils/GlobalVars') +const PreviousDB = new Database("previous", __glob.PREVIOUSFILE, {}) +const {LogType} = require("loguix") +const clog = new LogType("List") + +const AllLists = new Map() // Map + +class List { + next; + current; + shuffle; + guildId; + constructor(guildId) { + if(guildId === null) { + clog.error("Impossible de créer une liste, car guildId est null") + return + } + if(AllLists.has(guildId)) { + return AllLists.get(guildId) + } + // Add PreviousDB.data[this.guildId] + if(PreviousDB.data[guildId] === undefined) { + PreviousDB.data[guildId] = new Array() + savePrevious() + } + AllLists.set(guildId, this) + this.next = new Array(); + this.current = null; + this.shuffle = false; + this.guildId = guildId; + } + getNext() { + return this.next; + } + + getNextSong() { + if(this.next.length > 0) { + return this.next[0]; + } else { + return null; + } + } + + nextSong() { + var song = null; + if(!this.shuffle) { + song = this.next[0] + this.next.splice(0, 1) + } else { + const randomIndex = Math.floor(Math.random() * this.next.length); + song = this.next[randomIndex] + this.next.splice(randomIndex, 1) + + } + return song + } + + clearNext() { + this.next = new Array(); + } + + addNextSong(song) { + this.next.push(song) + } + + removeNextByIndex(index) { + this.next.splice(index, 1) + } + + moveSongToUpNext(index) { + const song = this.next[index] + this.next.splice(index, 1) + this.next.unshift(song) + } + + getPrevious() { + return PreviousDB.data[this.guildId]; + } + + getPreviousSong() { + if(PreviousDB.data[this.guildId].length > 0) { + const song = PreviousDB.data[this.guildId][0] + PreviousDB.data[this.guildId].splice(0, 1) + savePrevious() + return song + } else { + return null; + } + } + + clearPrevious() { + PreviousDB.data[this.guildId] = new Array(); + savePrevious(); + } + + addPreviousSongToNextByIndex(index) { + const song = PreviousDB.data[this.guildId][index] + this.next.push(song) + } + + addPreviousSong(song) { + PreviousDB.data[this.guildId].unshift(song) + savePrevious() + } + + getCurrent() { + return this.current; + } + + setCurrent(value) { + this.current = value; + } + + destroy() { + this.clearNext(); + this.current = null + this.shuffle = false; + } + + setShuffle(value) { + this.shuffle = value; + } + + isShuffle() { + return this.shuffle; + } + + // Play the song with the index in the queue and delete it from the queue + playByIndex(index, typelist) { + + var index = data[0] + var list = data[1] + + if(typelist == ListType.NEXT) { + + const song = this.next[index] + this.next.splice(index, 1) + + return song + + } else if(typelist == ListType.PREVIOUS) { + + const song = PreviousDB.data[this.guildId][index] + return song + + } + } + + + + + +} + + +const ListType = { + NEXT: "0", + PREVIOUS: "1" +} + +function savePrevious() { + + for(const guildId in PreviousDB.data) { + if(PreviousDB.data[guildId].length > 50) { + PreviousDB.data[guildId].splice(50, PreviousDB.data[guildId].length - 50) + } + } + + PreviousDB.save(); +} + +module.exports = { List, ListType } \ No newline at end of file diff --git a/backend/src/player/Method/Media.js b/backend/src/player/Method/Media.js new file mode 100644 index 0000000..dd1d47c --- /dev/null +++ b/backend/src/player/Method/Media.js @@ -0,0 +1,18 @@ +const {createAudioResource, VoiceConnectionStatus} = require('@discordjs/voice'); +const {LogType} = require('loguix') +const clog = new LogType("Media") +const plog = require("loguix").getInstance("Player") + +async function play(instance, song) { + //const resource = await song.getResource() + const resource = createAudioResource(song.url) + console.log(resource) + // Wait until connection is ready + instance.connection.once(VoiceConnectionStatus.Ready, async () => { + instance.player.play(resource) + }) + + plog.log(`GUILD : ${instance.guildId} - Lecture de la musique : ${song.title}`) +} + +module.exports = {play} \ No newline at end of file diff --git a/backend/src/player/Player.js b/backend/src/player/Player.js new file mode 100644 index 0000000..ad2e41d --- /dev/null +++ b/backend/src/player/Player.js @@ -0,0 +1,126 @@ +const { joinVoiceChannel, getVoiceConnection, entersState, VoiceConnectionStatus, createAudioPlayer, AudioPlayerStatus } = require('@discordjs/voice'); +const {List} = require('./List') +const {LogType} = require("loguix"); + +const plog = new LogType("Player") +const clog = new LogType("Signal") + +const media = require('./Method/Media'); + +const AllPlayers = new Map() + +class Player { + connection; + player; + guildId; + queue; + constructor(guildId) { + if(this.guildId === null) { + clog.error("Impossible de créer un Player, car guildId est null") + return + } + if(AllPlayers.has(guildId)) { + return AllPlayers.get(guildId) + } + this.connection = null + this.player = null + this.guildId = guildId + this.queue = new List(guildId) + AllPlayers.set(guildId, this) + } + + async join(channel) { + + if(getVoiceConnection(channel.guild.id)) { + clog.log(`GUILD : ${this.guildId} - Une connexion existe déjà pour ce serveur`) + return + } + this.connection = joinVoiceChannel({ + channelId: channel.id, + guildId: channel.guild.id, + adapterCreator: channel.guild.voiceAdapterCreator, + }); + + this.player = createAudioPlayer() + + this.connection.subscribe(this.player) + + this.connection.on('stateChange', (oldState, newState) => { + clog.log(`GUILD : ${this.guildId} - [STATE] OLD : "${oldState.status}" NEW : "${newState.status}"`); + }); + + this.player.on('error', error => { + plog.error(`GUILD : ${this.guildId} - Une erreur est survenue dans le player`); + plog.error(error); + }); + + this.player.on(AudioPlayerStatus.Idle, () => { + if(this.queue.next.length > 0) { + //TODO : Play next song + } + }); + + this.player.on(AudioPlayerStatus.Playing, () => { + plog.log(`GUILD : ${this.guildId} - Le player est en train de jouer le contenu suivant : ${this.queue.current.title}`); + }); + + } + + checkConnection() { + if(this.connection === null) { + clog.error(`GUILD : ${this.guildId} - La connection n'est pas définie`) + return true + } + if(this.player === null) { + plog.error(`GUILD : ${this.guildId} - Le player n'est pas défini`) + return true + } + } + + async play(song) { + if(song.type = "attachment") { + media.play(this, song) + } + } + + async add(song) { + if(this.player.state.status = AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) { + this.play(song) + return + } + + this.queue.addNextSong(song) + } + + async pause() { + if(this.player.state.status = AudioPlayerStatus.Paused) { + this.player.unpause() + } else { + this.player.pause() + } + } + + async leave() { + // Détruit la connection et le player et l'enlève de la liste des + this.connection.destroy() + this.player.stop() + AllPlayers.delete(this.guildId) + clog.log("Connection détruite avec le guildId : " + this.guildId) + plog.log("Player détruit avec le guildId : " + this.guildId) + + } + + + +} + +module.exports = {Player} + + +/* + +You can access created connections elsewhere in your code without having to track the connections yourself. It is best practice to not track the voice connections yourself as you may forget to clean them up once they are destroyed, leading to memory leaks. + +const connection = getVoiceConnection(myVoiceChannel.guild.id); + +*/ \ No newline at end of file diff --git a/backend/src/player/Song.js b/backend/src/player/Song.js new file mode 100644 index 0000000..1a5dd8d --- /dev/null +++ b/backend/src/player/Song.js @@ -0,0 +1,77 @@ +const {LogType} = require('loguix') +const { createAudioResource, StreamType } = require('@discordjs/voice'); +const ffprobe = require('ffprobe'); +const ffprobeStatic = require('ffprobe-static'); +const { getReadableDuration } = require('../utils/TimeConverter'); + +const clog = new LogType("Song") + +class Song { + title = "Aucun titre"; + author = "Auteur inconnu" + url; + thumbnail; + duration; + readduration; + type; + + async processMedia(media, provider) { + if(provider) this.author = provider + // Check if media is a file or a link + if(media.attachment) { + this.url = media.attachment.url + this.type = "attachment" + + // In face, duration is null, get the metadata of the file to get the duration + await getMediaInformation(this, media) + + } else { + clog.error("Impossible de traiter le média") + } + + } + + async getResource() { + + const resource = createAudioResource(this.url, { + inputType: StreamType.Arbitrary + }) + return resource + + + } + + + + +} + +module.exports = {Song} + +async function getMediaInformation(instance, media, provider) { + try { + const info = await ffprobe(media.attachment.url, { path: ffprobeStatic.path }); + if (info.streams?.[0]?.duration_ts) { + instance.duration = info.streams[0].duration; + instance.readduration = getReadableDuration(instance.duration) + } + + // Vérification pour éviter une erreur si `streams[0]` ou `tags` n'existe pas + instance.thumbnail = info.streams?.[0]?.tags?.thumbnail ?? + "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png"; + + // Obtenir le titre (sinon utiliser le nom du fichier) + instance.title = info.streams?.[0]?.tags?.title ?? media.attachment.name; + + // Obtenir l'auteur (s'il existe) + instance.author = info.streams?.[0]?.tags?.artist ?? instance.author; + + + + + } catch (err) { + clog.error("Impossible de récupérer les informations de la musique : " + this.name) + clog.error(err) + return null; + } +} \ No newline at end of file diff --git a/backend/src/utils/Database/Database.js b/backend/src/utils/Database/Database.js index 8c109b6..9a6c94c 100644 --- a/backend/src/utils/Database/Database.js +++ b/backend/src/utils/Database/Database.js @@ -61,6 +61,9 @@ class Database { clog.error(`Erreur lors de la sauvegarde de la base de données '${this.name}'`) clog.error(e) } + + // Assure that the database is up to date and reloaded + this.update() } diff --git a/backend/src/utils/GlobalVars.js b/backend/src/utils/GlobalVars.js index 121364a..48578f6 100644 --- a/backend/src/utils/GlobalVars.js +++ b/backend/src/utils/GlobalVars.js @@ -8,7 +8,8 @@ const __glob = { LOGS: root + path.sep + "logs", DATA: root + path.sep + "data", COMMANDS: root + path.sep + "src" + path.sep + "discord" + path.sep + "commands", - METRIC_FILE: root + path.sep + "data" + path.sep + "metrics.json" + METRIC_FILE: root + path.sep + "data" + path.sep + "metrics.json", + PREVIOUSFILE: root + path.sep + "data" + path.sep + "previous.json", } module.exports = {__glob} \ No newline at end of file diff --git a/backend/src/utils/Maintenance.js b/backend/src/utils/Maintenance.js new file mode 100644 index 0000000..5a772fd --- /dev/null +++ b/backend/src/utils/Maintenance.js @@ -0,0 +1,11 @@ +const pm2 = require("pm2") +const { LogType } = require("loguix") +const clog = new LogType("Maintenance") + +function restart(reason) { + clog.warn("Redémarrage du serveur Subsonics") + clog.warn(`Reason: ${reason}`) + pm2.restart("Subsonics") +} + +module.exports = {restart} \ No newline at end of file diff --git a/backend/src/utils/TimeConverter.js b/backend/src/utils/TimeConverter.js new file mode 100644 index 0000000..52f1087 --- /dev/null +++ b/backend/src/utils/TimeConverter.js @@ -0,0 +1,32 @@ +function getReadableDuration(duration) { + var max = "" + duration *= 1000; + + const maxhours = Math.floor(duration / 3600000); + + var maxmin = Math.trunc(duration / 60000) - (Math.floor(duration / 60000 / 60) * 60); + var maxsec = Math.floor(duration / 1000) - (Math.floor(duration / 1000 / 60) * 60); + + + if (maxsec < 10) { + maxsec = `0${maxsec}`; + } + + + if(maxhours != 0) { + + if (maxmin < 10) { + maxmin = `0${maxmin}`; + } + + + max = maxhours + "h" + maxmin + "m" + maxsec + } else { + max = maxmin + "m" + maxsec + "s" + + } + + return max +} + +module.exports = {getReadableDuration} \ No newline at end of file -- 2.30.2 From 5e722e9dbc05f392a857e1babb88f2e531b2fb69 Mon Sep 17 00:00:00 2001 From: Raphix Date: Tue, 25 Feb 2025 17:01:21 +0100 Subject: [PATCH 2/6] Version 0.2.0-alpha2 - Test Git --- backend/src/player/Method/Media.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/player/Method/Media.js b/backend/src/player/Method/Media.js index dd1d47c..0185ffe 100644 --- a/backend/src/player/Method/Media.js +++ b/backend/src/player/Method/Media.js @@ -5,7 +5,8 @@ const plog = require("loguix").getInstance("Player") async function play(instance, song) { //const resource = await song.getResource() - const resource = createAudioResource(song.url) + //Test with a local file + const resource = createAudioResource("C:\\Users\\picot\\Downloads\\Confrontation_Replique_Raphix.mp3") console.log(resource) // Wait until connection is ready instance.connection.once(VoiceConnectionStatus.Ready, async () => { -- 2.30.2 From f99fc24aa9d034a716a0c551df6a71f5c6eb1346 Mon Sep 17 00:00:00 2001 From: Raphix Date: Wed, 26 Feb 2025 18:02:43 +0100 Subject: [PATCH 3/6] Version 0.2.0 - Ajout de Player (Media) --- .gitignore | 4 +- backend/src/discord/Activity.js | 4 +- backend/src/discord/Bot.js | 2 +- backend/src/discord/Commands/Leave.js | 28 +++++++++ backend/src/discord/Commands/Media.js | 8 +-- backend/src/discord/Commands/Pause.js | 34 ++++++++--- backend/src/discord/Commands/Previous.js | 52 ++++++++++++++++ backend/src/discord/Commands/Queue.js | 39 ++++++++++++ backend/src/discord/Commands/Skip.js | 49 +++++++++++++++ backend/src/discord/Commands/State.js | 34 +++++++++++ backend/src/discord/Embed.js | 8 ++- backend/src/media/MediaInformation.js | 32 ++++++++++ backend/src/player/Finder.js | 0 backend/src/player/List.js | 34 ++++++++++- backend/src/player/Method/Media.js | 29 ++++++--- backend/src/player/Player.js | 78 ++++++++++++++++++++---- backend/src/player/Song.js | 52 ++++++---------- 17 files changed, 413 insertions(+), 74 deletions(-) create mode 100644 backend/src/discord/Commands/Leave.js create mode 100644 backend/src/discord/Commands/Previous.js create mode 100644 backend/src/discord/Commands/Queue.js create mode 100644 backend/src/discord/Commands/Skip.js create mode 100644 backend/src/discord/Commands/State.js create mode 100644 backend/src/media/MediaInformation.js delete mode 100644 backend/src/player/Finder.js diff --git a/.gitignore b/.gitignore index 8506ed8..238b8dd 100644 --- a/.gitignore +++ b/.gitignore @@ -141,4 +141,6 @@ docs/_book # TODO: where does this rule come from? test/ -data/ \ No newline at end of file +data/ + +__DEBUG.js \ No newline at end of file diff --git a/backend/src/discord/Activity.js b/backend/src/discord/Activity.js index 5f063ed..bac8bed 100644 --- a/backend/src/discord/Activity.js +++ b/backend/src/discord/Activity.js @@ -13,10 +13,10 @@ function setMusicActivity(songName, artistName, imageUrl) { const client = bot.getClient() client.user.setActivity(`${songName} - ${artistName}`,{ type: ActivityType.Listening, - /*assets: { + assets: { largeImage: imageUrl, largeText: songName - }*/ + } }); dlog.log(`Activité mise à jour : ${songName} - ${artistName}`) } diff --git a/backend/src/discord/Bot.js b/backend/src/discord/Bot.js index 17c2b36..ba4a1bc 100644 --- a/backend/src/discord/Bot.js +++ b/backend/src/discord/Bot.js @@ -20,7 +20,7 @@ function getClient() { function init() { - + client.once('ready', () => { dlog.log("Connexion au Bot Discord réussi ! Connecté en tant que : " + client.user.tag) diff --git a/backend/src/discord/Commands/Leave.js b/backend/src/discord/Commands/Leave.js new file mode 100644 index 0000000..1713cb7 --- /dev/null +++ b/backend/src/discord/Commands/Leave.js @@ -0,0 +1,28 @@ +const {Command} = require("../Command") +const {Embed, EmbedError} = require("../Embed") +const {Player, AllPlayers} = require("../../player/Player") + +const command = new Command("leave", "Quitter le salon vocal", (client, interaction) => { + + if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour arrêter le bot !").send(interaction) + const channel = interaction.member.voice.channel + var embed = new Embed() + if(AllPlayers.has(channel.guildId)) { + const player = AllPlayers.get(channel.guildId) + player.leave() + + + embed.setColor(200, 20, 20) + embed.setTitle('**Déconnexion**') + embed.setDescription('Déconnexion du salon vocal') + embed.setThumbnail("https://www.iconsdb.com/icons/download/white/phone-51-64.png") + + } else { + + embed = new EmbedError("Le bot n'est pas connecté à ce salon vocal") + } + embed.send(interaction) + +}) + +module.exports = {command} diff --git a/backend/src/discord/Commands/Media.js b/backend/src/discord/Commands/Media.js index 723f245..cde51aa 100644 --- a/backend/src/discord/Commands/Media.js +++ b/backend/src/discord/Commands/Media.js @@ -5,7 +5,7 @@ const { Song } = require('../../player/Song'); const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal", async (client, interaction) => { - if(!interaction.member.voice.channel) return interaction.reply({content:"Vous devez rejoindre un salon vocal pour lire un(e) titre / playlist !", ephemeral: true}) + if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer un média !").send(interaction, true) const media = interaction.options.get("media") const now = interaction.options.getBoolean("now") || false @@ -34,9 +34,9 @@ const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal } embed.setDescription('**Titre : **' + song.title) - embed.addField('**Durée : **'+ song.readduration, "") - embed.addField("**Artiste : **" + song.author, "") - embed.addField('**Demandé par **' + interaction.member.user.username,"") + embed.addField('**Durée : **', song.readduration) + embed.addField("**Artiste : **",song.author) + embed.addField('**Demandé par **' + interaction.member.user.username, "") embed.setThumbnail(song.thumbnail) diff --git a/backend/src/discord/Commands/Pause.js b/backend/src/discord/Commands/Pause.js index 6bba65f..dac6a82 100644 --- a/backend/src/discord/Commands/Pause.js +++ b/backend/src/discord/Commands/Pause.js @@ -2,22 +2,42 @@ const {Command} = require("../Command") const {Embed, EmbedError} = require("../Embed") const { Player } = require("../../player/Player") -const command = new Command("pause", "Mettre en pause la musique en cours", (client, interaction) => { +const command = new Command("pause", "Mettre en pause / Reprendre la musique en cours", (client, interaction) => { if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour mettre en pause la musique !").send(interaction) const channel = interaction.member.voice.channel const player = new Player(channel.guildId) - player.pause() + const result = player.pause() + + + var embed = new Embed() + embed.setColor(0x03ff2d) + + result.then((pause) => { + + if(pause == "no_music") { + embed = new EmbedError("Il n'y a pas de musique en cours de lecture") + + } else if(pause) { + embed.setTitle('Musique en pause') + embed.setDescription("La musique a été mise en pause") + embed.setThumbnail("https://www.iconsdb.com/icons/download/white/pause-64.png") + + + } else { + embed.setTitle('Musique reprise') + embed.setDescription("La musique a été reprise") + embed.setThumbnail("https://www.iconsdb.com/icons/download/white/play-64.png") + } + + embed.send(interaction) + }) // Réponse en embed - const embed = new Embed() - embed.setColor(0x00ff66) - embed.setTitle('Musique en pause') - embed.setDescription("La musique a été mise en pause") - embed.send(interaction) + }) diff --git a/backend/src/discord/Commands/Previous.js b/backend/src/discord/Commands/Previous.js new file mode 100644 index 0000000..bd1a787 --- /dev/null +++ b/backend/src/discord/Commands/Previous.js @@ -0,0 +1,52 @@ +const {Command} = require("../Command") +const {Embed, EmbedError} = require("../Embed") +const { Player, AllPlayers } = require("../../player/Player") + +const command = new Command("previous", "Passe à la musique précédente", (client, interaction) => { + + + if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour passer à la musique suivante !").send(interaction) + + const channel = interaction.member.voice.channel + + if(AllPlayers.has(channel.guildId)) { + + const player = new Player(channel.guildId) + const result = player.previous() + + + var embed = new Embed() + embed.setColor(0x15e6ed) + + result.then((song) => { + + if(song == "no_music") { + embed = new EmbedError("Il n'y a pas de musique précédemment jouée") + + } else if(song) { + + // Result is a song + + + + embed.setTitle('**Musique précédente !**') + embed.setDescription('**Titre : **' + song.title) + embed.addField('**Durée : **'+ song.readduration, "") + embed.addField("**Artiste : **" + song.author, "") + embed.setThumbnail(song.thumbnail) + + + } + + embed.send(interaction) + }) + + } else { + return new EmbedError("Le bot n'est pas connecté").send(interaction) + } + + + +}) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/Queue.js b/backend/src/discord/Commands/Queue.js new file mode 100644 index 0000000..f67a937 --- /dev/null +++ b/backend/src/discord/Commands/Queue.js @@ -0,0 +1,39 @@ +const {Command} = require("../Command") +const {Embed, EmbedError} = require("../Embed") +const { Player, AllPlayers } = require("../../player/Player") + +const command = new Command("liste", "Affiche la file d'attente", (client, interaction) => { + + const channel = interaction.member.voice.channel + + if(AllPlayers.has(channel.guildId)) { + + const player = new Player(channel.guildId) + const queue = player.queue.getNext() + + var embed = new Embed() + embed.setColor(0x15e6ed) + + if(queue.length == 0) { + embed = new EmbedError("Il n'y a pas de musique en file d'attente") + + } else if(queue.length > 0) { + + // Result is a song + embed.setColor(0x15e6ed) + embed.setThumbnail("https://www.iconsdb.com/icons/download/white/list-2-64.png") + embed.setTitle('**File d\'attente :**') + queue.forEach((song, index) => { + embed.addField(`**${index+1} - ${song.title}**`, `**Durée : **${song.readduration}\n**Artiste : **${song.author}`) + }) + + } + + embed.send(interaction) + + } else { + return new EmbedError("Le bot n'est pas connecté").send(interaction) + } + }) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/Skip.js b/backend/src/discord/Commands/Skip.js new file mode 100644 index 0000000..637074f --- /dev/null +++ b/backend/src/discord/Commands/Skip.js @@ -0,0 +1,49 @@ +const {Command} = require("../Command") +const {Embed, EmbedError} = require("../Embed") +const { Player, AllPlayers } = require("../../player/Player") + +const command = new Command("skip", "Passe à la musique suivante", (client, interaction) => { + + if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour passer à la musique suivante !").send(interaction) + + const channel = interaction.member.voice.channel + + if(AllPlayers.has(channel.guildId)) { + + const player = new Player(channel.guildId) + const result = player.skip() + + + var embed = new Embed() + embed.setColor(0x15e6ed) + result.then((song) => { + + if(song == "no_music") { + embed = new EmbedError("Il n'y a pas de musique en file d'attente") + + } else if(song) { + + // Result is a song + embed.setColor(0x15e6ed) + + embed.setTitle('**Musique suivante !**') + embed.setDescription('**Titre : **' + song.title) + embed.addField('**Durée : **'+ song.readduration, "") + embed.addField("**Artiste : **" + song.author, "") + embed.setThumbnail(song.thumbnail) + + + } + + embed.send(interaction) + }) + + } else { + return new EmbedError("Le bot n'est pas connecté").send(interaction) + } + + + +}) + +module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/State.js b/backend/src/discord/Commands/State.js new file mode 100644 index 0000000..b17ecaa --- /dev/null +++ b/backend/src/discord/Commands/State.js @@ -0,0 +1,34 @@ +const {Command} = require("../Command") +const {Embed, EmbedError} = require("../Embed") +const {Player} = require("../../player/Player") + +const command = new Command("state", "Affiche la musique en cours", (client, interaction) => { + + const channel = interaction.member.voice.channel + const player = new Player(channel.guildId) + const song = player.queue.getCurrent() + + var embed = new Embed() + embed.setColor(0x15e6ed) + + if(!song) { + embed = new EmbedError("Il n'y a pas de musique en cours de lecture") + + } else if(song) { + + // Result is a song + embed.setColor(0x15e6ed) + + embed.setTitle('**Musique en cours :**') + embed.setDescription('**Titre : **' + song.title) + embed.addField('**Durée : **', song.readduration) + embed.addField("**Artiste : **", song.author) + embed.setThumbnail(song.thumbnail) + + + } + + embed.send(interaction) +}) + +module.exports = {command} diff --git a/backend/src/discord/Embed.js b/backend/src/discord/Embed.js index f76f096..7e6e37b 100644 --- a/backend/src/discord/Embed.js +++ b/backend/src/discord/Embed.js @@ -81,8 +81,12 @@ class Embed { return this.embed } - send(interaction) { - interaction.reply({embeds: [this.build()]}) + send(interaction, ephemeral) { + if(ephemeral) { + interaction.reply({embeds: [this.build()], ephemeral: true}) + } else { + interaction.reply({embeds: [this.build()]}) + } } } diff --git a/backend/src/media/MediaInformation.js b/backend/src/media/MediaInformation.js new file mode 100644 index 0000000..fe0f03b --- /dev/null +++ b/backend/src/media/MediaInformation.js @@ -0,0 +1,32 @@ +const ffprobe = require('ffprobe'); +const ffprobeStatic = require('ffprobe-static'); +const { getReadableDuration } = require('../utils/TimeConverter'); +const clog = require("loguix").getInstance("Song") + + +async function getMediaInformation(instance, media, provider) { + try { + const info = await ffprobe(media.attachment.url, { path: ffprobeStatic.path }); + if (info.streams?.[0]?.duration_ts) { + instance.duration = info.streams[0].duration; + instance.readduration = getReadableDuration(instance.duration) + } + + // Vérification pour éviter une erreur si `streams[0]` ou `tags` n'existe pas + instance.thumbnail = info.streams?.[0]?.tags?.thumbnail ?? + "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png"; + + // Obtenir le titre (sinon utiliser le nom du fichier) + instance.title = info.streams?.[0]?.tags?.title ?? media.attachment.name; + + // Obtenir l'auteur (s'il existe) + instance.author = info.streams?.[0]?.tags?.artist ?? instance.author; + + } catch (err) { + clog.error("Impossible de récupérer les informations de la musique : " + media.attachment.name) + clog.error(err) + return null; + } +} + +module.exports = {getMediaInformation} \ No newline at end of file diff --git a/backend/src/player/Finder.js b/backend/src/player/Finder.js deleted file mode 100644 index e69de29..0000000 diff --git a/backend/src/player/List.js b/backend/src/player/List.js index 71de905..c1616af 100644 --- a/backend/src/player/List.js +++ b/backend/src/player/List.js @@ -3,6 +3,7 @@ const { __glob } = require('../utils/GlobalVars') const PreviousDB = new Database("previous", __glob.PREVIOUSFILE, {}) const {LogType} = require("loguix") const clog = new LogType("List") +const { Song } = require('./Song') const AllLists = new Map() // Map @@ -43,6 +44,9 @@ class List { } nextSong() { + if(this.current != null) { + this.addPreviousSong(this.current) + } var song = null; if(!this.shuffle) { song = this.next[0] @@ -53,9 +57,11 @@ class List { this.next.splice(randomIndex, 1) } + this.setCurrent(song) return song } + clearNext() { this.next = new Array(); } @@ -64,6 +70,10 @@ class List { this.next.push(song) } + firstNext(song) { + this.next.unshift(song) + } + removeNextByIndex(index) { this.next.splice(index, 1) } @@ -75,15 +85,33 @@ class List { } getPrevious() { - return PreviousDB.data[this.guildId]; + const previousList = new Array() + + for(const song of PreviousDB.data[this.guildId]) { + previousList.push(new Song(song)) + } + return previousList; + } getPreviousSong() { + if(PreviousDB.data[this.guildId].length > 0) { + return new Song(PreviousDB.data[this.guildId][0]) + } else { + return null; + } + } + + previousSong() { + if(this.current != null) { + this.firstNext(this.current) + } if(PreviousDB.data[this.guildId].length > 0) { const song = PreviousDB.data[this.guildId][0] + // Remove the song from the previous list PreviousDB.data[this.guildId].splice(0, 1) savePrevious() - return song + return new Song(song) } else { return null; } @@ -116,6 +144,8 @@ class List { this.clearNext(); this.current = null this.shuffle = false; + AllLists.delete(this.guildId) + } setShuffle(value) { diff --git a/backend/src/player/Method/Media.js b/backend/src/player/Method/Media.js index 0185ffe..427d477 100644 --- a/backend/src/player/Method/Media.js +++ b/backend/src/player/Method/Media.js @@ -1,19 +1,28 @@ -const {createAudioResource, VoiceConnectionStatus} = require('@discordjs/voice'); +const {createAudioResource, VoiceConnectionStatus, createAudioPlayer} = require('@discordjs/voice'); const {LogType} = require('loguix') const clog = new LogType("Media") const plog = require("loguix").getInstance("Player") async function play(instance, song) { - //const resource = await song.getResource() - //Test with a local file - const resource = createAudioResource("C:\\Users\\picot\\Downloads\\Confrontation_Replique_Raphix.mp3") - console.log(resource) - // Wait until connection is ready - instance.connection.once(VoiceConnectionStatus.Ready, async () => { - instance.player.play(resource) - }) - plog.log(`GUILD : ${instance.guildId} - Lecture de la musique : ${song.title}`) + + try { + + instance.player = createAudioPlayer() + instance.generatePlayerEvents() + const player = instance.player + const resource = await song.getResource() // Remplace par ton fichier audio + + player.play(resource); + instance.connection.subscribe(player); + clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - Filename : ${song.filename}`) + + } catch(e) { + clog.error("Erreur lors de la lecture de la musique : " + song.title) + clog.error(e) + } + + } module.exports = {play} \ No newline at end of file diff --git a/backend/src/player/Player.js b/backend/src/player/Player.js index ad2e41d..94681e7 100644 --- a/backend/src/player/Player.js +++ b/backend/src/player/Player.js @@ -6,6 +6,7 @@ const plog = new LogType("Player") const clog = new LogType("Signal") const media = require('./Method/Media'); +const Activity = require('../discord/Activity'); const AllPlayers = new Map() @@ -39,33 +40,48 @@ class Player { channelId: channel.id, guildId: channel.guild.id, adapterCreator: channel.guild.voiceAdapterCreator, + selfDeaf: false, + selfMute: false }); this.player = createAudioPlayer() - - this.connection.subscribe(this.player) - + this.generatePlayerEvents() + this.connection.on('stateChange', (oldState, newState) => { clog.log(`GUILD : ${this.guildId} - [STATE] OLD : "${oldState.status}" NEW : "${newState.status}"`); + + // Si la connection est fermée, on détruit le player + + if(newState.status === VoiceConnectionStatus.Disconnected) { + this.leave() + } }); + } + + generatePlayerEvents() { + this.player.on('error', error => { plog.error(`GUILD : ${this.guildId} - Une erreur est survenue dans le player`); plog.error(error); }); - - this.player.on(AudioPlayerStatus.Idle, () => { + + this.player.on(AudioPlayerStatus.Idle, () => { + Activity.idleActivity() + this.queue.setCurrent(null) if(this.queue.next.length > 0) { - //TODO : Play next song - } + this.play(this.queue.nextSong()) + } }); this.player.on(AudioPlayerStatus.Playing, () => { plog.log(`GUILD : ${this.guildId} - Le player est en train de jouer le contenu suivant : ${this.queue.current.title}`); + Activity.setMusicActivity(this.queue.current.title, this.queue.current.author, this.queue.current.thumbnail) + }); - } + checkConnection() { if(this.connection === null) { clog.error(`GUILD : ${this.guildId} - La connection n'est pas définie`) @@ -78,43 +94,81 @@ class Player { } async play(song) { + if(this.checkConnection()) return + if(this.queue.current != null) { + this.player.stop() + } + this.queue.setCurrent(song) + if(song.type = "attachment") { media.play(this, song) } } async add(song) { - if(this.player.state.status = AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) { + if(this.player.state.status == AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) { this.play(song) return } this.queue.addNextSong(song) + plog.log(`GUILD : ${this.guildId} - La musique a été ajoutée à la liste de lecture : ${song.title}`) } async pause() { - if(this.player.state.status = AudioPlayerStatus.Paused) { + if(this.checkConnection()) return "no_music" + if(this.player.state.status == AudioPlayerStatus.Paused) { this.player.unpause() + plog.log(`GUILD : ${this.guildId} - La musique a été reprise`) + return false } else { this.player.pause() + plog.log(`GUILD : ${this.guildId} - La musique a été mise en pause`) + return true } } async leave() { + if(this.checkConnection()) return + if(this.queue.current != null) { + this.queue.addPreviousSong(this.queue.current) + } // Détruit la connection et le player et l'enlève de la liste des this.connection.destroy() this.player.stop() + Activity.idleActivity() + this.queue.destroy() AllPlayers.delete(this.guildId) clog.log("Connection détruite avec le guildId : " + this.guildId) plog.log("Player détruit avec le guildId : " + this.guildId) } + async skip() { + + if(this.checkConnection()) return "no_music" + if(this.queue.next.length === 0) { + return "no_music" + } + const songSkip = this.queue.nextSong() + this.play(songSkip) + return songSkip + } - + async previous() { + + if(this.checkConnection()) return "no_music" + if(this.queue.getPrevious().length === 0) { + return "no_music" + } + + const songPrevious = this.queue.previousSong() + this.play(songPrevious) + return songPrevious + } } -module.exports = {Player} +module.exports = {Player, AllPlayers} /* diff --git a/backend/src/player/Song.js b/backend/src/player/Song.js index 1a5dd8d..6f8f656 100644 --- a/backend/src/player/Song.js +++ b/backend/src/player/Song.js @@ -1,29 +1,43 @@ const {LogType} = require('loguix') const { createAudioResource, StreamType } = require('@discordjs/voice'); -const ffprobe = require('ffprobe'); -const ffprobeStatic = require('ffprobe-static'); -const { getReadableDuration } = require('../utils/TimeConverter'); + const clog = new LogType("Song") +const MediaInformation = require('../media/MediaInformation') class Song { title = "Aucun titre"; + filename = "Aucun fichier"; author = "Auteur inconnu" url; - thumbnail; + thumbnail = "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png" ; duration; readduration; type; + constructor(properties) { + if(properties) { + this.title = properties.title ?? this.title + this.filename = properties.filename ?? this.filename + this.author = properties.author ?? this.author + this.url = properties.url ?? this.url + this.thumbnail = properties.thumbnail ?? this.thumbnail + this.duration = properties.duration ?? this.duration + this.readduration = properties.readduration ?? this.readduration + this.type = properties.type ?? this.type + } + } + async processMedia(media, provider) { if(provider) this.author = provider // Check if media is a file or a link if(media.attachment) { this.url = media.attachment.url + this.filename = media.attachment.name this.type = "attachment" // In face, duration is null, get the metadata of the file to get the duration - await getMediaInformation(this, media) + await MediaInformation.getMediaInformation(this, media) } else { clog.error("Impossible de traiter le média") @@ -47,31 +61,3 @@ class Song { } module.exports = {Song} - -async function getMediaInformation(instance, media, provider) { - try { - const info = await ffprobe(media.attachment.url, { path: ffprobeStatic.path }); - if (info.streams?.[0]?.duration_ts) { - instance.duration = info.streams[0].duration; - instance.readduration = getReadableDuration(instance.duration) - } - - // Vérification pour éviter une erreur si `streams[0]` ou `tags` n'existe pas - instance.thumbnail = info.streams?.[0]?.tags?.thumbnail ?? - "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png"; - - // Obtenir le titre (sinon utiliser le nom du fichier) - instance.title = info.streams?.[0]?.tags?.title ?? media.attachment.name; - - // Obtenir l'auteur (s'il existe) - instance.author = info.streams?.[0]?.tags?.artist ?? instance.author; - - - - - } catch (err) { - clog.error("Impossible de récupérer les informations de la musique : " + this.name) - clog.error(err) - return null; - } -} \ No newline at end of file -- 2.30.2 From a060d00599641b51e959593becf81aacae74ea08 Mon Sep 17 00:00:00 2001 From: Raphix Date: Fri, 28 Feb 2025 19:21:16 +0100 Subject: [PATCH 4/6] Version 0.2.0 - Change Youtube Information Program --- backend/src/media/YoutubeInformation.js | 139 ++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 backend/src/media/YoutubeInformation.js diff --git a/backend/src/media/YoutubeInformation.js b/backend/src/media/YoutubeInformation.js new file mode 100644 index 0000000..650eb26 --- /dev/null +++ b/backend/src/media/YoutubeInformation.js @@ -0,0 +1,139 @@ +const {LogType} = require('loguix'); +const clog = new LogType("YoutubeInformation"); +const config = require('../utils/Database/Configuration'); +const YOUTUBE_API_KEY = config.getYoutubeApiKey() +const { Song } = require('../player/Song'); +const { Playlist } = require('../player/Playlist'); +const { getReadableDuration } = require('../utils/TimeConverter'); + + +async function +getQuery(query) { + // Check Query not null and a string + if(query === null && typeof query !== 'string') { + clog.error("Impossible de rechercher une vidéo YouTube, car la requête est nulle"); + return null; + } + // * Fetch + try { + const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=${encodeURIComponent(query)}&key=${YOUTUBE_API_KEY}`); + const data = await response.json(); + + var videoLink = null + const videoId = data.items[0]?.id.videoId; + if(videoId) videoLink = `https://www.youtube.com/watch?v=${videoId}`; + if(videoLink === null) { + clog.error("Impossible de récupérer le lien de la vidéo YouTube à partir de la requête"); + return null; + } + const song = await getVideo(videoLink); + + return song; + + } catch (error) { + clog.error('Erreur lors de la recherche YouTube: ' + error); + return null; + } +} + +async function getVideo(url) { + // Extract video ID from URL if it exists and is valid (11 characters) and if not return "NOT_VALID" + // Extract id from youtu.be youtube.com and music.youtube.com + const videoId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:watch\?v=)?([a-zA-Z0-9_-]{11})/); + if(videoId === null) { + clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL"); + return null; + } + // Fetch video information + try { + const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId[1]}&key=${YOUTUBE_API_KEY}`); + const data = await response.json(); + + const video = data.items[0]; + if(video) { + + const songReturn = new Song() + await songReturn.processYoutubeVideo(video); + + return songReturn; + } else { + clog.error("Impossible de récupérer la vidéo YouTube à partir de l'identifiant"); + return null; + } + } catch (error) { + clog.error('Erreur lors de la recherche de la vidéo YouTube:' + error); + return null; + } + + + + +} + +async function getPlaylist(url) { + // Check Query not null and a string + if(url === null && typeof url !== 'string') { + clog.error("Impossible de rechercher une playlist YouTube, car la requête est nulle"); + return null; + } + // * Fetch + try { + // For Playlist + const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/); + if(playlistId === null) { + clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL"); + return null; + } + const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&type=playlist&q=${encodeURIComponent(playlistId[1])}&key=${YOUTUBE_API_KEY}`); + const data = await response.json(); + + if(data.items.length === 0) { + clog.error("Impossible de récupérer la playlist YouTube à partir de l'identifiant"); + return null; + } + + const playlist = new Playlist() + playlist.type = "youtube" + playlist.author = data.items[0].snippet.channelTitle + playlist.authorId = data.items[0].snippet.channelId + playlist.title = data.items[0].snippet.title + playlist.thumbnail = data.items[0].snippet.thumbnails.high.url + playlist.description = data.items[0].snippet.description + playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}` + playlist.id = playlistId[1] + + + + + // Get all songs from playlist + + const responsePlaylist = await fetch(`https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=${playlistId[1]}&key=${YOUTUBE_API_KEY}&maxResults=100`); + const dataPlaylist = await responsePlaylist.json(); + + if(dataPlaylist.items.length === 0) { + clog.error("Impossible de récupérer les vidéos de la playlist YouTube à partir de l'identifiant ou la playlist est vide"); + return null; + } + + for (const video of dataPlaylist.items) { + const song = new Song() + video.id = video.snippet.resourceId.videoId + await song.processYoutubeVideo(video) + //? Add seconds to playlist duration + playlist.duration += song.duration + playlist.songs.push(song) + } + playlist.readduration = getReadableDuration(playlist.duration) + return playlist; + + + + + } catch (error) { + clog.error('Erreur lors de la recherche YouTube: ' + error); + return null; + } + +} + +module.exports = {getQuery, getVideo, getPlaylist} \ No newline at end of file -- 2.30.2 From c8c8fd71be910dae051f1a7eff213c2059a9b067 Mon Sep 17 00:00:00 2001 From: Raphix Date: Fri, 28 Feb 2025 19:21:47 +0100 Subject: [PATCH 5/6] Version 0.3.0-alpha1 - Youtube and Spotify support --- backend/package-lock.json | 521 +++++++++++++++----- backend/package.json | 8 +- backend/src/discord/Activity.js | 5 +- backend/src/discord/Bot.js | 3 + backend/src/discord/Commands/About.js | 2 +- backend/src/discord/Commands/Play.js | 61 ++- backend/src/discord/Commands/Queue.js | 3 + backend/src/main.js | 2 +- backend/src/media/SoundcloudInformation.js | 0 backend/src/media/SpotifyInformation.js | 112 +++++ backend/src/player/Finder.js | 43 ++ backend/src/player/List.js | 10 + backend/src/player/Method/Media.js | 12 +- backend/src/player/Method/Youtube.js | 37 ++ backend/src/player/Player.js | 24 +- backend/src/player/Playlist.js | 16 + backend/src/player/Song.js | 39 +- backend/src/utils/Database/Configuration.js | 22 +- backend/src/utils/Links.js | 79 +++ backend/src/utils/QueryType.js | 16 + backend/src/utils/Resolver.js | 32 ++ backend/src/utils/YoutubeDuration.js | 45 ++ 22 files changed, 925 insertions(+), 167 deletions(-) create mode 100644 backend/src/media/SoundcloudInformation.js create mode 100644 backend/src/media/SpotifyInformation.js create mode 100644 backend/src/player/Finder.js create mode 100644 backend/src/player/Method/Youtube.js create mode 100644 backend/src/player/Playlist.js create mode 100644 backend/src/utils/Links.js create mode 100644 backend/src/utils/QueryType.js create mode 100644 backend/src/utils/Resolver.js create mode 100644 backend/src/utils/YoutubeDuration.js diff --git a/backend/package-lock.json b/backend/package-lock.json index 4965292..e3ccb57 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,15 +1,17 @@ { "name": "chopin-backend", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "chopin-backend", - "version": "0.2.0", + "version": "0.3.0", "license": "ISC", "dependencies": { "@discordjs/voice": "^0.18.0", + "@distube/ytdl-core": "^4.11.5", + "@distube/ytsr": "2.0.4", "cors": "^2.8.5", "discord-player": "^7.1.0", "discord.js": "^14.18.0", @@ -22,9 +24,9 @@ "nodemon": "^3.1.9", "pm2": "^5.4.3", "socket.io": "^4.8.1", + "spotify-web-api-node": "^5.0.2", "uuid": "^11.1.0", - "webmetrik": "^0.1.4", - "ytdl-core": "^4.11.5" + "webmetrik": "^0.1.4" } }, "node_modules/@derhuerst/http-basic": { @@ -251,10 +253,55 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@distube/ytdl-core": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@distube/ytdl-core/-/ytdl-core-4.16.4.tgz", + "integrity": "sha512-r0ZPMMB5rbUSQSez//dYDWjPSAEOm6eeV+9gyR+1vngGYFUi953Z/CoF4epTBS40X8dR32gyH3ERlh7NbnCaRg==", + "license": "MIT", + "dependencies": { + "http-cookie-agent": "^6.0.8", + "https-proxy-agent": "^7.0.6", + "m3u8stream": "^0.8.6", + "miniget": "^4.2.3", + "sax": "^1.4.1", + "tough-cookie": "^5.1.0", + "undici": "^7.3.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/distubejs/ytdl-core?sponsor" + } + }, + "node_modules/@distube/ytdl-core/node_modules/undici": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.3.0.tgz", + "integrity": "sha512-Qy96NND4Dou5jKoSJ2gm8ax8AJM/Ey9o9mz7KN1bb9GP+G0l20Zw8afxTnY2f4b7hmhn/z8aC2kfArVQlAhFBw==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/@distube/ytsr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@distube/ytsr/-/ytsr-2.0.4.tgz", + "integrity": "sha512-OiSWgARQ9LTj+dXt3jmMFzUH4l86VVCD4dVC4hEHNXdqp+DyU4QEzc+W6YY6//kWkvzTaUxOo7JUY7lBzwIF0A==", + "license": "MIT", + "dependencies": { + "undici": "^6.18.2" + }, + "engines": { + "node": ">=14.0" + }, + "funding": { + "url": "https://github.com/distubejs/ytsr?sponsor" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "cpu": [ "ppc64" ], @@ -268,9 +315,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", "cpu": [ "arm" ], @@ -284,9 +331,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", "cpu": [ "arm64" ], @@ -300,9 +347,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", "cpu": [ "x64" ], @@ -316,9 +363,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", "cpu": [ "arm64" ], @@ -332,9 +379,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", "cpu": [ "x64" ], @@ -348,9 +395,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", "cpu": [ "arm64" ], @@ -364,9 +411,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", "cpu": [ "x64" ], @@ -380,9 +427,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", "cpu": [ "arm" ], @@ -396,9 +443,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", "cpu": [ "arm64" ], @@ -412,9 +459,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", "cpu": [ "ia32" ], @@ -428,9 +475,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", "cpu": [ "loong64" ], @@ -444,9 +491,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", "cpu": [ "mips64el" ], @@ -460,9 +507,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", "cpu": [ "ppc64" ], @@ -476,9 +523,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", "cpu": [ "riscv64" ], @@ -492,9 +539,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", "cpu": [ "s390x" ], @@ -508,9 +555,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "cpu": [ "x64" ], @@ -524,9 +571,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", "cpu": [ "arm64" ], @@ -540,9 +587,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", "cpu": [ "x64" ], @@ -556,9 +603,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", "cpu": [ "arm64" ], @@ -572,9 +619,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", "cpu": [ "x64" ], @@ -588,9 +635,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", "cpu": [ "x64" ], @@ -604,9 +651,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", "cpu": [ "arm64" ], @@ -620,9 +667,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", "cpu": [ "ia32" ], @@ -636,9 +683,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", "cpu": [ "x64" ], @@ -1507,6 +1554,12 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1836,12 +1889,33 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "license": "MIT" }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1908,6 +1982,12 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "license": "MIT" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -2024,6 +2104,15 @@ "node": ">= 14" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2335,10 +2424,25 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -2348,31 +2452,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "node_modules/escape-html": { @@ -2547,6 +2651,12 @@ "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fclone": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", @@ -2754,6 +2864,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.3.tgz", + "integrity": "sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -2767,6 +2892,16 @@ "node": ">=12.20.0" } }, + "node_modules/formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "license": "MIT", + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2983,6 +3118,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -3012,6 +3162,30 @@ "license": "ISC", "peer": true }, + "node_modules/http-cookie-agent": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-6.0.8.tgz", + "integrity": "sha512-qnYh3yLSr2jBsTYkw11elq+T361uKAJaZ2dR4cfYZChw1dt9uL5t3zSUwehoqqVb4oldk1BpkXKm2oat8zV+oA==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/3846masa" + }, + "peerDependencies": { + "tough-cookie": "^4.0.0 || ^5.0.0", + "undici": "^5.11.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "undici": { + "optional": true + } + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -5447,6 +5621,15 @@ "node": ">= 12" } }, + "node_modules/spotify-web-api-node": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/spotify-web-api-node/-/spotify-web-api-node-5.0.2.tgz", + "integrity": "sha512-r82dRWU9PMimHvHEzL0DwEJrzFk+SMCVfq249SLt3I7EFez7R+jeoKQd+M1//QcnjqlXPs2am4DFsGk8/GCsrA==", + "license": "MIT", + "dependencies": { + "superagent": "^6.1.0" + } + }, "node_modules/sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -5616,6 +5799,64 @@ "node": ">= 6" } }, + "node_modules/superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 7.0.0" + } + }, + "node_modules/superagent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/superagent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -5742,6 +5983,24 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tldts": { + "version": "6.1.79", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.79.tgz", + "integrity": "sha512-wjlYwK8lC/WcywLWf3A7qbK07SexezXjTRVwuPWXHvcjD7MnpPS2RXY5rLO3g12a8CNc7Y7jQRQsV7XyuBZjig==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.79" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.79", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.79.tgz", + "integrity": "sha512-HM+Ud/2oQuHt4I43Nvjc213Zji/z25NSH5OkJskJwHXNtYh9DTRlHMDFhms9dFMP7qyve/yVaXFIxmcJ7TdOjw==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5790,6 +6049,18 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tough-cookie": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", + "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -5825,26 +6096,26 @@ "license": "0BSD" }, "node_modules/tsup": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.6.tgz", - "integrity": "sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.4.0.tgz", + "integrity": "sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==", "license": "MIT", "dependencies": { - "bundle-require": "^5.0.0", + "bundle-require": "^5.1.0", "cac": "^6.7.14", - "chokidar": "^4.0.1", - "consola": "^3.2.3", - "debug": "^4.3.7", - "esbuild": "^0.24.0", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.25.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", - "rollup": "^4.24.0", + "rollup": "^4.34.8", "source-map": "0.8.0-beta.0", "sucrase": "^3.35.0", - "tinyexec": "^0.3.1", - "tinyglobby": "^0.2.9", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "bin": { @@ -6288,20 +6559,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" - }, - "node_modules/ytdl-core": { - "version": "4.11.5", - "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.11.5.tgz", - "integrity": "sha512-27LwsW4n4nyNviRCO1hmr8Wr5J1wLLMawHCQvH8Fk0hiRqrxuIu028WzbJetiYH28K8XDbeinYW4/wcHQD1EXA==", - "license": "MIT", - "dependencies": { - "m3u8stream": "^0.8.6", - "miniget": "^4.2.2", - "sax": "^1.1.3" - }, - "engines": { - "node": ">=12" - } } } } diff --git a/backend/package.json b/backend/package.json index f883299..f3648e1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "chopin-backend", - "version": "0.2.0", + "version": "0.3.0", "description": "Discord Bot for music - Fetching everywhere !", "main": "src/main.js", "nodemonConfig": { @@ -19,6 +19,8 @@ "license": "ISC", "dependencies": { "@discordjs/voice": "^0.18.0", + "@distube/ytdl-core": "^4.11.5", + "@distube/ytsr": "2.0.4", "cors": "^2.8.5", "discord-player": "^7.1.0", "discord.js": "^14.18.0", @@ -31,8 +33,8 @@ "nodemon": "^3.1.9", "pm2": "^5.4.3", "socket.io": "^4.8.1", + "spotify-web-api-node": "^5.0.2", "uuid": "^11.1.0", - "webmetrik": "^0.1.4", - "ytdl-core": "^4.11.5" + "webmetrik": "^0.1.4" } } diff --git a/backend/src/discord/Activity.js b/backend/src/discord/Activity.js index bac8bed..c3d957b 100644 --- a/backend/src/discord/Activity.js +++ b/backend/src/discord/Activity.js @@ -13,10 +13,7 @@ function setMusicActivity(songName, artistName, imageUrl) { const client = bot.getClient() client.user.setActivity(`${songName} - ${artistName}`,{ type: ActivityType.Listening, - assets: { - largeImage: imageUrl, - largeText: songName - } + url: imageUrl }); dlog.log(`Activité mise à jour : ${songName} - ${artistName}`) } diff --git a/backend/src/discord/Bot.js b/backend/src/discord/Bot.js index ba4a1bc..0cb9378 100644 --- a/backend/src/discord/Bot.js +++ b/backend/src/discord/Bot.js @@ -68,6 +68,9 @@ function init() { } }) + // TODO: Implement the disconnect event for the bot + + client.login(config.getToken()) diff --git a/backend/src/discord/Commands/About.js b/backend/src/discord/Commands/About.js index 434b499..85355d5 100644 --- a/backend/src/discord/Commands/About.js +++ b/backend/src/discord/Commands/About.js @@ -11,7 +11,7 @@ const command = new Command("about", "Affiche des informations sur le bot", (cli const seconds = Math.floor(uptime % 60); const embed = new Embed() - embed.setColor(0xb0f542) + embed.setColor(237, 12, 91) embed.setThumbnail("https://cdn.discordapp.com/avatars/" + client.user.id + "/" + client.user.avatar + ".png") embed.setTitle('Subsonics - Chopin') embed.addField('Informations',"") diff --git a/backend/src/discord/Commands/Play.js b/backend/src/discord/Commands/Play.js index 7d334a8..73b9332 100644 --- a/backend/src/discord/Commands/Play.js +++ b/backend/src/discord/Commands/Play.js @@ -1,15 +1,72 @@ const { Command } = require("../Command"); const { Embed, EmbedError } = require("../Embed"); const { Player } = require("../../player/Player"); +const Finder = require("../../player/Finder"); +const { Playlist } = require("../../player/Playlist"); -const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", (client, interaction) => { +const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", async (client, interaction) => { if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer une musique !").send(interaction) const url = interaction.options.get("url") const channel = interaction.member.voice.channel + const now = interaction.options.getBoolean("now") || false + await Finder.search(url.value).then((song) => { + if(!song) return new EmbedError("Impossible de trouver la musique à partir du lien donné ou des mots clés donnés").send(interaction) -}, [{type: "STRING", name: "url", description: "Lien audio (Youtube / Soundclound / Spotify)", required: true}] + const player = new Player(channel.guildId) + player.join(channel) + + const embed = new Embed() + embed.setColor(0x15e6ed) + + // Check if song is playlist + if(song instanceof Playlist) { + + if(now) { + player.readPlaylist(song, true) + embed.setTitle('**Lecture immédiate**') + } else { + player.readPlaylist(song) + embed.setTitle('**Ajout à la liste de lecture**') + } + embed.setDescription('**Playlist : **' + song.songs.length + ' musiques') + embed.addField('**Titre : **' + song.title, "") + embed.addField('**Demandé par : **', interaction.member.user.username,) + embed.addField('**Auteur : **', song.author) + embed.addField('**Durée : **', song.readduration) + + embed.setThumbnail(song.thumbnail) + + } else { + + if(now) { + + player.play(song) + embed.setTitle('**Lecture immédiate**') + + } else { + player.add(song) + embed.setTitle('**Ajout à liste de lecture**') + + } + + embed.setDescription('**Titre : **' + song.title) + embed.addField('**Durée : **', song.readduration) + embed.addField("**Artiste : **",song.author) + embed.addField('**Demandé par **' + interaction.member.user.username, "") + embed.setThumbnail(song.thumbnail) + + + } + + + + embed.send(interaction) + }) + +}, [{type: "STRING", name: "url", description: "Recherche / Lien audio (Youtube / Soundclound / Spotify)", required: true}, + {type:"BOOLEAN", name: "now", description: "Lire le média maintenant", required: false}] ) module.exports = {command} \ No newline at end of file diff --git a/backend/src/discord/Commands/Queue.js b/backend/src/discord/Commands/Queue.js index f67a937..85befb1 100644 --- a/backend/src/discord/Commands/Queue.js +++ b/backend/src/discord/Commands/Queue.js @@ -23,7 +23,10 @@ const command = new Command("liste", "Affiche la file d'attente", (client, inter embed.setColor(0x15e6ed) embed.setThumbnail("https://www.iconsdb.com/icons/download/white/list-2-64.png") embed.setTitle('**File d\'attente :**') + embed.setDescription('**' + queue.length + ' musiques**') queue.forEach((song, index) => { + // max 24 fields + if(index > 10) return embed.addField(`**${index+1} - ${song.title}**`, `**Durée : **${song.readduration}\n**Artiste : **${song.author}`) }) diff --git a/backend/src/main.js b/backend/src/main.js index 6c1a5ab..ccc049e 100644 --- a/backend/src/main.js +++ b/backend/src/main.js @@ -18,7 +18,7 @@ metric.publishMetrics("8001", "raphraph") setup(); -function setup() { +async function setup() { const DiscordBot = require("./discord/Bot") DiscordBot.init() } \ No newline at end of file diff --git a/backend/src/media/SoundcloudInformation.js b/backend/src/media/SoundcloudInformation.js new file mode 100644 index 0000000..e69de29 diff --git a/backend/src/media/SpotifyInformation.js b/backend/src/media/SpotifyInformation.js new file mode 100644 index 0000000..eea84d6 --- /dev/null +++ b/backend/src/media/SpotifyInformation.js @@ -0,0 +1,112 @@ +const {LogType} = require('loguix'); +const clog = new LogType("SpotifyInformation"); +const config = require('../utils/Database/Configuration'); +const SPOTIFY_CLIENT_ID = config.getSpotifyClientId() +const SPOTIFY_CLIENT_SECRET = config.getSpotifyClientSecret() +const SpotifyWebApi = require('spotify-web-api-node'); +const {Playlist} = require('../player/Playlist'); +const {Song} = require('../player/Song'); +const youtube = require("../media/YoutubeInformation"); +const {getReadableDuration} = require('../utils/TimeConverter'); + +const spotifyApi = new SpotifyWebApi({ + clientId: SPOTIFY_CLIENT_ID, + clientSecret: SPOTIFY_CLIENT_SECRET, +}); + +async function getSong(url) { + try { + const data = await spotifyApi.clientCredentialsGrant(); + spotifyApi.setAccessToken(data.body['access_token']); + + const parts = url.split('/'); + const trackId = parts[parts.length - 1]; + + if(!trackId) { + clog.error("Impossible de récupérer l'identifiant de la piste Spotify à partir de l'URL"); + return null; + } + const trackInfo = await spotifyApi.getTrack(trackId); + const trackName = trackInfo.body.name; + const artistName = trackInfo.body.artists[0].name; + + return `${trackName} - ${artistName}`; + } catch (error) { + console.error('Erreur lors de la récupération des données :', error); + + } +} + +async function getAlbum(albumId) { + + +} + +async function getPlaylist(url) { + // Get the playlist and return a Playlist Object + const data = await spotifyApi.clientCredentialsGrant(); + spotifyApi.setAccessToken(data.body['access_token']); + + const parts = url.split('/'); + const playlistId = parts[parts.indexOf('playlist') + 1].split('?')[0]; + + spotifyApi.getPlaylist(playlistId) + .then(function(data) { + const info = data.body; + + const playlist = new Playlist() + playlist.title = info.name; + playlist.author = info.owner.display_name; + playlist.authorId = info.owner.id; + playlist.thumbnail = info.images[0].url; + playlist.url = info.external_urls.spotify; + playlist.id = playlistId; + playlist.type = "spotify"; + + const tracks = info.tracks.items; + tracks.forEach(async function(track) { + + var trackName = track.track.name; + var artistName = track.track.artists[0].name; + var queryForYoutube = `${trackName} - ${artistName}`; + + var urlYoutubeFounded = await youtube.getQuery(queryForYoutube).then(function(songFind) { + if(!songFind) return null; + return songFind.url; + }); + + clog.log("URL de la vidéo YouTube trouvée : " + urlYoutubeFounded); + + if(!urlYoutubeFounded) { + clog.error("Impossible de récupérer l'URL de la vidéo YouTube à partir de la requête " + queryForYoutube); + + } else { + const song = new Song(); + song.title = track.track.name; + song.author = track.track.artists[0].name; + song.url = urlYoutubeFounded; + song.thumbnail = track.track.album.images[0].url; + song.id = track.track.id; + song.duration = track.track.duration_ms / 1000; + song.readduration = getReadableDuration(track.track.duration_ms); + + playlist.duration += track.track.duration_ms; + + + playlist.songs.push(song); + } + + + }); + + playlist.readduration = getReadableDuration(playlist.duration); + return playlist; + + }, function(err) { + clog.error('Une erreur s\'est produite lors de la récupération de la playlist'); + clog.error(err); + }); +} + + +module.exports = {getSong, getAlbum, getPlaylist} \ No newline at end of file diff --git a/backend/src/player/Finder.js b/backend/src/player/Finder.js new file mode 100644 index 0000000..46e02d5 --- /dev/null +++ b/backend/src/player/Finder.js @@ -0,0 +1,43 @@ +const Resolver = require('../utils/Resolver'); +const { QueryType } = require('../utils/QueryType'); +const { Links } = require('../utils/Links'); +const youtube = require("../media/YoutubeInformation") +const spotify = require("../media/SpotifyInformation") + + +async function search(query) { + const type = Resolver.getQueryType(query) + if(type == QueryType.YOUTUBE_SEARCH) { + + return await youtube.getQuery(query) + + } + if(type == QueryType.YOUTUBE_VIDEO) { + + return await youtube.getVideo(query) + } + if(type == QueryType.YOUTUBE_PLAYLIST) { + + return await youtube.getPlaylist(query) + } + if(type == QueryType.SPOTIFY_SONG) { + return await youtube.getQuery(await spotify.getSong(query)) + + } + if(type == QueryType.SPOTIFY_ALBUM) { + + } + if(type == QueryType.SPOTIFY_PLAYLIST) { + return await spotify.getPlaylist(query) + + } + if(type == QueryType.SOUNDCLOUD_TRACK) { + + } + if(type == QueryType.SOUNDCLOUD_PLAYLIST) { + + } + // TODO: Add more providers +} + +module.exports = {search} \ No newline at end of file diff --git a/backend/src/player/List.js b/backend/src/player/List.js index c1616af..9c4508b 100644 --- a/backend/src/player/List.js +++ b/backend/src/player/List.js @@ -177,6 +177,16 @@ class List { } } + addNextPlaylist(playlist, firstAlreadyPlayed) { + if(firstAlreadyPlayed) { + playlist.songs.shift() + } + + for(const song of playlist.songs) { + this.addNextSong(song) + } + + } diff --git a/backend/src/player/Method/Media.js b/backend/src/player/Method/Media.js index 427d477..511a25f 100644 --- a/backend/src/player/Method/Media.js +++ b/backend/src/player/Method/Media.js @@ -1,21 +1,21 @@ -const {createAudioResource, VoiceConnectionStatus, createAudioPlayer} = require('@discordjs/voice'); +const {createAudioResource, VoiceConnectionStatus, createAudioPlayer, StreamType} = require('@discordjs/voice'); const {LogType} = require('loguix') const clog = new LogType("Media") const plog = require("loguix").getInstance("Player") async function play(instance, song) { - - try { instance.player = createAudioPlayer() instance.generatePlayerEvents() const player = instance.player - const resource = await song.getResource() // Remplace par ton fichier audio + song.resource = await createAudioResource(song.url, { + inputType: StreamType.Arbitrary + }) // Remplace par ton fichier audio - player.play(resource); + player.play(song.resource); instance.connection.subscribe(player); - clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - Filename : ${song.filename}`) + clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`) } catch(e) { clog.error("Erreur lors de la lecture de la musique : " + song.title) diff --git a/backend/src/player/Method/Youtube.js b/backend/src/player/Method/Youtube.js new file mode 100644 index 0000000..aaa4c45 --- /dev/null +++ b/backend/src/player/Method/Youtube.js @@ -0,0 +1,37 @@ +const {createAudioResource, VoiceConnectionStatus, createAudioPlayer, StreamType} = require('@discordjs/voice'); +const {LogType} = require('loguix') +const clog = new LogType("Youtube") +const plog = require("loguix").getInstance("Player") +const ytdl = require('@distube/ytdl-core') + +async function play(instance, song) { + try { + + instance.player = createAudioPlayer() + instance.generatePlayerEvents() + const player = instance.player + const stream = ytdl(song.url, { + quality: 'highestaudio', + highWaterMark: 1 << 30, + liveBuffer: 20000, + dlChunkSize: 0, + bitrate: 128, + + }); + + // Add compressor to the audio resource + song.resource = createAudioResource(stream); + + + + player.play(song.resource); + instance.connection.subscribe(player); + clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`) + + } catch(e) { + clog.error("Erreur lors de la lecture de la musique : " + song.title) + clog.error(e) + } +} + +module.exports = {play} diff --git a/backend/src/player/Player.js b/backend/src/player/Player.js index 94681e7..39a6588 100644 --- a/backend/src/player/Player.js +++ b/backend/src/player/Player.js @@ -6,6 +6,7 @@ const plog = new LogType("Player") const clog = new LogType("Signal") const media = require('./Method/Media'); +const youtube = require('./Method/Youtube'); const Activity = require('../discord/Activity'); const AllPlayers = new Map() @@ -75,6 +76,7 @@ class Player { }); this.player.on(AudioPlayerStatus.Playing, () => { + plog.log(`GUILD : ${this.guildId} - Le player est en train de jouer le contenu suivant : ${this.queue.current.title}`); Activity.setMusicActivity(this.queue.current.title, this.queue.current.author, this.queue.current.thumbnail) @@ -98,11 +100,18 @@ class Player { if(this.queue.current != null) { this.player.stop() } + this.queue.setCurrent(song) - if(song.type = "attachment") { + if(song.type == "attachment") { media.play(this, song) } + if(song.type == 'youtube') { + youtube.play(this, song) + } + + + // TODO: Créer une méthode pour les autres types de médias } async add(song) { @@ -115,6 +124,19 @@ class Player { plog.log(`GUILD : ${this.guildId} - La musique a été ajoutée à la liste de lecture : ${song.title}`) } + async readPlaylist(playlist, now) { + if(this.player.state.status == AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) { + this.play(playlist.songs[0]) + } + if(now) { + this.play(playlist.songs[0]) + this.queue.addNextPlaylist(playlist, true) + } else { + this.queue.addNextPlaylist(playlist) + } + plog.log(`GUILD : ${this.guildId} - La playlist a été ajoutée à la liste de lecture : ${playlist.title}`) + } + async pause() { if(this.checkConnection()) return "no_music" if(this.player.state.status == AudioPlayerStatus.Paused) { diff --git a/backend/src/player/Playlist.js b/backend/src/player/Playlist.js new file mode 100644 index 0000000..48838aa --- /dev/null +++ b/backend/src/player/Playlist.js @@ -0,0 +1,16 @@ +class Playlist { + title = "Aucun titre"; + id; + url; + author = "Auteur inconnu"; + authorId; + songs = []; + thumbnail = "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png" ; + duration = 0; + readduration; + description; + type; +} + +module.exports = {Playlist}; + diff --git a/backend/src/player/Song.js b/backend/src/player/Song.js index 6f8f656..ff5bb2c 100644 --- a/backend/src/player/Song.js +++ b/backend/src/player/Song.js @@ -1,39 +1,44 @@ const {LogType} = require('loguix') -const { createAudioResource, StreamType } = require('@discordjs/voice'); - const clog = new LogType("Song") const MediaInformation = require('../media/MediaInformation') +const YoutubeDuration = require('../utils/YoutubeDuration'); +const { getReadableDuration } = require('../utils/TimeConverter'); class Song { title = "Aucun titre"; - filename = "Aucun fichier"; + id = "Aucun fichier"; author = "Auteur inconnu" + authorId; url; thumbnail = "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png" ; duration; readduration; type; + resource; constructor(properties) { if(properties) { + this.type = properties.type ?? this.type this.title = properties.title ?? this.title - this.filename = properties.filename ?? this.filename + this.id = properties.id ?? this.id this.author = properties.author ?? this.author this.url = properties.url ?? this.url this.thumbnail = properties.thumbnail ?? this.thumbnail this.duration = properties.duration ?? this.duration this.readduration = properties.readduration ?? this.readduration this.type = properties.type ?? this.type + this.authorId = properties.authorId ?? this.authorId } } async processMedia(media, provider) { - if(provider) this.author = provider + if(provider) this.author = provider; + if(provider) this.authorId = provider; // Check if media is a file or a link if(media.attachment) { this.url = media.attachment.url - this.filename = media.attachment.name + this.id = media.attachment.name this.type = "attachment" // In face, duration is null, get the metadata of the file to get the duration @@ -45,18 +50,20 @@ class Song { } - async getResource() { - - const resource = createAudioResource(this.url, { - inputType: StreamType.Arbitrary - }) - return resource + async processYoutubeVideo(video) { + this.title = video.snippet.title + this.author = video.snippet.channelTitle + this.authorId = video.snippet.channelId + this.thumbnail = video.snippet.thumbnails.standard.url + this.url = `https://www.youtube.com/watch?v=${video.id}` + this.type = "youtube" + this.id = video.id - + this.duration = await YoutubeDuration.getDurationVideo(video.id) + this.readduration = getReadableDuration(this.duration) + + return this } - - - } diff --git a/backend/src/utils/Database/Configuration.js b/backend/src/utils/Database/Configuration.js index eb46b32..50cd2c0 100644 --- a/backend/src/utils/Database/Configuration.js +++ b/backend/src/utils/Database/Configuration.js @@ -10,6 +10,13 @@ const config = new Database("config", __glob.DATA + path.sep + "config.json", { report: { channel : "", contact : "" + }, + api: { + youtube: "", + spotify: { + clientId: "", + clientSecret: "" + } } }) @@ -25,9 +32,22 @@ function getReportContact() { return config.data.report.contact } +function getYoutubeApiKey() { + return config.data.api.youtube +} + +function getSpotifyClientId() { + return config.data.api.spotify.clientId +} + +function getSpotifyClientSecret() { + + return config.data.api.spotify.clientSecret +} + if(getToken() == "") { clog.error("Impossible de démarrer sans token valide") process.exit(1) } -module.exports = {getToken, getReportChannel, getReportContact} \ No newline at end of file +module.exports = {getToken, getReportChannel, getReportContact, getYoutubeApiKey, getSpotifyClientId, getSpotifyClientSecret} \ No newline at end of file diff --git a/backend/src/utils/Links.js b/backend/src/utils/Links.js new file mode 100644 index 0000000..589b386 --- /dev/null +++ b/backend/src/utils/Links.js @@ -0,0 +1,79 @@ +const YoutubeLinks = [ + "youtube.com", + "youtu.be", + "music.youtube.com", + "gaming.youtube.com", + "www.youtube.com", + "m.youtube.com" +] + + +var youtubePlaylistRegex = new RegExp(/^https?:\/\/(www.)?youtube.com\/playlist\?list=((PL|FL|UU|LL|RD|OL)[a-zA-Z0-9-_]{16,41})$/) +var youtubeVideoURLRegex = new RegExp(/^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:watch\?v=))([\w-]{11})(\S+)?$/) +var youtubeVideoIdRegex = new RegExp(/^[a-zA-Z0-9-_]{11}$/) + + + + +const SpotifyLinks = [ + "open.spotify.com", + "embed.spotify.com" +] + +var spotifySongRegex = new RegExp(/^https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(intl-([a-z]|[A-Z])+\/)?(?:track\/|\?uri=spotify:track:)((\w|-){22})(\?si=.+)?$/) +var spotifyPlaylistRegex = new RegExp(/^https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(intl-([a-z]|[A-Z])+\/)?(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})(\?si=.+)?$/) +var spotifyAlbumRegex = new RegExp(/^https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(intl-([a-z]|[A-Z])+\/)?(?:album\/|\?uri=spotify:album:)((\w|-){22})(\?si=.+)?$/) + + +const SoundcloudLinks = [ + "soundcloud.com" +] + + +var soundcloudTrackRegex = new RegExp(/^https?:\/\/(m.|www.)?soundcloud.com\/(\w|-)+\/(\w|-)+(.+)?$/) +var soundcloudPlaylistRegex = new RegExp(/^https?:\/\/(m.|www.)?soundcloud.com\/(\w|-)+\/sets\/(\w|-)+(.+)?$/) + +/** + * @typedef {Object} Links + * @property {Object} regex + * @property {Object} regex.youtube + * @property {RegExp} regex.youtube.playlist + * @property {RegExp} regex.youtube.videoURL + * @property {RegExp} regex.youtube.videoId + * @property {Object} regex.spotify + * @property {RegExp} regex.spotify.song + * @property {RegExp} regex.spotify.playlist + * @property {RegExp} regex.spotify.album + * @property {Object} regex.soundcloud + * @property {RegExp} regex.soundcloud.track + * @property {RegExp} regex.soundcloud.playlist + * @property {Object} types + * @property {Array} types.youtube + * @property {Array} types.spotify + * @property {Array} types.soundcloud + */ +const Links = { + regex: { + youtube: { + playlist: youtubePlaylistRegex, + videoURL: youtubeVideoURLRegex, + videoId: youtubeVideoIdRegex + }, + spotify: { + song: spotifySongRegex, + playlist: spotifyPlaylistRegex, + album: spotifyAlbumRegex + }, + soundcloud: { + track: soundcloudTrackRegex, + playlist: soundcloudPlaylistRegex + } + }, + types: { + youtube: YoutubeLinks, + spotify: SpotifyLinks, + soundcloud: SoundcloudLinks + } +} + +module.exports = {Links} \ No newline at end of file diff --git a/backend/src/utils/QueryType.js b/backend/src/utils/QueryType.js new file mode 100644 index 0000000..25871f7 --- /dev/null +++ b/backend/src/utils/QueryType.js @@ -0,0 +1,16 @@ +/** + * Enum for query types + * @readonly + */ +const QueryType = { + SPOTIFY_PLAYLIST: 'spotify_playlist', + SPOTIFY_ALBUM: 'spotify_album', + SPOTIFY_SONG: 'spotify_song', + YOUTUBE_PLAYLIST: 'youtube_playlist', + YOUTUBE_VIDEO: 'youtube_video', + SOUNDCLOUD_TRACK: 'soundcloud_track', + SOUNDCLOUD_PLAYLIST: 'soundcloud_playlist', + YOUTUBE_SEARCH: 'youtube_search', +} + +module.exports = { QueryType }; \ No newline at end of file diff --git a/backend/src/utils/Resolver.js b/backend/src/utils/Resolver.js new file mode 100644 index 0000000..2a57ff9 --- /dev/null +++ b/backend/src/utils/Resolver.js @@ -0,0 +1,32 @@ +const {Links} = require('./Links') +const {QueryType} = require('./QueryType') + +function getQueryType(url) { + // Check if it's string + + if(typeof url !== "string") return "NOT_STRING" + // Check if it's a Youtube link + + if(Links.regex.youtube.playlist.test(url)) return QueryType.YOUTUBE_PLAYLIST + if(Links.regex.youtube.videoURL.test(url)) return QueryType.YOUTUBE_VIDEO + + // Check if it's a Spotify link + + if(Links.regex.spotify.playlist.test(url)) return QueryType.SPOTIFY_PLAYLIST + if(Links.regex.spotify.album.test(url)) return QueryType.SPOTIFY_ALBUM + if(Links.regex.spotify.song.test(url)) return QueryType.SPOTIFY_SONG + + // Check if it's a Soundcloud link + + if(Links.regex.soundcloud.track.test(url)) return QueryType.SOUNDCLOUD_TRACK + if(Links.regex.soundcloud.playlist.test(url)) return QueryType.SOUNDCLOUD_PLAYLIST + + + + return QueryType.YOUTUBE_SEARCH + + + +} + +module.exports = {getQueryType} \ No newline at end of file diff --git a/backend/src/utils/YoutubeDuration.js b/backend/src/utils/YoutubeDuration.js new file mode 100644 index 0000000..b3f496a --- /dev/null +++ b/backend/src/utils/YoutubeDuration.js @@ -0,0 +1,45 @@ +const config = require('../utils/Database/Configuration'); +const YOUTUBE_API_KEY = config.getYoutubeApiKey() + +async function getDurationVideo(videoId) { + const clog = require("loguix").getInstance("YoutubeInformation"); + // Check videoId if valid + if(videoId === null && typeof videoId !== 'string') { + clog.error("Impossible de récupérer la durée de la vidéo YouTube, car l'identifiant est nul ou n'est pas une chaîne de caractères"); + return null; + } + + // Fetch video information + try { + const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id=${videoId}&key=${YOUTUBE_API_KEY}`); + const data = await response.json(); + const video = data.items[0]; + if(video) { + + if(video.contentDetails.duration == "P0D") return "LIVE"; + const duration = video.contentDetails.duration; + //Convert ISO 8601 duration to seconds + return parseDuration(duration); + + + } else { + clog.error("Impossible de récupérer la durée de la vidéo YouTube à partir de l'identifiant"); + return null; + } + } catch (error) { + clog.error('Erreur lors de la recherche de la durée de la vidéo YouTube:', error); + return null; + } + + +} + +function parseDuration(duration) { + const match = duration.match(/PT(\d+H)?(\d+M)?(\d+S)?/); + const hours = parseInt(match[1]) || 0; + const minutes = parseInt(match[2]) || 0; + const seconds = parseInt(match[3]) || 0; + return hours * 3600 + minutes * 60 + seconds; +} + +module.exports = {getDurationVideo} \ No newline at end of file -- 2.30.2 From 2a934d14ae18a3639250cd4af5025af47e164bee Mon Sep 17 00:00:00 2001 From: Raphix Date: Sat, 1 Mar 2025 18:01:17 +0100 Subject: [PATCH 6/6] =?UTF-8?q?Version=200.3.0=20-=20Ajout=20des=20premi?= =?UTF-8?q?=C3=A8res=20fonctionnalit=C3=A9s=20du=20Player?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package-lock.json | 61 ++++++-- backend/package.json | 4 +- backend/src/discord/Bot.js | 41 +++++- backend/src/discord/Commands/Play.js | 70 ++++++---- backend/src/media/SoundcloudInformation.js | 85 ++++++++++++ backend/src/media/SpotifyInformation.js | 153 +++++++++++++++------ backend/src/media/YoutubeInformation.js | 126 ++++++----------- backend/src/player/Finder.js | 5 +- backend/src/player/Method/Media.js | 4 +- backend/src/player/Method/Soundcloud.js | 31 +++++ backend/src/player/Method/Youtube.js | 6 +- backend/src/player/Player.js | 15 +- backend/src/player/Song.js | 33 +++-- backend/src/utils/Resolver.js | 6 +- backend/src/utils/TimeConverter.js | 16 ++- backend/src/utils/YoutubeDuration.js | 45 ------ 16 files changed, 473 insertions(+), 228 deletions(-) create mode 100644 backend/src/player/Method/Soundcloud.js delete mode 100644 backend/src/utils/YoutubeDuration.js diff --git a/backend/package-lock.json b/backend/package-lock.json index e3ccb57..fb7330f 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -24,9 +24,11 @@ "nodemon": "^3.1.9", "pm2": "^5.4.3", "socket.io": "^4.8.1", + "soundcloud.ts": "^0.6.3", "spotify-web-api-node": "^5.0.2", "uuid": "^11.1.0", - "webmetrik": "^0.1.4" + "webmetrik": "^0.1.4", + "ytfps": "^1.2.0" } }, "node_modules/@derhuerst/http-basic": { @@ -65,6 +67,16 @@ "spotify-url-info": "^3.2.6" } }, + "node_modules/@discord-player/extractor/node_modules/soundcloud.ts": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.5.5.tgz", + "integrity": "sha512-bygjhC1w/w26Nk0Y+4D4cWSEJ1TdxLaE6+w4pCazFzPF+J4mzuB62ggWmFa7BiwnirzNf9lgPbjzrQYGege4Ew==", + "license": "MIT", + "peer": true, + "dependencies": { + "undici": "^6.17.0" + } + }, "node_modules/@discord-player/ffmpeg": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@discord-player/ffmpeg/-/ffmpeg-7.1.0.tgz", @@ -1560,6 +1572,32 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/axios": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz", + "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5569,14 +5607,10 @@ "license": "MIT" }, "node_modules/soundcloud.ts": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.5.5.tgz", - "integrity": "sha512-bygjhC1w/w26Nk0Y+4D4cWSEJ1TdxLaE6+w4pCazFzPF+J4mzuB62ggWmFa7BiwnirzNf9lgPbjzrQYGege4Ew==", - "license": "MIT", - "peer": true, - "dependencies": { - "undici": "^6.17.0" - } + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.6.3.tgz", + "integrity": "sha512-Ri5bO0jQKKACijGP1/OVbWXhHREDST2T6QUSAPWlzQjUScXVyh+7YJfN1mTnyuAA7vZjKyZ1FMlWC2hKd7jmHQ==", + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", @@ -6559,6 +6593,15 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" + }, + "node_modules/ytfps": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ytfps/-/ytfps-1.2.0.tgz", + "integrity": "sha512-DLcW0opwT0zO+4C5YqcCgPiOIzAtge6q6q3nDW0gCBy4kPufEdyxmjd1O9GUV4WeAFxfA2XNhZLmaohrGKV1WA==", + "license": "MIT", + "dependencies": { + "axios": "^1.7.2" + } } } } diff --git a/backend/package.json b/backend/package.json index f3648e1..8eb90ec 100644 --- a/backend/package.json +++ b/backend/package.json @@ -33,8 +33,10 @@ "nodemon": "^3.1.9", "pm2": "^5.4.3", "socket.io": "^4.8.1", + "soundcloud.ts": "^0.6.3", "spotify-web-api-node": "^5.0.2", "uuid": "^11.1.0", - "webmetrik": "^0.1.4" + "webmetrik": "^0.1.4", + "ytfps": "^1.2.0" } } diff --git a/backend/src/discord/Bot.js b/backend/src/discord/Bot.js index 0cb9378..c4b07f2 100644 --- a/backend/src/discord/Bot.js +++ b/backend/src/discord/Bot.js @@ -5,9 +5,13 @@ const { __glob } = require("../utils/GlobalVars") const { LogType } = require("loguix") const config = require("../utils/Database/Configuration") const metric = require("webmetrik") +const { Player } = require("../player/Player") const dlog = new LogType("Discord") +const membersVoices = new Map() +const timers = new Map() + const client = new Client({ intents:[GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers], }) @@ -68,7 +72,42 @@ function init() { } }) - // TODO: Implement the disconnect event for the bot + client.on("voiceStateUpdate", (oldMember, newMember) => { + membersVoices.set(newMember.id, { + guildId: newMember.guild.id, + channelId: newMember.channelId, + }) + + const player = new Player(newMember.guild.id) + + if(player.connection && player.channelId) { + client.channels.fetch(player.channelId).then(channel => { + + if(channel.members.size <= 1) { + + // If the player is alone in the channel, we will destroy it in 10 minutes + // 10 minutes = 600000 ms + // 10 second = 10000 ms + timers.set(newMember.guild.id, setTimeout(() => { + const getPlayer = new Player(newMember.guild.id) + if(getPlayer.connection && player.channelId) { + getPlayer.leave() + dlog.log("[Automatic Task] Guild Id :" + newMember.guild.id + " - Player supprimé : " + channel.name) + } + + }, 10000)) + dlog.log("[Automatic Task] Guild Id :" + newMember.guild.id + " - Player supprimé dans 10 minutess : " + channel.name) + } else { + dlog.log("[Automatic Task] Guild Id :" + newMember.guild.id + " - Player n'est pas seul dans le channel : " + channel.name) + clearTimeout(timers.get(newMember.guild.id)) + timers.delete(newMember.guild.id) + } + }) + + } + + + }) diff --git a/backend/src/discord/Commands/Play.js b/backend/src/discord/Commands/Play.js index 73b9332..62ba938 100644 --- a/backend/src/discord/Commands/Play.js +++ b/backend/src/discord/Commands/Play.js @@ -3,6 +3,7 @@ const { Embed, EmbedError } = require("../Embed"); const { Player } = require("../../player/Player"); const Finder = require("../../player/Finder"); const { Playlist } = require("../../player/Playlist"); +const spotify = require("../../media/SpotifyInformation"); const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", async (client, interaction) => { @@ -11,7 +12,7 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans const url = interaction.options.get("url") const channel = interaction.member.voice.channel const now = interaction.options.getBoolean("now") || false - await Finder.search(url.value).then((song) => { + await Finder.search(url.value).then(async (song) => { if(!song) return new EmbedError("Impossible de trouver la musique à partir du lien donné ou des mots clés donnés").send(interaction) const player = new Player(channel.guildId) @@ -22,35 +23,23 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans // Check if song is playlist if(song instanceof Playlist) { - - if(now) { - player.readPlaylist(song, true) - embed.setTitle('**Lecture immédiate**') - } else { - player.readPlaylist(song) - embed.setTitle('**Ajout à la liste de lecture**') - } + embed.setDescription('**Playlist : **' + song.songs.length + ' musiques') embed.addField('**Titre : **' + song.title, "") embed.addField('**Demandé par : **', interaction.member.user.username,) - embed.addField('**Auteur : **', song.author) - embed.addField('**Durée : **', song.readduration) + embed.addField('**Auteur : **', song.author) + embed.addField('**Provient de : **', song.type.replace(/^\w/, (c) => c.toUpperCase())) + if(!song.type == "spotify") { + embed.addField('**Durée : **', song.readduration) + } + embed.addField('**Lien : **', song.url) + embed.addField(":warning: La récupération des musiques peut prendre du temps", "Veuillez patienter ... et éviter de lancer d'autres commandes") + embed.setThumbnail(song.thumbnail) } else { - - if(now) { - - player.play(song) - embed.setTitle('**Lecture immédiate**') - - } else { - player.add(song) - embed.setTitle('**Ajout à liste de lecture**') - - } - + embed.setDescription('**Titre : **' + song.title) embed.addField('**Durée : **', song.readduration) embed.addField("**Artiste : **",song.author) @@ -60,9 +49,42 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans } + if(now) { + embed.setTitle("Lecture immédiate") + } else { + embed.setTitle("Ajoutée à la file d'attente") + } + + embed.send(interaction) + + if(song instanceof Playlist) { + if(song.type == "spotify") { + song = await spotify.getTracks(song) + } + if(now) { + player.readPlaylist(song, true) + + } else { + player.readPlaylist(song) + + } + } else { + + + if(now) { + + player.play(song) + + + } else { + player.add(song) + } + + } + - embed.send(interaction) + }) }, [{type: "STRING", name: "url", description: "Recherche / Lien audio (Youtube / Soundclound / Spotify)", required: true}, diff --git a/backend/src/media/SoundcloudInformation.js b/backend/src/media/SoundcloudInformation.js index e69de29..bd3cf52 100644 --- a/backend/src/media/SoundcloudInformation.js +++ b/backend/src/media/SoundcloudInformation.js @@ -0,0 +1,85 @@ +const {LogType} = require('loguix'); +const clog = new LogType("SoundcloudInformation"); +const {Song} = require('../player/Song'); +const {Playlist} = require('../player/Playlist'); +const {Soundcloud} = require('soundcloud.ts') +const {getReadableDuration} = require('../utils/TimeConverter'); + +const soundcloud = new Soundcloud(); + +async function getTrack(url) { + try { + const info = await soundcloud.tracks.get(url) + + if(!info) { + clog.error("Impossible de récupérer les informations de la piste Soundcloud à partir de l'URL"); + return null; + } + + const song = new Song(); + song.title = info.title; + song.author = info.user.username; + song.url = info.permalink_url; + song.thumbnail = info.artwork_url; + song.id = info.id; + song.duration = info.duration / 1000; + song.readduration = getReadableDuration(info.duration / 1000); + song.type = "soundcloud"; + + return song; + + } catch (error) { + clog.error('Erreur lors de la recherche Soundcloud (Track): ' + error); + return null; + } +} + +async function getPlaylist(url) { + + try { + + const info = await soundcloud.playlists.get(url) + + if(!info) { + clog.error("Impossible de récupérer les informations de la playlist Soundcloud à partir de l'URL"); + return null; + } + + const playlist = new Playlist(); + + playlist.title = info.title; + playlist.author = info.user.username; + playlist.url = info.permalink_url; + playlist.thumbnail = info.artwork_url; + playlist.id = info.id; + playlist.duration = 0; + playlist.songs = []; + playlist.type = "soundcloud"; + + for(const track of info.tracks) { + const song = new Song(); + song.title = track.title; + song.author = track.user.username; + song.url = track.permalink_url; + song.thumbnail = track.artwork_url; + song.id = track.id; + song.duration = track.duration / 1000; + song.readduration = getReadableDuration(track.duration / 1000); + song.type = "soundcloud"; + + playlist.duration += track.duration / 1000; + playlist.songs.push(song); + } + + playlist.readduration = getReadableDuration(playlist.duration); + + return playlist; + + } catch (error) { + clog.error('Erreur lors de la recherche Soundcloud (Playlist): ' + error); + return null; + } + +} + +module.exports = {getTrack, getPlaylist} \ No newline at end of file diff --git a/backend/src/media/SpotifyInformation.js b/backend/src/media/SpotifyInformation.js index eea84d6..d8727eb 100644 --- a/backend/src/media/SpotifyInformation.js +++ b/backend/src/media/SpotifyInformation.js @@ -27,33 +27,83 @@ async function getSong(url) { return null; } const trackInfo = await spotifyApi.getTrack(trackId); + const trackName = trackInfo.body.name; const artistName = trackInfo.body.artists[0].name; return `${trackName} - ${artistName}`; } catch (error) { - console.error('Erreur lors de la récupération des données :', error); - + + clog.error("Impossible de récupérer les informations de la piste Spotify à partir de l'URL"); + clog.error(error); + return null; } } -async function getAlbum(albumId) { +async function getAlbum(url) { + + try { + + + const creditdata = await spotifyApi.clientCredentialsGrant(); + spotifyApi.setAccessToken(creditdata.body['access_token']); + + const parts = url.split('/'); + const albumId = parts[parts.indexOf('album') + 1].split('?')[0]; + + const data = await spotifyApi.getAlbum(albumId); + const info = data.body; + + if(!info) { + clog.error("Impossible de récupérer les informations de l'album Spotify à partir de l'URL"); + return null; + } + + clog.log("Informations de l'album récupérées : " + info.name); + + const playlist = new Playlist() + playlist.title = info.name; + playlist.author = info.artists[0].name; + playlist.authorId = info.artists[0].id; + playlist.thumbnail = info.images[0].url; + playlist.url = info.external_urls.spotify; + playlist.id = albumId; + playlist.type = "spotify"; + playlist.songs = info.tracks.items; + + return playlist; + + } catch (error) { + + clog.error("Impossible de récupérer les informations de l'album Spotify à partir de l'URL"); + clog.error(error); + return null; + } } async function getPlaylist(url) { // Get the playlist and return a Playlist Object - const data = await spotifyApi.clientCredentialsGrant(); - spotifyApi.setAccessToken(data.body['access_token']); + + try { + const creditdata = await spotifyApi.clientCredentialsGrant(); + spotifyApi.setAccessToken(creditdata.body['access_token']); const parts = url.split('/'); const playlistId = parts[parts.indexOf('playlist') + 1].split('?')[0]; - spotifyApi.getPlaylist(playlistId) - .then(function(data) { + const data = await spotifyApi.getPlaylist(playlistId) + const info = data.body; + if(!info) { + clog.error("Impossible de récupérer les informations de la playlist Spotify à partir de l'URL"); + return null; + } + + clog.log("Informations de la playlist récupérées : " + info.name); + const playlist = new Playlist() playlist.title = info.name; playlist.author = info.owner.display_name; @@ -62,51 +112,68 @@ async function getPlaylist(url) { playlist.url = info.external_urls.spotify; playlist.id = playlistId; playlist.type = "spotify"; + + for(const track of info.tracks.items) { + playlist.songs.push(track.track); + } + + return playlist; - const tracks = info.tracks.items; - tracks.forEach(async function(track) { - - var trackName = track.track.name; - var artistName = track.track.artists[0].name; - var queryForYoutube = `${trackName} - ${artistName}`; + } catch (error) { + + clog.error("Impossible de récupérer les informations de l'album Spotify à partir de l'URL"); + clog.error(error); + return null; + } + +} - var urlYoutubeFounded = await youtube.getQuery(queryForYoutube).then(function(songFind) { - if(!songFind) return null; - return songFind.url; - }); - - clog.log("URL de la vidéo YouTube trouvée : " + urlYoutubeFounded); +async function getTracks(playlist) { - if(!urlYoutubeFounded) { - clog.error("Impossible de récupérer l'URL de la vidéo YouTube à partir de la requête " + queryForYoutube); - - } else { - const song = new Song(); - song.title = track.track.name; - song.author = track.track.artists[0].name; - song.url = urlYoutubeFounded; - song.thumbnail = track.track.album.images[0].url; - song.id = track.track.id; - song.duration = track.track.duration_ms / 1000; - song.readduration = getReadableDuration(track.track.duration_ms); + const tracks = playlist.songs + playlistSongs = []; + for(const track of tracks) { - playlist.duration += track.track.duration_ms; - - - playlist.songs.push(song); - } + var trackName = track.name; + var artistName = track.artists[0].name; + var queryForYoutube = `${trackName} - ${artistName}`; - + var urlYoutubeFounded = await youtube.getQuery(queryForYoutube).then(function(songFind) { + if(!songFind) return null; + return songFind.url; }); + + clog.log("URL de la vidéo YouTube trouvée : " + urlYoutubeFounded); + + if(!urlYoutubeFounded) { + clog.error("Impossible de récupérer l'URL de la vidéo YouTube à partir de la requête " + queryForYoutube); + + } else { + const song = new Song(); + + song.title = track.name; + song.author = track.artists[0].name; + song.url = urlYoutubeFounded; + song.thumbnail = playlist.thumbnail; + song.id = track.id; + song.duration = track.duration_ms / 1000; + song.readduration = getReadableDuration(track.duration_ms / 1000); + song.type = "youtube"; + + playlist.duration += track.duration_ms / 1000; + playlistSongs.push(song); + } + + // When finish do this + + } playlist.readduration = getReadableDuration(playlist.duration); + playlist.songs = playlistSongs; + + return playlist; - - }, function(err) { - clog.error('Une erreur s\'est produite lors de la récupération de la playlist'); - clog.error(err); - }); } -module.exports = {getSong, getAlbum, getPlaylist} \ No newline at end of file +module.exports = {getSong, getAlbum, getPlaylist, getTracks} \ No newline at end of file diff --git a/backend/src/media/YoutubeInformation.js b/backend/src/media/YoutubeInformation.js index 650eb26..ccb06b9 100644 --- a/backend/src/media/YoutubeInformation.js +++ b/backend/src/media/YoutubeInformation.js @@ -1,35 +1,28 @@ -const {LogType} = require('loguix'); +const { LogType } = require('loguix'); const clog = new LogType("YoutubeInformation"); -const config = require('../utils/Database/Configuration'); -const YOUTUBE_API_KEY = config.getYoutubeApiKey() const { Song } = require('../player/Song'); const { Playlist } = require('../player/Playlist'); const { getReadableDuration } = require('../utils/TimeConverter'); +const ytsr = require('@distube/ytsr'); +const ytfps = require('ytfps'); - -async function -getQuery(query) { - // Check Query not null and a string - if(query === null && typeof query !== 'string') { +async function getQuery(query) { + if (query === null || typeof query !== 'string') { clog.error("Impossible de rechercher une vidéo YouTube, car la requête est nulle"); return null; } - // * Fetch + try { - const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=${encodeURIComponent(query)}&key=${YOUTUBE_API_KEY}`); - const data = await response.json(); - - var videoLink = null - const videoId = data.items[0]?.id.videoId; - if(videoId) videoLink = `https://www.youtube.com/watch?v=${videoId}`; - if(videoLink === null) { + const searchResults = await ytsr(query, { limit: 1 }); + const video = searchResults.items.find(item => item.type === 'video'); + + if (!video) { clog.error("Impossible de récupérer le lien de la vidéo YouTube à partir de la requête"); return null; } - const song = await getVideo(videoLink); - + + const song = await getVideo(video.url); return song; - } catch (error) { clog.error('Erreur lors de la recherche YouTube: ' + error); return null; @@ -37,103 +30,72 @@ getQuery(query) { } async function getVideo(url) { - // Extract video ID from URL if it exists and is valid (11 characters) and if not return "NOT_VALID" - // Extract id from youtu.be youtube.com and music.youtube.com const videoId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:watch\?v=)?([a-zA-Z0-9_-]{11})/); - if(videoId === null) { + if (videoId === null) { clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL"); return null; } - // Fetch video information - try { - const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId[1]}&key=${YOUTUBE_API_KEY}`); - const data = await response.json(); - - const video = data.items[0]; - if(video) { - const songReturn = new Song() + try { + const searchResults = await ytsr(videoId[1], { limit: 1 }); + const video = searchResults.items.find(item => item.type === 'video'); + + if (video) { + const songReturn = new Song(); await songReturn.processYoutubeVideo(video); - return songReturn; } else { clog.error("Impossible de récupérer la vidéo YouTube à partir de l'identifiant"); return null; } } catch (error) { - clog.error('Erreur lors de la recherche de la vidéo YouTube:' + error); + clog.error('Erreur lors de la recherche de la vidéo YouTube:' + error); return null; } - - - - } async function getPlaylist(url) { - // Check Query not null and a string - if(url === null && typeof url !== 'string') { + if (url === null || typeof url !== 'string') { clog.error("Impossible de rechercher une playlist YouTube, car la requête est nulle"); return null; } - // * Fetch + try { - // For Playlist - const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/); - if(playlistId === null) { - clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL"); + const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/); + if (playlistId === null) { + clog.error("Impossible de récupérer l'identifiant de la playlist YouTube à partir de l'URL"); return null; } - const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&type=playlist&q=${encodeURIComponent(playlistId[1])}&key=${YOUTUBE_API_KEY}`); - const data = await response.json(); - if(data.items.length === 0) { + const playlistInfo = await ytfps(playlistId[1]); + + if (!playlistInfo) { clog.error("Impossible de récupérer la playlist YouTube à partir de l'identifiant"); return null; } - const playlist = new Playlist() - playlist.type = "youtube" - playlist.author = data.items[0].snippet.channelTitle - playlist.authorId = data.items[0].snippet.channelId - playlist.title = data.items[0].snippet.title - playlist.thumbnail = data.items[0].snippet.thumbnails.high.url - playlist.description = data.items[0].snippet.description - playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}` - playlist.id = playlistId[1] + const playlist = new Playlist(); + playlist.type = "youtube"; + playlist.author = playlistInfo.author.name; + playlist.authorId = playlistInfo.author.url; + playlist.title = playlistInfo.title; + playlist.thumbnail = playlistInfo.thumbnail_url; + playlist.description = playlistInfo.description; + playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}`; + playlist.id = playlistId[1]; - - - - // Get all songs from playlist - - const responsePlaylist = await fetch(`https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=${playlistId[1]}&key=${YOUTUBE_API_KEY}&maxResults=100`); - const dataPlaylist = await responsePlaylist.json(); - - if(dataPlaylist.items.length === 0) { - clog.error("Impossible de récupérer les vidéos de la playlist YouTube à partir de l'identifiant ou la playlist est vide"); - return null; + for (const video of playlistInfo.videos) { + const song = new Song(); + await song.processYoutubeVideo(video, true); + playlist.duration += song.duration; + playlist.songs.push(song); } - - for (const video of dataPlaylist.items) { - const song = new Song() - video.id = video.snippet.resourceId.videoId - await song.processYoutubeVideo(video) - //? Add seconds to playlist duration - playlist.duration += song.duration - playlist.songs.push(song) - } - playlist.readduration = getReadableDuration(playlist.duration) + playlist.readduration = getReadableDuration(playlist.duration); return playlist; - - - - } catch (error) { clog.error('Erreur lors de la recherche YouTube: ' + error); return null; } - } -module.exports = {getQuery, getVideo, getPlaylist} \ No newline at end of file +module.exports = { getQuery, getVideo, getPlaylist }; diff --git a/backend/src/player/Finder.js b/backend/src/player/Finder.js index 46e02d5..4efed39 100644 --- a/backend/src/player/Finder.js +++ b/backend/src/player/Finder.js @@ -3,6 +3,7 @@ const { QueryType } = require('../utils/QueryType'); const { Links } = require('../utils/Links'); const youtube = require("../media/YoutubeInformation") const spotify = require("../media/SpotifyInformation") +const soundcloud = require("../media/SoundcloudInformation") async function search(query) { @@ -25,16 +26,18 @@ async function search(query) { } if(type == QueryType.SPOTIFY_ALBUM) { - + return await spotify.getAlbum(query) } if(type == QueryType.SPOTIFY_PLAYLIST) { return await spotify.getPlaylist(query) } if(type == QueryType.SOUNDCLOUD_TRACK) { + return await soundcloud.getTrack(query) } if(type == QueryType.SOUNDCLOUD_PLAYLIST) { + return await soundcloud.getPlaylist(query) } // TODO: Add more providers diff --git a/backend/src/player/Method/Media.js b/backend/src/player/Method/Media.js index 511a25f..26130a6 100644 --- a/backend/src/player/Method/Media.js +++ b/backend/src/player/Method/Media.js @@ -9,11 +9,11 @@ async function play(instance, song) { instance.player = createAudioPlayer() instance.generatePlayerEvents() const player = instance.player - song.resource = await createAudioResource(song.url, { + var resource = await createAudioResource(song.url, { inputType: StreamType.Arbitrary }) // Remplace par ton fichier audio - player.play(song.resource); + player.play(resource); instance.connection.subscribe(player); clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`) diff --git a/backend/src/player/Method/Soundcloud.js b/backend/src/player/Method/Soundcloud.js new file mode 100644 index 0000000..0cde29b --- /dev/null +++ b/backend/src/player/Method/Soundcloud.js @@ -0,0 +1,31 @@ +const {createAudioResource, VoiceConnectionStatus, createAudioPlayer, StreamType} = require('@discordjs/voice'); +const {LogType} = require('loguix') +const clog = new LogType("Soundcloud") +const plog = require("loguix").getInstance("Player") +const {Soundcloud} = require('soundcloud.ts') + +const soundcloud = new Soundcloud(); + +async function play(instance, song) { + try { + + instance.player = createAudioPlayer() + instance.generatePlayerEvents() + const player = instance.player + + const stream = await soundcloud.util.streamTrack(song.url) + var resource = await createAudioResource(stream) + + player.play(resource); + instance.connection.subscribe(player); + clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Soundcloud): ${song.title} - id : ${song.id}`) + + } catch(e) { + clog.error("Erreur lors de la lecture de la musique : " + song.title) + clog.error(e) + } + + +} + +module.exports = {play} \ No newline at end of file diff --git a/backend/src/player/Method/Youtube.js b/backend/src/player/Method/Youtube.js index aaa4c45..077db93 100644 --- a/backend/src/player/Method/Youtube.js +++ b/backend/src/player/Method/Youtube.js @@ -20,13 +20,13 @@ async function play(instance, song) { }); // Add compressor to the audio resource - song.resource = createAudioResource(stream); + var resource = createAudioResource(stream); - player.play(song.resource); + player.play(resource); instance.connection.subscribe(player); - clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`) + clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Youtube): ${song.title} - id : ${song.id}`) } catch(e) { clog.error("Erreur lors de la lecture de la musique : " + song.title) diff --git a/backend/src/player/Player.js b/backend/src/player/Player.js index 39a6588..e7e2046 100644 --- a/backend/src/player/Player.js +++ b/backend/src/player/Player.js @@ -7,7 +7,7 @@ const clog = new LogType("Signal") const media = require('./Method/Media'); const youtube = require('./Method/Youtube'); -const Activity = require('../discord/Activity'); +const soundcloud = require('./Method/Soundcloud'); const AllPlayers = new Map() @@ -15,6 +15,7 @@ class Player { connection; player; guildId; + channelId; queue; constructor(guildId) { if(this.guildId === null) { @@ -45,6 +46,8 @@ class Player { selfMute: false }); + this.channelId = channel.id + this.player = createAudioPlayer() this.generatePlayerEvents() @@ -62,6 +65,8 @@ class Player { generatePlayerEvents() { + const Activity = require('../discord/Activity'); + this.player.on('error', error => { plog.error(`GUILD : ${this.guildId} - Une erreur est survenue dans le player`); plog.error(error); @@ -109,7 +114,9 @@ class Player { if(song.type == 'youtube') { youtube.play(this, song) } - + if(song.type == "soundcloud") { + soundcloud.play(this, song) + } // TODO: Créer une méthode pour les autres types de médias } @@ -151,6 +158,7 @@ class Player { } async leave() { + const Activity = require('../discord/Activity'); if(this.checkConnection()) return if(this.queue.current != null) { this.queue.addPreviousSong(this.queue.current) @@ -158,6 +166,9 @@ class Player { // Détruit la connection et le player et l'enlève de la liste des this.connection.destroy() this.player.stop() + this.player = null + this.connection = null + this.channelId = null Activity.idleActivity() this.queue.destroy() AllPlayers.delete(this.guildId) diff --git a/backend/src/player/Song.js b/backend/src/player/Song.js index ff5bb2c..3f3404d 100644 --- a/backend/src/player/Song.js +++ b/backend/src/player/Song.js @@ -2,8 +2,7 @@ const {LogType} = require('loguix') const clog = new LogType("Song") const MediaInformation = require('../media/MediaInformation') -const YoutubeDuration = require('../utils/YoutubeDuration'); -const { getReadableDuration } = require('../utils/TimeConverter'); +const { getReadableDuration, getSecondsDuration } = require('../utils/TimeConverter'); class Song { title = "Aucun titre"; @@ -15,7 +14,6 @@ class Song { duration; readduration; type; - resource; constructor(properties) { if(properties) { @@ -50,20 +48,33 @@ class Song { } - async processYoutubeVideo(video) { - this.title = video.snippet.title - this.author = video.snippet.channelTitle - this.authorId = video.snippet.channelId - this.thumbnail = video.snippet.thumbnails.standard.url - this.url = `https://www.youtube.com/watch?v=${video.id}` + async processYoutubeVideo(video, playlist) { + if(playlist) { + this.title = video.title + this.author = video.author.name + this.authorId = video.author.channel_url + this.thumbnail = video.thumbnail_url + this.url = video.url this.type = "youtube" this.id = video.id - this.duration = await YoutubeDuration.getDurationVideo(video.id) + this.duration = video.milis_length / 1000 this.readduration = getReadableDuration(this.duration) + } else { + this.title = video.name + this.author = video.author.name + this.authorId = video.author.url + this.thumbnail = video.thumbnail + this.url = video.url + this.type = "youtube" + this.id = video.id + + this.duration = getSecondsDuration(video.duration) + this.readduration = getReadableDuration(this.duration) + } return this - } + } } diff --git a/backend/src/utils/Resolver.js b/backend/src/utils/Resolver.js index 2a57ff9..9c664aa 100644 --- a/backend/src/utils/Resolver.js +++ b/backend/src/utils/Resolver.js @@ -17,10 +17,10 @@ function getQueryType(url) { if(Links.regex.spotify.song.test(url)) return QueryType.SPOTIFY_SONG // Check if it's a Soundcloud link - - if(Links.regex.soundcloud.track.test(url)) return QueryType.SOUNDCLOUD_TRACK - if(Links.regex.soundcloud.playlist.test(url)) return QueryType.SOUNDCLOUD_PLAYLIST + if(Links.regex.soundcloud.playlist.test(url)) return QueryType.SOUNDCLOUD_PLAYLIST + if(Links.regex.soundcloud.track.test(url)) return QueryType.SOUNDCLOUD_TRACK + return QueryType.YOUTUBE_SEARCH diff --git a/backend/src/utils/TimeConverter.js b/backend/src/utils/TimeConverter.js index 52f1087..73e2d3e 100644 --- a/backend/src/utils/TimeConverter.js +++ b/backend/src/utils/TimeConverter.js @@ -29,4 +29,18 @@ function getReadableDuration(duration) { return max } -module.exports = {getReadableDuration} \ No newline at end of file +function getSecondsDuration(duration) { + // Duration is in format hh:mm:ss and can be just m:ss or mm:ss + var durationArray = duration.split(":"); + var seconds = 0; + if(durationArray.length == 3) { + seconds = parseInt(durationArray[0]) * 3600 + parseInt(durationArray[1]) * 60 + parseInt(durationArray[2]); + } else if(durationArray.length == 2) { + seconds = parseInt(durationArray[0]) * 60 + parseInt(durationArray[1]); + } else { + seconds = parseInt(durationArray[0]); + } + return seconds; +} + +module.exports = {getReadableDuration, getSecondsDuration} \ No newline at end of file diff --git a/backend/src/utils/YoutubeDuration.js b/backend/src/utils/YoutubeDuration.js deleted file mode 100644 index b3f496a..0000000 --- a/backend/src/utils/YoutubeDuration.js +++ /dev/null @@ -1,45 +0,0 @@ -const config = require('../utils/Database/Configuration'); -const YOUTUBE_API_KEY = config.getYoutubeApiKey() - -async function getDurationVideo(videoId) { - const clog = require("loguix").getInstance("YoutubeInformation"); - // Check videoId if valid - if(videoId === null && typeof videoId !== 'string') { - clog.error("Impossible de récupérer la durée de la vidéo YouTube, car l'identifiant est nul ou n'est pas une chaîne de caractères"); - return null; - } - - // Fetch video information - try { - const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id=${videoId}&key=${YOUTUBE_API_KEY}`); - const data = await response.json(); - const video = data.items[0]; - if(video) { - - if(video.contentDetails.duration == "P0D") return "LIVE"; - const duration = video.contentDetails.duration; - //Convert ISO 8601 duration to seconds - return parseDuration(duration); - - - } else { - clog.error("Impossible de récupérer la durée de la vidéo YouTube à partir de l'identifiant"); - return null; - } - } catch (error) { - clog.error('Erreur lors de la recherche de la durée de la vidéo YouTube:', error); - return null; - } - - -} - -function parseDuration(duration) { - const match = duration.match(/PT(\d+H)?(\d+M)?(\d+S)?/); - const hours = parseInt(match[1]) || 0; - const minutes = parseInt(match[2]) || 0; - const seconds = parseInt(match[3]) || 0; - return hours * 3600 + minutes * 60 + seconds; -} - -module.exports = {getDurationVideo} \ No newline at end of file -- 2.30.2