Version 1.1.0 - BACKEND - Release STABLE - Ajout de l'historique, de l'ajout de playlist privé, lecture de fichier média
This commit is contained in:
		
							
								
								
									
										3
									
								
								TODOS.md
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								TODOS.md
									
									
									
									
									
								
							@@ -1,6 +1,3 @@
 | 
			
		||||
# List
 | 
			
		||||
 | 
			
		||||
TODO: Lecture de fichiers depuis le site, nécéssite hébergement.
 | 
			
		||||
TODO: Récupération des recommendations, playlists Youtube et Spotify
 | 
			
		||||
TODO: Acces à un historique personnel (LOCAL ?)
 | 
			
		||||
TODO: Faire un systême de parole.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										342
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										342
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,16 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "chopin-backend",
 | 
			
		||||
  "version": "1.0.1",
 | 
			
		||||
  "version": "1.1.0",
 | 
			
		||||
  "lockfileVersion": 3,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "packages": {
 | 
			
		||||
    "": {
 | 
			
		||||
      "name": "chopin-backend",
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "version": "1.1.0",
 | 
			
		||||
      "license": "ISC",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@discordjs/voice": "^0.18.0",
 | 
			
		||||
        "@distube/ytdl-core": "^4.16.9",
 | 
			
		||||
        "@distube/ytdl-core": "^4.16.10",
 | 
			
		||||
        "@distube/ytsr": "2.0.4",
 | 
			
		||||
        "cors": "^2.8.5",
 | 
			
		||||
        "discord-player": "^7.1.0",
 | 
			
		||||
@@ -20,8 +20,10 @@
 | 
			
		||||
        "ffprobe": "^1.1.2",
 | 
			
		||||
        "ffprobe-static": "^3.1.0",
 | 
			
		||||
        "fluent-ffmpeg": "^2.1.3",
 | 
			
		||||
        "googleapis": "^149.0.0",
 | 
			
		||||
        "libsodium-wrappers": "^0.7.15",
 | 
			
		||||
        "loguix": "^1.4.2",
 | 
			
		||||
        "mime-types": "^3.0.1",
 | 
			
		||||
        "nodemon": "^3.1.9",
 | 
			
		||||
        "pm2": "^5.4.3",
 | 
			
		||||
        "socket.io": "^4.8.1",
 | 
			
		||||
@@ -267,9 +269,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@distube/ytdl-core": {
 | 
			
		||||
      "version": "4.16.9",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@distube/ytdl-core/-/ytdl-core-4.16.9.tgz",
 | 
			
		||||
      "integrity": "sha512-eRYM3lDR1/1ZB+k6jzIdR+8m9VsYEqjz9+DstX1S/aW1f2rlbj22WCdrRbE+sE3DJW8DLJEp69akfjWqQ+nKIw==",
 | 
			
		||||
      "version": "4.16.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@distube/ytdl-core/-/ytdl-core-4.16.10.tgz",
 | 
			
		||||
      "integrity": "sha512-KFKZtNlynOO0PYxelUF5h2bKyAU1d8fe6aZmo+gxWt7H2MQbd0bUeyV4y9iWhI57nukjkSXXQGB625CfhrVdGQ==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "http-cookie-agent": "^7.0.1",
 | 
			
		||||
@@ -1482,6 +1484,27 @@
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/accepts/node_modules/mime-db": {
 | 
			
		||||
      "version": "1.52.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
 | 
			
		||||
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/accepts/node_modules/mime-types": {
 | 
			
		||||
      "version": "2.1.35",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
 | 
			
		||||
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": "1.52.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/agent-base": {
 | 
			
		||||
      "version": "7.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
 | 
			
		||||
@@ -1623,6 +1646,27 @@
 | 
			
		||||
        "node": ">= 6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/axios/node_modules/mime-db": {
 | 
			
		||||
      "version": "1.52.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
 | 
			
		||||
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/axios/node_modules/mime-types": {
 | 
			
		||||
      "version": "2.1.35",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
 | 
			
		||||
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": "1.52.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/balanced-match": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 | 
			
		||||
@@ -1667,6 +1711,15 @@
 | 
			
		||||
        "node": ">=10.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/bignumber.js": {
 | 
			
		||||
      "version": "9.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "*"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/binary-extensions": {
 | 
			
		||||
      "version": "2.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
 | 
			
		||||
@@ -1785,6 +1838,12 @@
 | 
			
		||||
        "ieee754": "^1.1.13"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/buffer-equal-constant-time": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
 | 
			
		||||
      "license": "BSD-3-Clause"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/buffer-from": {
 | 
			
		||||
      "version": "1.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
 | 
			
		||||
@@ -2341,6 +2400,15 @@
 | 
			
		||||
      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ecdsa-sig-formatter": {
 | 
			
		||||
      "version": "1.0.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
 | 
			
		||||
      "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ee-first": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
 | 
			
		||||
@@ -2693,6 +2761,12 @@
 | 
			
		||||
        "url": "https://opencollective.com/express"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/extend": {
 | 
			
		||||
      "version": "3.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/extrareqp2": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/extrareqp2/-/extrareqp2-1.0.0.tgz",
 | 
			
		||||
@@ -2972,6 +3046,27 @@
 | 
			
		||||
        "node": ">= 6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/form-data/node_modules/mime-db": {
 | 
			
		||||
      "version": "1.52.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
 | 
			
		||||
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/form-data/node_modules/mime-types": {
 | 
			
		||||
      "version": "2.1.35",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
 | 
			
		||||
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": "1.52.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/formdata-polyfill": {
 | 
			
		||||
      "version": "4.0.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
 | 
			
		||||
@@ -3036,6 +3131,69 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/ljharb"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/gaxios": {
 | 
			
		||||
      "version": "6.7.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
 | 
			
		||||
      "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "extend": "^3.0.2",
 | 
			
		||||
        "https-proxy-agent": "^7.0.1",
 | 
			
		||||
        "is-stream": "^2.0.0",
 | 
			
		||||
        "node-fetch": "^2.6.9",
 | 
			
		||||
        "uuid": "^9.0.1"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/gaxios/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",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "whatwg-url": "^5.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "4.x || >=6.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "encoding": "^0.1.0"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependenciesMeta": {
 | 
			
		||||
        "encoding": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/gaxios/node_modules/uuid": {
 | 
			
		||||
      "version": "9.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
 | 
			
		||||
      "funding": [
 | 
			
		||||
        "https://github.com/sponsors/broofa",
 | 
			
		||||
        "https://github.com/sponsors/ctavan"
 | 
			
		||||
      ],
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "uuid": "dist/bin/uuid"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/gcp-metadata": {
 | 
			
		||||
      "version": "6.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "gaxios": "^6.1.1",
 | 
			
		||||
        "google-logging-utils": "^0.0.2",
 | 
			
		||||
        "json-bigint": "^1.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/get-intrinsic": {
 | 
			
		||||
      "version": "1.2.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
 | 
			
		||||
@@ -3178,6 +3336,75 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/isaacs"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/google-auth-library": {
 | 
			
		||||
      "version": "9.15.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz",
 | 
			
		||||
      "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "base64-js": "^1.3.0",
 | 
			
		||||
        "ecdsa-sig-formatter": "^1.0.11",
 | 
			
		||||
        "gaxios": "^6.1.1",
 | 
			
		||||
        "gcp-metadata": "^6.1.0",
 | 
			
		||||
        "gtoken": "^7.0.0",
 | 
			
		||||
        "jws": "^4.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/google-logging-utils": {
 | 
			
		||||
      "version": "0.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/googleapis": {
 | 
			
		||||
      "version": "149.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-149.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-LTMc/njwYy7KTeaUHDcQt7KxftHyghdzm2XzbL46PRLd1AXB09utT9Po2ZJn2X0EApz0pE2T5x5A9zM8iue6zw==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "google-auth-library": "^9.0.0",
 | 
			
		||||
        "googleapis-common": "^7.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/googleapis-common": {
 | 
			
		||||
      "version": "7.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "extend": "^3.0.2",
 | 
			
		||||
        "gaxios": "^6.0.3",
 | 
			
		||||
        "google-auth-library": "^9.7.0",
 | 
			
		||||
        "qs": "^6.7.0",
 | 
			
		||||
        "url-template": "^2.0.8",
 | 
			
		||||
        "uuid": "^9.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/googleapis-common/node_modules/uuid": {
 | 
			
		||||
      "version": "9.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
 | 
			
		||||
      "funding": [
 | 
			
		||||
        "https://github.com/sponsors/broofa",
 | 
			
		||||
        "https://github.com/sponsors/ctavan"
 | 
			
		||||
      ],
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "uuid": "dist/bin/uuid"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/gopd": {
 | 
			
		||||
      "version": "1.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
 | 
			
		||||
@@ -3190,6 +3417,19 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/ljharb"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/gtoken": {
 | 
			
		||||
      "version": "7.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "gaxios": "^6.0.0",
 | 
			
		||||
        "jws": "^4.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/has-flag": {
 | 
			
		||||
      "version": "3.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
 | 
			
		||||
@@ -3502,6 +3742,18 @@
 | 
			
		||||
        "node": ">=0.12.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/is-stream": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=8"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/isexe": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
 | 
			
		||||
@@ -3573,6 +3825,15 @@
 | 
			
		||||
      "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/json-bigint": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "bignumber.js": "^9.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/json-stringify-safe": {
 | 
			
		||||
      "version": "5.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
 | 
			
		||||
@@ -3605,6 +3866,27 @@
 | 
			
		||||
        "node": "*"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/jwa": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "buffer-equal-constant-time": "^1.0.1",
 | 
			
		||||
        "ecdsa-sig-formatter": "1.0.11",
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/jws": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "jwa": "^2.0.0",
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/lazy": {
 | 
			
		||||
      "version": "1.0.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz",
 | 
			
		||||
@@ -4054,21 +4336,21 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/mime-db": {
 | 
			
		||||
      "version": "1.52.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
 | 
			
		||||
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
 | 
			
		||||
      "version": "1.54.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
 | 
			
		||||
      "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/mime-types": {
 | 
			
		||||
      "version": "2.1.35",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
 | 
			
		||||
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": "1.52.0"
 | 
			
		||||
        "mime-db": "^1.54.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
@@ -6130,8 +6412,7 @@
 | 
			
		||||
      "version": "0.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "peer": true
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/tree-kill": {
 | 
			
		||||
      "version": "1.2.2",
 | 
			
		||||
@@ -6341,6 +6622,27 @@
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/type-is/node_modules/mime-db": {
 | 
			
		||||
      "version": "1.52.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
 | 
			
		||||
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/type-is/node_modules/mime-types": {
 | 
			
		||||
      "version": "2.1.35",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
 | 
			
		||||
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mime-db": "1.52.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/typedarray": {
 | 
			
		||||
      "version": "0.0.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
 | 
			
		||||
@@ -6400,6 +6702,12 @@
 | 
			
		||||
        "node": ">= 0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/url-template": {
 | 
			
		||||
      "version": "2.0.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
 | 
			
		||||
      "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==",
 | 
			
		||||
      "license": "BSD"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/util-deprecate": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
 | 
			
		||||
@@ -6475,8 +6783,7 @@
 | 
			
		||||
      "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
 | 
			
		||||
      "license": "BSD-2-Clause"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/webmetrik": {
 | 
			
		||||
      "version": "0.1.4",
 | 
			
		||||
@@ -6489,7 +6796,6 @@
 | 
			
		||||
      "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"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "chopin-backend",
 | 
			
		||||
  "version": "1.0.2",
 | 
			
		||||
  "version": "1.1.0",
 | 
			
		||||
  "description": "Discord Bot for music - Fetching everywhere !",
 | 
			
		||||
  "main": "src/main.js",
 | 
			
		||||
  "nodemonConfig": {
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
  "license": "ISC",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@discordjs/voice": "^0.18.0",
 | 
			
		||||
    "@distube/ytdl-core": "^4.16.9",
 | 
			
		||||
    "@distube/ytdl-core": "^4.16.10",
 | 
			
		||||
    "@distube/ytsr": "2.0.4",
 | 
			
		||||
    "cors": "^2.8.5",
 | 
			
		||||
    "discord-player": "^7.1.0",
 | 
			
		||||
@@ -31,8 +31,10 @@
 | 
			
		||||
    "ffprobe": "^1.1.2",
 | 
			
		||||
    "ffprobe-static": "^3.1.0",
 | 
			
		||||
    "fluent-ffmpeg": "^2.1.3",
 | 
			
		||||
    "googleapis": "^149.0.0",
 | 
			
		||||
    "libsodium-wrappers": "^0.7.15",
 | 
			
		||||
    "loguix": "^1.4.2",
 | 
			
		||||
    "mime-types": "^3.0.1",
 | 
			
		||||
    "nodemon": "^3.1.9",
 | 
			
		||||
    "pm2": "^5.4.3",
 | 
			
		||||
    "socket.io": "^4.8.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ const { Player } = require("../player/Player")
 | 
			
		||||
const {refreshAllUserInformation} = require("../server/auth/User")
 | 
			
		||||
 | 
			
		||||
const dlog = new LogType("Discord")
 | 
			
		||||
dlog.log("Initialisation du Bot Discord")   
 | 
			
		||||
 | 
			
		||||
const membersVoices = new Map()
 | 
			
		||||
const timers = new Map()
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ const {Command} = require('../Command');
 | 
			
		||||
const {Embed, EmbedError} = require('../Embed');
 | 
			
		||||
const { Player } = require('../../player/Player');
 | 
			
		||||
const { Song } = require('../../player/Song');
 | 
			
		||||
const history = require('../../playlists/History'); 
 | 
			
		||||
 | 
			
		||||
const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal", async (client, interaction) => {
 | 
			
		||||
 | 
			
		||||
@@ -35,6 +36,8 @@ const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    history.addToPersonalHistory(interaction.user.id, song)
 | 
			
		||||
        
 | 
			
		||||
    embed.setDescription('**Titre : **' + song.title)
 | 
			
		||||
    embed.addField('**Durée : **', song.readduration)
 | 
			
		||||
    embed.addField("**Artiste : **",song.author)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ const { Player } = require("../../player/Player");
 | 
			
		||||
const Finder = require("../../player/Finder");
 | 
			
		||||
const { Playlist } = require("../../playlists/Playlist");
 | 
			
		||||
const spotify = require("../../media/SpotifyInformation");
 | 
			
		||||
const history = require("../../playlists/History");
 | 
			
		||||
 | 
			
		||||
const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", async (client, interaction) => {
 | 
			
		||||
 | 
			
		||||
@@ -76,6 +77,8 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
 | 
			
		||||
                player.add(song)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            history.addToPersonalHistory(interaction.user.id, song)
 | 
			
		||||
                
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
       
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								backend/src/discord/MediaBase.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								backend/src/discord/MediaBase.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
const {LogType} = require("loguix")
 | 
			
		||||
const config = require("../utils/Database/Configuration")   
 | 
			
		||||
const wlog = new LogType("MediaBase")
 | 
			
		||||
const { Database } = require("../utils/Database/Database")
 | 
			
		||||
const {__glob} = require("../utils/GlobalVars")
 | 
			
		||||
const { AttachmentBuilder } = require("discord.js")
 | 
			
		||||
const discordBot = require("./Bot")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var connected = false
 | 
			
		||||
var mediaDB = new Database("media", __glob.MEDIA_DB, [])
 | 
			
		||||
 | 
			
		||||
wlog.step.init("init_db", "Initialisation de la base de données multimédia")
 | 
			
		||||
 | 
			
		||||
if(!config.getMediaGuildId() || !config.getMediaChannelId()) {
 | 
			
		||||
    wlog.warn("La configuration de la base de données multimédia n'est pas définie, vérifiez le fichier de configuration.")
 | 
			
		||||
    wlog.step.error("init_db","Impossible d'initialiser la base de données multimédia, vérifiez le fichier de configuration.")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var channel = null
 | 
			
		||||
 | 
			
		||||
discordBot.getClient().on("ready", () => {
 | 
			
		||||
    channel = discordBot.getChannel(config.getMediaGuildId(), config.getMediaChannelId())
 | 
			
		||||
    if(!channel) {
 | 
			
		||||
    wlog.warn("Le canal multimédia n'existe pas, vérifiez le fichier de configuration.")
 | 
			
		||||
    wlog.step.error("init_db","Impossible d'initialiser la base de données multimédia, vérifiez le fichier de configuration.")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    try {
 | 
			
		||||
        const dateTime = new Date()
 | 
			
		||||
        const date = dateTime.toLocaleDateString('fr-FR', { timeZone: 'Europe/Paris' })
 | 
			
		||||
        const time = dateTime.toLocaleTimeString('fr-FR', { timeZone: 'Europe/Paris' })
 | 
			
		||||
        const message = `[LOGS] La base de données multimédia a été initialisée le ${date} à ${time}`
 | 
			
		||||
        channel.send(message)
 | 
			
		||||
        wlog.log("La base de données multimédia a été initialisée avec succès.")
 | 
			
		||||
        wlog.step.end("init_db")
 | 
			
		||||
        connected = true    
 | 
			
		||||
    } catch (e) {   
 | 
			
		||||
        wlog.error("Impossible d'envoyer un message au canal multimédia, vérifiez le fichier de configuration.")
 | 
			
		||||
        wlog.step.error("init_db","Impossible d'envoyer un message au canal multimédia, vérifiez le fichier de configuration.")
 | 
			
		||||
        connected = false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// SEND FILE TO DISCORD AND GET THE URL ID
 | 
			
		||||
 | 
			
		||||
async function postMedia(file) {
 | 
			
		||||
    if(!connected) {
 | 
			
		||||
        wlog.error("La base de données multimédia n'est pas connectée, impossible d'envoyer le fichier.")
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    try {
 | 
			
		||||
        const attachment = new AttachmentBuilder(file.file)
 | 
			
		||||
        attachment.setName(file.name) // Set the name of the file
 | 
			
		||||
        attachment.setDescription("Fichier envoyé par Subsonics Chopin - Raphix")
 | 
			
		||||
        const message = await channel.send({ files: [attachment] })
 | 
			
		||||
        const url = message.attachments.first().url
 | 
			
		||||
        wlog.log(`Fichier envoyé avec succès : ${url}`)
 | 
			
		||||
        // add the file to the database
 | 
			
		||||
        mediaDB.data.push({
 | 
			
		||||
            id: message.id,
 | 
			
		||||
            url: url,
 | 
			
		||||
            name: file.name,
 | 
			
		||||
            size: file.size,
 | 
			
		||||
            createdAt: new Date().toISOString()
 | 
			
		||||
        })
 | 
			
		||||
        mediaDB.save()
 | 
			
		||||
        return url
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        wlog.error(`Erreur lors de l'envoi du fichier : ${error.message}`)
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getMedia(id) {
 | 
			
		||||
    if(!connected) {
 | 
			
		||||
        wlog.error("La base de données multimédia n'est pas connectée, impossible de récupérer le fichier.")
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const media = mediaDB.data.find(m => m.id === id)
 | 
			
		||||
    if(!media) {
 | 
			
		||||
        wlog.error(`Aucun média trouvé avec l'ID : ${id}`)
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    try {
 | 
			
		||||
        return media.url
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        wlog.error(`Erreur lors de la récupération du média : ${error.message}`)
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    postMedia,
 | 
			
		||||
    getMedia,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								backend/src/lyrics/Lyrics.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								backend/src/lyrics/Lyrics.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
const { LogType } = require("loguix");
 | 
			
		||||
const plog = new LogType('Lyrics');
 | 
			
		||||
const urls = require('./urls.json');
 | 
			
		||||
 | 
			
		||||
// Make sure Url exists and get lyrics for the first item only
 | 
			
		||||
async function getLyrics(name) {
 | 
			
		||||
    let result = null;
 | 
			
		||||
    try {
 | 
			
		||||
        const searchResponse = await fetch(`${urls.urlSearch}${encodeURIComponent(name)}`, {
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            headers: {
 | 
			
		||||
                'content-type': 'application/json'
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        const searchData = await searchResponse.json();
 | 
			
		||||
 | 
			
		||||
        // Check if data exists and has at least one item
 | 
			
		||||
        if (searchData && searchData.data && searchData.data.length > 0) {
 | 
			
		||||
            const firstItem = searchData.data[0];
 | 
			
		||||
            const artist = firstItem.artist && firstItem.artist.name ? firstItem.artist.name : null;
 | 
			
		||||
            const title = firstItem.title || null;
 | 
			
		||||
 | 
			
		||||
            if (artist && title) {
 | 
			
		||||
                try {
 | 
			
		||||
                    const lyricsResponse = await fetch(`${urls.urlGet}${encodeURIComponent(artist)}/${encodeURIComponent(title)}`, {
 | 
			
		||||
                        method: 'GET',
 | 
			
		||||
                        headers: {
 | 
			
		||||
                            'content-type': 'application/json'
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    const lyricsData = await lyricsResponse.json();
 | 
			
		||||
                    console.log(lyricsData);
 | 
			
		||||
                    if (lyricsData && lyricsData && lyricsData.lyrics) {
 | 
			
		||||
                        result = lyricsData.lyrics;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        plog.error('Invalid response structure:', lyricsData);
 | 
			
		||||
                        return null;
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (error) {
 | 
			
		||||
                    plog.error('Error fetching lyrics data:', error);
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                plog.error('Artist or title missing in search result');
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            plog.error('No search results found');
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        plog.error('Error fetching search data:', error);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = { getLyrics };
 | 
			
		||||
							
								
								
									
										4
									
								
								backend/src/lyrics/urls.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								backend/src/lyrics/urls.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
    "urlSearch": "http://api.deezer.com/search?limit=5&q=",
 | 
			
		||||
    "urlGet": "https://api.lyrics.ovh/v1/"
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const { LogType } = require('loguix');
 | 
			
		||||
const { __glob } = require("./utils/GlobalVars")
 | 
			
		||||
require("loguix").setup(__glob.LOGS, __glob.PACKAGEINFO)
 | 
			
		||||
const config = require("./utils/Database/Configuration")
 | 
			
		||||
@@ -20,7 +19,7 @@ setup();
 | 
			
		||||
 | 
			
		||||
async function setup() {
 | 
			
		||||
    const DiscordBot = require("./discord/Bot")
 | 
			
		||||
    DiscordBot.init()
 | 
			
		||||
    await DiscordBot.init()
 | 
			
		||||
    const Server = require("./server/Server")
 | 
			
		||||
    Server.init()
 | 
			
		||||
    await Server.init()
 | 
			
		||||
}
 | 
			
		||||
@@ -29,4 +29,30 @@ async function getMediaInformation(instance, media, provider) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {getMediaInformation}
 | 
			
		||||
async function getMediaInformationFromUrl(instance, url) {
 | 
			
		||||
    try {
 | 
			
		||||
        const info = await ffprobe(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 ?? "Titre inconnu";
 | 
			
		||||
        
 | 
			
		||||
        // Obtenir l'auteur (s'il existe)
 | 
			
		||||
        instance.author = info.streams?.[0]?.tags?.artist ?? "Auteur inconnu";
 | 
			
		||||
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        clog.error("Impossible de récupérer les informations de la musique depuis l'URL : " + url);
 | 
			
		||||
        console.log(err)
 | 
			
		||||
        clog.error(err);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {getMediaInformation, getMediaInformationFromUrl};
 | 
			
		||||
@@ -2,7 +2,7 @@ const { LogType } = require('loguix');
 | 
			
		||||
const clog = new LogType("YoutubeInformation");
 | 
			
		||||
const { Song } = require('../player/Song');
 | 
			
		||||
const { Playlist } = require('../playlists/Playlist');
 | 
			
		||||
const { getReadableDuration } = require('../utils/TimeConverter');
 | 
			
		||||
const { getReadableDuration, getSecondsDuration } = require('../utils/TimeConverter');
 | 
			
		||||
const ytsr = require('@distube/ytsr');
 | 
			
		||||
const ytfps = require('ytfps');
 | 
			
		||||
 | 
			
		||||
@@ -110,4 +110,26 @@ async function getPlaylist(url) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = { getQuery, getVideo, getPlaylist };
 | 
			
		||||
async function getSecondsFromUrl(url) {
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
        const searchResults = await ytsr(videoId[1], { limit: 1 });
 | 
			
		||||
        const video = searchResults.items.find(item => item.type === 'video');
 | 
			
		||||
        console.log(video);
 | 
			
		||||
        if (video) {
 | 
			
		||||
            return getSecondsDuration(video.duration); // Convert seconds to milliseconds
 | 
			
		||||
        } 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = { getQuery, getVideo, getPlaylist, getSecondsFromUrl };
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ class Song {
 | 
			
		||||
    thumbnail = "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png" ;
 | 
			
		||||
    duration;
 | 
			
		||||
    readduration;
 | 
			
		||||
    form = "SONG"; 
 | 
			
		||||
    type;
 | 
			
		||||
    userAddedId; 
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										87
									
								
								backend/src/playlists/Google/OAuth2.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								backend/src/playlists/Google/OAuth2.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
const { LogType } = require('loguix');
 | 
			
		||||
const alog = new LogType("GoogleOAuth2");
 | 
			
		||||
const { google } = require('googleapis');
 | 
			
		||||
const config = require("../../utils/Database/Configuration");
 | 
			
		||||
const Users = require('../../server/auth/User');
 | 
			
		||||
 | 
			
		||||
const clientId = config.getYoutubeApiClientId();
 | 
			
		||||
const clientSecret = config.getYoutubeApiClientSecret();
 | 
			
		||||
const redirectUri = config.getWebsiteLink() + "/oauth2callback";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const oAuth2Map = new Map();
 | 
			
		||||
 
 | 
			
		||||
function createAuthUrl(userId) {
 | 
			
		||||
    if(!checkCredientials()) return null;
 | 
			
		||||
    var oAuth2Client;
 | 
			
		||||
    const user = Users.getUserById(userId);
 | 
			
		||||
    if (!user) {
 | 
			
		||||
       alog.error(`User with ID ${userId} not found.`);
 | 
			
		||||
       return null;
 | 
			
		||||
    }
 | 
			
		||||
    if (!clientId || !clientSecret) {
 | 
			
		||||
        alog.error("YouTube API client ID or secret is not set in the configuration.");
 | 
			
		||||
    } else {
 | 
			
		||||
        oAuth2Client = new google.auth.OAuth2(
 | 
			
		||||
            clientId,
 | 
			
		||||
            clientSecret,
 | 
			
		||||
            redirectUri
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        alog.log("Google OAuth2 client initialized successfully.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!oAuth2Client) {
 | 
			
		||||
        alog.error("OAuth2 client is not initialized. Please check your configuration.");
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    oAuth2Map.set(userId, oAuth2Client);
 | 
			
		||||
    alog.log(`OAuth2 client created for user ${userId}.`);
 | 
			
		||||
    return oAuth2Client.generateAuthUrl({
 | 
			
		||||
        access_type: 'offline',
 | 
			
		||||
        scope: SCOPES,
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getAuthorization(userId, code) {
 | 
			
		||||
      if(!checkCredientials()) return null;
 | 
			
		||||
    try {
 | 
			
		||||
        const user = Users.getUserById(userId);
 | 
			
		||||
        if (!user) {
 | 
			
		||||
        alog.error(`User with ID ${userId} not found.`);
 | 
			
		||||
        return null;
 | 
			
		||||
        }
 | 
			
		||||
        oAuth2Client = oAuth2Map.get(userId);
 | 
			
		||||
        if (!oAuth2Client) {
 | 
			
		||||
            alog.error(`OAuth2 client for user ${userId} not found. Please create an OAuth2 client first.`);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        const { tokens } = await oAuth2Client.getToken(code);
 | 
			
		||||
        oAuth2Client.setCredentials(tokens);
 | 
			
		||||
        alog.log(`OAuth2 client credentials set for user ${userId}.`);
 | 
			
		||||
        return oAuth2Client;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        alog.error(`Error during OAuth2 authorization for user ${userId}:`, error);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkCredientials() {
 | 
			
		||||
    if (!clientId || !clientSecret) {
 | 
			
		||||
        alog.error("YouTube API client ID or secret is not set in the configuration.");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}   
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    createAuthUrl,
 | 
			
		||||
    getAuthorization,
 | 
			
		||||
    getOAuth2Client: (userId) => oAuth2Map.get(userId),
 | 
			
		||||
    oAuth2Map
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								backend/src/playlists/Google/YoutubeList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								backend/src/playlists/Google/YoutubeList.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
const { google } = require('googleapis');
 | 
			
		||||
const { LogType } = require('loguix');
 | 
			
		||||
const alog = new LogType("YoutubeAPI");
 | 
			
		||||
 | 
			
		||||
const OAuth2 = require('./OAuth2');
 | 
			
		||||
const Users = require('../../server/auth/User');
 | 
			
		||||
 | 
			
		||||
async function getYoutubePlaylists(userId) {
 | 
			
		||||
    const user = Users.getUserById(userId);
 | 
			
		||||
    if (!user) {
 | 
			
		||||
        alog.error(`User with ID ${userId} not found.`);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const oAuth2Client = OAuth2.getOAuth2Client(userId);
 | 
			
		||||
    if (!oAuth2Client) {
 | 
			
		||||
        alog.error(`OAuth2 client for user ${userId} not found. Please authenticate first.`);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const youtube = google.youtube({ version: 'v3', auth: oAuth2Client });
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        const response = await youtube.playlists.list({
 | 
			
		||||
            part: 'snippet,contentDetails',
 | 
			
		||||
            mine: true,
 | 
			
		||||
            maxResults: 50
 | 
			
		||||
        });
 | 
			
		||||
        alog.log(`Retrieved playlists for user ${userId}.`);
 | 
			
		||||
        return response.data.items;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        alog.error(`Error retrieving playlists for user ${userId}:`, error);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getYoutubePlaylistSongs(playlistId, userId) {
 | 
			
		||||
    const user = Users.getUserById(userId);
 | 
			
		||||
    if (!user) {
 | 
			
		||||
        alog.error(`User with ID ${userId} not found.`);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const oAuth2Client = OAuth2.getOAuth2Client(userId);
 | 
			
		||||
    if (!oAuth2Client) {
 | 
			
		||||
        alog.error(`OAuth2 client for user ${userId} not found. Please authenticate first.`);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const youtube = google.youtube({ version: 'v3', auth: oAuth2Client });
 | 
			
		||||
 | 
			
		||||
    return youtube.playlistItems.list({
 | 
			
		||||
        part: 'snippet',
 | 
			
		||||
        playlistId: playlistId,
 | 
			
		||||
        maxResults: 50
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    getYoutubePlaylists,
 | 
			
		||||
    getYoutubePlaylistSongs
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										54
									
								
								backend/src/playlists/History.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								backend/src/playlists/History.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
const {LogType} = require("loguix")
 | 
			
		||||
const hlog = new LogType("PersonalHistory")
 | 
			
		||||
const {__glob} = require("../utils/GlobalVars")
 | 
			
		||||
const { Database } = require("../utils/Database/Database")
 | 
			
		||||
const historyDb = new Database("history", __glob.HISTORY_DB, {})
 | 
			
		||||
historyDb.load()
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {string} userId
 | 
			
		||||
 * @returns {Array<Object>}
 | 
			
		||||
 * @description Renvoie l'historique personnel de l'utilisateur
 | 
			
		||||
 */
 | 
			
		||||
function getPersonalHistory(userId) {
 | 
			
		||||
    if (historyDb.data[userId]) {
 | 
			
		||||
        return historyDb.data[userId];
 | 
			
		||||
    } else {
 | 
			
		||||
        hlog.log(`Création d'une clé pour l'utilisateur : ${userId}`);
 | 
			
		||||
        historyDb.data[userId] = [];
 | 
			
		||||
        historyDb.save();
 | 
			
		||||
        return historyDb.data[userId];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {string} userId
 | 
			
		||||
 * @param {Object} entry
 | 
			
		||||
 * @description Ajoute une entrée à l'historique personnel de l'utilisateur
 | 
			
		||||
 */
 | 
			
		||||
function addToPersonalHistory(userId, entry) {
 | 
			
		||||
    hlog.log(`Ajout d'une entrée à l'historique personnel de l'utilisateur : ${userId}`);
 | 
			
		||||
    const history = getPersonalHistory(userId);
 | 
			
		||||
    // Limit to 25 entries
 | 
			
		||||
    if (history.length >= 25) {
 | 
			
		||||
        history.shift();
 | 
			
		||||
    }
 | 
			
		||||
    history.push(entry)
 | 
			
		||||
    historyDb.save();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {string} userId
 | 
			
		||||
 * @description Vide l'historique personnel de l'utilisateur
 | 
			
		||||
 */
 | 
			
		||||
function clearPersonalHistory(userId) {
 | 
			
		||||
    hlog.log(`Vidage de l'historique personnel de l'utilisateur : ${userId}`);
 | 
			
		||||
    historyDb.data[userId] = [];
 | 
			
		||||
    historyDb.save();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    getPersonalHistory,
 | 
			
		||||
    addToPersonalHistory,
 | 
			
		||||
    clearPersonalHistory
 | 
			
		||||
};
 | 
			
		||||
@@ -11,6 +11,7 @@ class Playlist {
 | 
			
		||||
    duration = 0;
 | 
			
		||||
    readduration;
 | 
			
		||||
    description;
 | 
			
		||||
    form = "PLAYLIST"; 
 | 
			
		||||
    type;
 | 
			
		||||
    constructor(title, url, author, authorId, songs, thumbnail, duration, readduration, description) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,10 @@ const {LogType} = require('loguix');
 | 
			
		||||
const clog = new LogType("PlaylistManager");
 | 
			
		||||
const Finder = require('../player/Finder');
 | 
			
		||||
const spotify = require('../media/SpotifyInformation');
 | 
			
		||||
const { getYoutubePlaylistSongs } = require('./Google/YoutubeList');
 | 
			
		||||
const { auth } = require('googleapis/build/src/apis/abusiveexperiencereport');
 | 
			
		||||
const { getReadableDuration } = require('../utils/TimeConverter');
 | 
			
		||||
const { getSecondsFromUrl } = require('../media/YoutubeInformation');
 | 
			
		||||
 | 
			
		||||
const playlistDB = new Database("Playlists", __glob.PLAYLISTFILE, {});
 | 
			
		||||
 | 
			
		||||
@@ -182,6 +186,84 @@ function removeSong(id, playlistName, songId) {
 | 
			
		||||
    clog.log(`Suppression de la chanson ${songId} de la playlist ${playlistName} pour l'utilisateur ${id}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function processYoutubeData(userId, data) {
 | 
			
		||||
    if (!data || data.length === 0) {
 | 
			
		||||
        clog.warn(`Aucune donnée YouTube trouvée pour l'utilisateur ${userId}`);
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const playlists = [];
 | 
			
		||||
     for (const item of data) {
 | 
			
		||||
        if (item.snippet && item.contentDetails) {
 | 
			
		||||
            const playlist = new Playlist();
 | 
			
		||||
            playlist.id = item.id;
 | 
			
		||||
            playlist.title = item.snippet.title;
 | 
			
		||||
            playlist.url = `https://www.youtube.com/playlist?list=${item.id}`;
 | 
			
		||||
            playlist.description = item.snippet.description || "Aucune description disponible";
 | 
			
		||||
            playlist.author = item.snippet.channelTitle;
 | 
			
		||||
            playlist.thumbnail = item.snippet.thumbnails.default.url;
 | 
			
		||||
            playlist.authorId = `https://www.youtube.com/channel/${item.snippet.channelId}`;
 | 
			
		||||
            playlist.songs = []; // You can fetch songs later if needed
 | 
			
		||||
            await getYoutubePlaylistSongs(item.id, userId).then(songsData => {
 | 
			
		||||
                if (songsData && songsData.data && songsData.data.items) {
 | 
			
		||||
                    playlist.songs = songsData.data.items.map(song => ({
 | 
			
		||||
                        id: song.snippet.resourceId.videoId,
 | 
			
		||||
                        title: song.snippet.title,
 | 
			
		||||
                        author: song.snippet.videoOwnerChannelTitle,
 | 
			
		||||
                        authorId: `https://www.youtube.com/channel/${song.snippet.videoOwnerChannelId}`,
 | 
			
		||||
                        url: `https://www.youtube.com/watch?v=${song.snippet.resourceId.videoId}`,
 | 
			
		||||
                        thumbnail: song.snippet?.thumbnails?.default?.url || "https://radomisol.fr/wp-content/uploads/2016/08/cropped-note-radomisol-musique.png",
 | 
			
		||||
                    }));
 | 
			
		||||
                    // Add readduration for every items in songs
 | 
			
		||||
 | 
			
		||||
                } else {
 | 
			
		||||
                    clog.warn(`Aucune chanson trouvée pour la playlist ${item.id}`);
 | 
			
		||||
                }
 | 
			
		||||
            }).catch(err => {
 | 
			
		||||
                clog.error(`Erreur lors de la récupération des chansons pour la playlist ${item.id}:`, err);
 | 
			
		||||
            });
 | 
			
		||||
            for (const song of playlist.songs) {
 | 
			
		||||
                // If authorId is not defined, delete the song
 | 
			
		||||
                if (song.authorId == "https://www.youtube.com/channel/undefined") {
 | 
			
		||||
                    clog.warn(`L'auteur de la chanson ${song.title} (${song.id}) n'est pas défini. Suppression de la chanson.`);
 | 
			
		||||
                    playlist.songs.splice(playlist.songs.indexOf(song), 1);
 | 
			
		||||
                    continue; // Skip this song
 | 
			
		||||
                }
 | 
			
		||||
                song.duration = await getSecondsFromUrl(song.url);
 | 
			
		||||
                if (song.duration === null) {
 | 
			
		||||
                    clog.warn(`Impossible de récupérer la durée de la chanson ${song.title} (${song.id})`);
 | 
			
		||||
                    song.duration = 0; // Set to 0 if duration cannot be fetched
 | 
			
		||||
                } else {
 | 
			
		||||
                    song.readduration = getReadableDuration(song.duration);
 | 
			
		||||
                    playlist.duration += song.duration; // Initialize duration if not set
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
          
 | 
			
		||||
            playlist.readduration = getReadableDuration(playlist.duration);
 | 
			
		||||
            playlist.type = "youtube";
 | 
			
		||||
            playlists.push(playlist);
 | 
			
		||||
        } else {
 | 
			
		||||
            clog.warn(`Données YouTube manquantes pour l'élément ${item.id}`);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    clog.log(`Traitement des données YouTube pour l'utilisateur ${userId} terminé. Nombre de playlists trouvées : ${playlists.length}`);
 | 
			
		||||
    // Save the playlists to the user's playlist collection
 | 
			
		||||
    const userPlaylists = getPlaylistsOfUser(userId);
 | 
			
		||||
    // Remove existing playlists with the same IDs to avoid duplicates
 | 
			
		||||
    for (const playlist of playlists) {
 | 
			
		||||
        const existingIndex = userPlaylists.findIndex(p => p.id === playlist.id);
 | 
			
		||||
        if (existingIndex !== -1) {
 | 
			
		||||
            userPlaylists.splice(existingIndex, 1); // Remove existing playlist with the same ID
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    userPlaylists.push(...playlists);
 | 
			
		||||
    playlistDB.save();
 | 
			
		||||
    clog.log(`Playlists ajoutées pour l'utilisateur ${userId}. Nombre total de playlists : ${userPlaylists.length}`);
 | 
			
		||||
    return playlists;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    getPlaylistsOfUser,
 | 
			
		||||
    getPlaylistOfUser,
 | 
			
		||||
@@ -191,5 +273,6 @@ module.exports = {
 | 
			
		||||
    copyPlaylist,
 | 
			
		||||
    renamePlaylist,
 | 
			
		||||
    addSong,
 | 
			
		||||
    removeSong
 | 
			
		||||
    removeSong,
 | 
			
		||||
    processYoutubeData
 | 
			
		||||
}
 | 
			
		||||
@@ -1,234 +0,0 @@
 | 
			
		||||
# Documentation des Requêtes `socket.io`
 | 
			
		||||
 | 
			
		||||
Les requêtes sont du point de vue du serveur.
 | 
			
		||||
 | 
			
		||||
Le Client doit être initialisé comme ceci :
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
const socket = io("subsonics.raphix.fr:5000", {
 | 
			
		||||
  auth: {
 | 
			
		||||
    token: "TOKEN_HERE",
 | 
			
		||||
    auth_code: "AUTH_FROM_DISCORD_HERE",
 | 
			
		||||
    session: "SESSION_ID_HERE"
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
REDIRECT_CALLBACK = `/callback`
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Requêtes Envoyées
 | 
			
		||||
 | 
			
		||||
### Événement : `NEW_SESSION`
 | 
			
		||||
 | 
			
		||||
- **Description** : `/login` et `/` : Envoie un jeton de session utile pour la traçabilité de la connexion par Discord. Dès réception, le client le stocke dans les cookies sous le nom `session`. Si l'utilisateur n'est pas sur `/login`, il doit y être redirigé. Supprime également le cookie `token` s’il existe.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"SESSION_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Événement : `NEW_TOKEN`
 | 
			
		||||
 | 
			
		||||
- **Description** : `/callback` : Lors de la redirection depuis Discord, ce jeton est généré après vérification du code d'autorisation. Il est envoyé au client qui est ensuite redirigé vers `/`.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"TOKEN_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Événement : `BANNED`
 | 
			
		||||
 | 
			
		||||
- **Description** : `/callback` et `/` : Si reçu, le client est redirigé vers la page de connexion avec l'erreur "BANNI".
 | 
			
		||||
 | 
			
		||||
### Événement : `AUTH_ERROR`
 | 
			
		||||
 | 
			
		||||
- **Description** : `/callback` et `/` : Erreur lors de l’authentification (ex. code Discord invalide ou accès refusé).
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Requêtes Reçues
 | 
			
		||||
 | 
			
		||||
> Toutes les requêtes commencent par l’événement `socket.on("EVENT_NAME", callback)` côté client, et sont traitées côté serveur par `IORequest("EVENT_NAME", callback)`.
 | 
			
		||||
 | 
			
		||||
### Utilisateur
 | 
			
		||||
 | 
			
		||||
#### `/USER/INFO`
 | 
			
		||||
 | 
			
		||||
- **Description** : Renvoie l’identité Discord, les guildes et les labels de l'utilisateur connecté.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
{}
 | 
			
		||||
```
 | 
			
		||||
- **Réponse** :
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "identity": { ... },
 | 
			
		||||
  "guilds": [ ... ],
 | 
			
		||||
  "labels": [ "admin", ... ]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/USERS/LIST`
 | 
			
		||||
 | 
			
		||||
- **Description** : Renvoie la liste des utilisateurs connectés à une guilde.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"GUILD_ID"
 | 
			
		||||
```
 | 
			
		||||
- **Réponse** :
 | 
			
		||||
```json
 | 
			
		||||
[ { "id": "...", "username": "...", ... }, ... ]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Player (Musique)
 | 
			
		||||
 | 
			
		||||
#### `/PLAYER/STATE`
 | 
			
		||||
 | 
			
		||||
- **Description** : Récupère l'état actuel du player pour une guilde.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"GUILD_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/PLAYER/JOIN` / `/PLAYER/LEAVE`
 | 
			
		||||
 | 
			
		||||
- **Description** : Rejoint ou quitte l’écoute du player pour une guilde.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"GUILD_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/PLAYER/PAUSE`, `/PLAYER/BACKWARD`, `/PLAYER/FORWARD`, `/PLAYER/LOOP`, `/PLAYER/SHUFFLE`, `/PLAYER/DISCONNECT`
 | 
			
		||||
 | 
			
		||||
- **Description** : Contrôle du player (pause, chanson précédente/suivante, boucle, aléatoire, déconnexion).
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"GUILD_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/PLAYER/CHANNEL/CHANGE`
 | 
			
		||||
 | 
			
		||||
- **Description** : Change le salon vocal du player vers celui de l’utilisateur.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"GUILD_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/PLAYER/SEEK`
 | 
			
		||||
 | 
			
		||||
- **Description** : Change la position de la lecture.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["GUILD_ID", TEMPS_EN_SECONDES]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Queue
 | 
			
		||||
 | 
			
		||||
#### `/QUEUE/PLAY/NOW`
 | 
			
		||||
 | 
			
		||||
- **Description** : Joue une chanson de la queue immédiatement.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["GUILD_ID", "previous"|"next", INDEX]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/QUEUE/NEXT/DELETE`, `/QUEUE/NEXT/DELETEALL`, `/QUEUE/NEXT/MOVE`
 | 
			
		||||
 | 
			
		||||
- **Description** : Supprime ou déplace une chanson dans la file d’attente.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["GUILD_ID", INDEX (ou NEW_INDEX)]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Recherche
 | 
			
		||||
 | 
			
		||||
#### `/SEARCH`
 | 
			
		||||
 | 
			
		||||
- **Description** : Effectue une recherche de musique.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"QUERY"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/SEARCH/PLAY`
 | 
			
		||||
 | 
			
		||||
- **Description** : Joue un morceau directement ou l'ajoute à la queue.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["GUILD_ID", SONG, now (bool)]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Playlists
 | 
			
		||||
 | 
			
		||||
#### `/PLAYLISTS/CREATE`, `/DELETE`, `/RENAME`, `/ADD_SONG`, `/REMOVE_SONG`, `/SEND`, `/PLAY`
 | 
			
		||||
 | 
			
		||||
- **Description** : Gère les playlists (création, suppression, renommage, ajout, lecture, envoi à un autre utilisateur).
 | 
			
		||||
- **Données envoyées** : Variable selon l'action, ex :
 | 
			
		||||
```json
 | 
			
		||||
["PLAYLIST_NAME", SONG]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/PLAYLISTS/LIST`
 | 
			
		||||
 | 
			
		||||
- **Description** : Renvoie la liste des playlists de l'utilisateur.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
{}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Admin
 | 
			
		||||
 | 
			
		||||
> Nécessite le label `"admin"` dans `socketUser.labels`.
 | 
			
		||||
 | 
			
		||||
#### `/ADMIN/LOGS`
 | 
			
		||||
 | 
			
		||||
- **Description** : Renvoie les logs du serveur.
 | 
			
		||||
 | 
			
		||||
#### `/ADMIN/MAINTENANCE/RESTART`
 | 
			
		||||
 | 
			
		||||
- **Description** : Redémarre le serveur avec une raison.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"RAISON"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/ADMIN/USERS/SWITCH_ADMIN`, `/FULL_BAN`, `/DELETE`
 | 
			
		||||
 | 
			
		||||
- **Description** : Gère les utilisateurs (promotion admin, ban complet, suppression).
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
"USER_ID"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/ADMIN/PLAYER/GETALLSTATE`
 | 
			
		||||
 | 
			
		||||
- **Description** : Renvoie l’état de tous les players.
 | 
			
		||||
 | 
			
		||||
### Owner / Modérateur
 | 
			
		||||
 | 
			
		||||
#### `/OWNER/USERS/SWITCH_MOD`
 | 
			
		||||
 | 
			
		||||
- **Description** : Nomme ou enlève un modérateur.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["USER_ID", "GUILD_ID"]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `/MOD/USERS/BAN`
 | 
			
		||||
 | 
			
		||||
- **Description** : Bannit un utilisateur d’une guilde.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["USER_ID", "GUILD_ID"]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Utilitaires
 | 
			
		||||
 | 
			
		||||
#### `/REPORT`
 | 
			
		||||
 | 
			
		||||
- **Description** : Envoie un rapport avec un niveau et une description.
 | 
			
		||||
- **Données envoyées** :
 | 
			
		||||
```json
 | 
			
		||||
["LEVEL", "DESCRIPTION"]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@@ -15,10 +15,18 @@ const Finder = require("../player/Finder")
 | 
			
		||||
const fs = require("fs")
 | 
			
		||||
const {__glob} = require("../utils/GlobalVars")
 | 
			
		||||
const playlists = require("../playlists/PlaylistManager")
 | 
			
		||||
const history = require("../playlists/History")
 | 
			
		||||
const lyrics = require("../lyrics/Lyrics")
 | 
			
		||||
const mediaBase = require("../discord/MediaBase")
 | 
			
		||||
const googleApis = require("../playlists/Google/OAuth2")
 | 
			
		||||
const youtubeApi = require("../playlists/Google/YoutubeList")
 | 
			
		||||
 | 
			
		||||
const configuration = require("../utils/Database/Configuration")
 | 
			
		||||
const { List } = require('../player/List')
 | 
			
		||||
const { restart } = require('../utils/Maintenance')
 | 
			
		||||
const { isAudioFile } = require('../utils/AudioBufferCheck')
 | 
			
		||||
const { Song } = require('../player/Song')
 | 
			
		||||
const { getMediaInformationFromUrl } = require('../media/MediaInformation')
 | 
			
		||||
 | 
			
		||||
const allConnectedUsers = new Array()
 | 
			
		||||
const guildConnectedUsers = new Map()
 | 
			
		||||
@@ -205,18 +213,21 @@ function init() {
 | 
			
		||||
                    identity: socketUser.identity,
 | 
			
		||||
                    guilds: guildPresents, 
 | 
			
		||||
                    labels: socketUser.labels,
 | 
			
		||||
                   
 | 
			
		||||
                    history: history.getPersonalHistory(socketUser.identity.id),
 | 
			
		||||
                })
 | 
			
		||||
                wlog.log("Envoi des informations Discord de '" + socketUser.identity.id + "' à '" + socket.id + "'" )
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            IORequest("/USER/HISTORY", () => {
 | 
			
		||||
                IOAnswer("/USER/HISTORY", history.getPersonalHistory(socketUser.identity.id))
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            //CHECKED : 24/04/2025
 | 
			
		||||
            IORequest("/USER/SIGNOUT", () => {
 | 
			
		||||
                socketUser.removeToken(token)
 | 
			
		||||
                socket.disconnect()
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // CHECKED : 24/04/2025 
 | 
			
		||||
            IORequest("/USERS/LIST", (guildId) => {
 | 
			
		||||
                if(!checkUserGuild(socketUser, guildId)) return
 | 
			
		||||
@@ -226,6 +237,28 @@ function init() {
 | 
			
		||||
 | 
			
		||||
            // PLAYERS
 | 
			
		||||
 | 
			
		||||
            IORequest("/PLAYER/LYRICS", async (guildId) => {
 | 
			
		||||
                if(!checkUserGuild(socketUser, guildId)) return
 | 
			
		||||
                const player = await verifyPlayerAction(guildId)
 | 
			
		||||
                if(!player) return IOAnswer("/PLAYER/LYRICS", false)
 | 
			
		||||
                if(!player.queue?.current) {
 | 
			
		||||
                    wlog.warn("Le player de la guilde : " + guildId + " n'a pas de musique en cours")
 | 
			
		||||
                    IOAnswer("/PLAYER/LYRICS", false)
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                const song = player.queue.current
 | 
			
		||||
                const lyricsData = await lyrics.getLyrics(song.title + " " + song.author)
 | 
			
		||||
                console.log(lyricsData)
 | 
			
		||||
                if(!lyricsData) {
 | 
			
		||||
                    wlog.warn("Aucune lyrics trouvée pour la musique : " + song.title + " de l'artiste : " + song.author)
 | 
			
		||||
                    IOAnswer("/PLAYER/LYRICS", false)
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                IOAnswer("/PLAYER/LYRICS", lyricsData)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            //CHECKED : 03/05/2025
 | 
			
		||||
            IORequest("/PLAYER/PREVIOUS/LIST", (guildId) => {   
 | 
			
		||||
                if(!checkUserGuild(socketUser, guildId)) return
 | 
			
		||||
@@ -316,9 +349,9 @@ function init() {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // CHECKED : 04/05/2025            
 | 
			
		||||
            IORequest("/QUEUE/PLAY/NOW", (data) => {
 | 
			
		||||
            IORequest("/QUEUE/PLAY", (data) => {
 | 
			
		||||
                if(!data) return IOAnswer("/QUEUE/PLAY/NOW", false)
 | 
			
		||||
                const {guildId, index, listType} = data
 | 
			
		||||
                const {guildId, index, listType, now} = data
 | 
			
		||||
                if(!index) return IOAnswer("/QUEUE/PLAY/NOW", false)
 | 
			
		||||
                if(!guildId) return IOAnswer("/QUEUE/PLAY/NOW", false)
 | 
			
		||||
                if(!listType) return IOAnswer("/QUEUE/PLAY/NOW", false)
 | 
			
		||||
@@ -335,7 +368,12 @@ function init() {
 | 
			
		||||
                }
 | 
			
		||||
                if(!song) return IOAnswer("/QUEUE/PLAY/NOW", false)
 | 
			
		||||
                if(listType == "next") player.queue.removeNextByIndex(index)
 | 
			
		||||
                player.play(song)
 | 
			
		||||
                if(now) {
 | 
			
		||||
                    player.play(song)
 | 
			
		||||
                } else {
 | 
			
		||||
                    player.add(song)
 | 
			
		||||
                }
 | 
			
		||||
                history.addToPersonalHistory(socketUser.identity.id, song)
 | 
			
		||||
                IOAnswer("/QUEUE/PLAY/NOW", true)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
@@ -395,6 +433,7 @@ function init() {
 | 
			
		||||
                } else {
 | 
			
		||||
                    player.add(song)
 | 
			
		||||
                }
 | 
			
		||||
                history.addToPersonalHistory(socketUser.identity.id, song)
 | 
			
		||||
                IOAnswer("/SEARCH/PLAY", true)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
@@ -412,9 +451,72 @@ function init() {
 | 
			
		||||
                IOAnswer("/SEARCH/PLAYLIST", true)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            IORequest("/SEARCH/LYRICS", async (name) => {
 | 
			
		||||
                if(!name) return IOAnswer("/SEARCH/LYRICS", false)
 | 
			
		||||
                const lyricsData = await lyrics.getLyrics(name)
 | 
			
		||||
                if(!lyricsData) return IOAnswer("/SEARCH/LYRICS", false)
 | 
			
		||||
                IOAnswer("/SEARCH/LYRICS", lyricsData)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            // UPLOAD
 | 
			
		||||
 | 
			
		||||
            // CHECKED : 29/05/2025
 | 
			
		||||
 | 
			
		||||
            IORequest("/UPLOAD/FILE", async (data) => {
 | 
			
		||||
                if(!data) return IOAnswer("/UPLOAD/FILE", false)
 | 
			
		||||
                if(!data.name) return IOAnswer("/UPLOAD/FILE", false)
 | 
			
		||||
                const file = data.file
 | 
			
		||||
                // Check wav or mp3
 | 
			
		||||
                if(isAudioFile(file) == false) {
 | 
			
		||||
                    wlog.warn("Le fichier envoyé n'est pas un fichier audio valide (MP3/WAV)")
 | 
			
		||||
                    return IOAnswer("/UPLOAD/FILE", false)
 | 
			
		||||
                }
 | 
			
		||||
                const url = await mediaBase.postMedia(data)
 | 
			
		||||
                if(!url) return IOAnswer("/UPLOAD/FILE", false)
 | 
			
		||||
                IOAnswer("/UPLOAD/FILE", {"url": url, "name": data.name})
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            // CHECKED : 29/05/2025
 | 
			
		||||
            IORequest("/UPLOAD/FILE/GET_SONG", async (data) => {
 | 
			
		||||
                if(!data) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
 | 
			
		||||
                const {name, url} = data
 | 
			
		||||
                if(!url) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
 | 
			
		||||
                if(!name) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
 | 
			
		||||
                const song = new Song()
 | 
			
		||||
                if(!song) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
 | 
			
		||||
                await getMediaInformationFromUrl(song, url)
 | 
			
		||||
                song.type = "attachment"
 | 
			
		||||
                song.author = socketUser.identity.username
 | 
			
		||||
                song.authorId = socketUser.identity.id
 | 
			
		||||
                song.title = name
 | 
			
		||||
                song.url = url
 | 
			
		||||
                IOAnswer("/UPLOAD/FILE/GET_SONG", song)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            // GOOGLE API
 | 
			
		||||
 | 
			
		||||
            IORequest("/GOOGLE/AUTH", () => {
 | 
			
		||||
                IOAnswer("/GOOGLE/AUTH", googleApis.createAuthUrl(socketUser.identity.id))
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            IORequest("/GOOGLE/YOUTUBE/ADD_PLAYLIST", async (code) => {
 | 
			
		||||
                if(!code) {
 | 
			
		||||
                    IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", false)
 | 
			
		||||
                }
 | 
			
		||||
                const token = await googleApis.getAuthorization(socketUser.identity.id, code)
 | 
			
		||||
                if(!token) {
 | 
			
		||||
                    IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", false)
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                playlists.processYoutubeData(socketUser.identity.id, await youtubeApi.getYoutubePlaylists(socketUser.identity.id))
 | 
			
		||||
                IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", true)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // PLAYLISTS
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            // CHECKED : 30/04/2025
 | 
			
		||||
            IORequest("/PLAYLISTS/CREATE", async (data) => {
 | 
			
		||||
                if(!data) return IOAnswer("/PLAYLISTS/CREATE", false)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								backend/src/utils/AudioBufferCheck.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								backend/src/utils/AudioBufferCheck.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
function isAudioFile(buffer) {
 | 
			
		||||
    // Ensure the buffer is long enough to contain the magic number
 | 
			
		||||
    if (!Buffer.isBuffer(buffer)) {
 | 
			
		||||
        throw new TypeError('Expected a Buffer');
 | 
			
		||||
    }
 | 
			
		||||
    if (buffer.length < 2) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Convert the first few bytes to a hex string
 | 
			
		||||
    const signature = buffer.subarray(0, 4).toString('hex').toUpperCase();
 | 
			
		||||
 | 
			
		||||
    // Audio file signatures
 | 
			
		||||
    const audioSignatures = [
 | 
			
		||||
        '494433', // ID3 tag for MP3
 | 
			
		||||
        'FFFB', // Another possible MP3 signature
 | 
			
		||||
        'FFF3', // Another possible MP3 signature
 | 
			
		||||
        'FFF2', // Another possible MP3 signature
 | 
			
		||||
        '52494646', // RIFF header for WAV
 | 
			
		||||
        '4F676753', // OGG container
 | 
			
		||||
        '66747970', // MP4 container
 | 
			
		||||
        // Add more audio file signatures as needed
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // Check if the signature matches any known audio file type
 | 
			
		||||
    return audioSignatures.some(magicNumber => signature.startsWith(magicNumber));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    isAudioFile
 | 
			
		||||
};
 | 
			
		||||
@@ -14,7 +14,10 @@ const config = new Database("config", __glob.DATA  + path.sep + "config.json", {
 | 
			
		||||
        contact : ""
 | 
			
		||||
    },
 | 
			
		||||
    api: {
 | 
			
		||||
        youtube: "",
 | 
			
		||||
        youtube: {
 | 
			
		||||
            clientId : "" ,
 | 
			
		||||
            clientSecret: ""
 | 
			
		||||
        },
 | 
			
		||||
        spotify: {
 | 
			
		||||
            clientId: "",
 | 
			
		||||
            clientSecret: ""
 | 
			
		||||
@@ -22,6 +25,10 @@ const config = new Database("config", __glob.DATA  + path.sep + "config.json", {
 | 
			
		||||
    },
 | 
			
		||||
    website: "",
 | 
			
		||||
    server_port: 5000,
 | 
			
		||||
    media: {
 | 
			
		||||
        guildId: "",
 | 
			
		||||
        channelId: "",
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
function getToken() {
 | 
			
		||||
@@ -36,8 +43,12 @@ function getReportContact() {
 | 
			
		||||
    return config.data.report.contact
 | 
			
		||||
}   
 | 
			
		||||
 | 
			
		||||
function getYoutubeApiKey() {
 | 
			
		||||
    return config.data.api.youtube
 | 
			
		||||
function getYoutubeApiClientId() {
 | 
			
		||||
    return config.data.api.youtube.clientId
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getYoutubeApiClientSecret() {
 | 
			
		||||
    return config.data.api.youtube.clientSecret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getSpotifyClientId() {
 | 
			
		||||
@@ -61,9 +72,31 @@ function getClientSecret() {
 | 
			
		||||
    return config.data.client_secret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getMediaGuildId() {
 | 
			
		||||
    return config.data.media.guildId
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getMediaChannelId() {
 | 
			
		||||
    return config.data.media.channelId
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if(getToken() == "") {
 | 
			
		||||
    clog.error("Impossible de démarrer sans token valide")
 | 
			
		||||
    process.exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {getToken, getClientSecret, getReportChannel, getReportContact, getYoutubeApiKey, getSpotifyClientId, getSpotifyClientSecret, getWebsiteLink, getPort}
 | 
			
		||||
module.exports = {
 | 
			
		||||
    getToken,
 | 
			
		||||
    getClientSecret,
 | 
			
		||||
    getReportChannel,
 | 
			
		||||
    getReportContact,
 | 
			
		||||
    getYoutubeApiClientId,
 | 
			
		||||
    getYoutubeApiClientSecret,
 | 
			
		||||
    getSpotifyClientId,
 | 
			
		||||
    getSpotifyClientSecret,
 | 
			
		||||
    getWebsiteLink,
 | 
			
		||||
    getPort,
 | 
			
		||||
    getMediaGuildId,
 | 
			
		||||
    getMediaChannelId
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -12,6 +12,8 @@ const __glob = {
 | 
			
		||||
    PREVIOUSFILE: root + path.sep + "data" + path.sep + "previous.json",
 | 
			
		||||
    USERFILE: root + path.sep + "data" + path.sep + "users.json",
 | 
			
		||||
    PLAYLISTFILE: root + path.sep + "data" + path.sep + "playlists.json",
 | 
			
		||||
    HISTORY_DB: root + path.sep + "data" + path.sep + "history.json",
 | 
			
		||||
    MEDIA_DB: root + path.sep + "data" + path.sep + "media.json",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {__glob}
 | 
			
		||||
		Reference in New Issue
	
	Block a user