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