Version 2.0.0 - Refonte complète du Bot

This commit is contained in:
Raphael 2024-02-05 22:49:15 +01:00
parent 87c967d1eb
commit a51c027985
49 changed files with 5545 additions and 3859 deletions

2
.gitignore vendored
View File

@ -132,6 +132,6 @@ dist
.pnp.* .pnp.*
data/config.json data/config.json
data

17
DONTREADME.md Normal file
View File

@ -0,0 +1,17 @@
# **Easter Egg Subsonics**
> Un savant fou fait des recherches sur les gens du CLP et a caché son système et ses recherches sur le site du bot
**Etapes**
* Page caché
* Confirmation avec le bot
* Erreur assembler le programme
* Accès aux donnés
# Idéés
- Faille dans le bot (à) la recherche
- C'est moi le grand méchant et il doivent arrêter mon plan macchiavélique
- Etape : Me parler pour me soutirer des infos : Genre une histoire

View File

View File

@ -1,42 +1,12 @@
# <center>Subsonics Web</center> <img style='width: 150px; margin-left: auto; margin-right: auto;' src='/images/logo-with-background.png'>
<div style="font-size: 20px"> # <center style='font-family: Gunship;'>Subsonics WEB</center>
* En cas de bug, n'hésitez pas à faire un **report** sur votre profil. <center>Bienvenue sur le site de Subsonics ! Recherche, lance et écoute ! <br>
* Vous pouvez utiliser la commande **/restart** sur Discord pour redémarrer l'intégralité du Bot ! Si tu veux utiliser le bot, pas de soucis mais vérifie que quelqu'un ne l'utilise pas !</center>
* Pour toute suggestion, vous pouvez envoyez un rapport avec la catégorie Suggestion !
<div style='font-size: 12px;'>
</div> <center>Fait avec ❤️ par Raphix
<br> Pour le CLP :)
<hr> <br> Avec l'aide de Gabouille et de IcePlayer </center>
</div>
<div style="font-size: 14px; display: flex; flex-direction: column; gap: 2px;">
<strong>
<center>Développé par Raphix</center>
<center>Avec l'aide de Gabouille et de IcePlayer</center>
<center>Pour le CLP 💖</center>
</strong>
</div>
# Changelog
## Subsonics - Web - 2.0.0
- **Adds :** *Rework Style, Soundboard Editor, OOBE*
### Details
**Rework Style**
> - Style principal, (Cf StylePlans)
> - Création d'éléments modèles (Classe commune)
> - Permettre l'ajout de playlist youtube en favoris
**Soundboard Editor**
> - Faire l'HTML & CSS
> - Faire le lien entre l'API Discord et Subsonics
> - Demander les permissions à IcePlayer
**OOBE**
> - Faire l'HTML & CSS
> - Faire la vérification de la lecture de l'OOBE

285
package-lock.json generated
View File

@ -15,6 +15,7 @@
"erela.js": "^2.4.0", "erela.js": "^2.4.0",
"express": "^4.18.2", "express": "^4.18.2",
"express-favicon": "^2.0.4", "express-favicon": "^2.0.4",
"genius-lyrics": "^4.4.6",
"loguix": "^1.4.2", "loguix": "^1.4.2",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
@ -107,6 +108,14 @@
"node": ">=16.9.0" "node": ">=16.9.0"
} }
}, },
"node_modules/@fastify/busboy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
"engines": {
"node": ">=14"
}
},
"node_modules/@opencensus/core": { "node_modules/@opencensus/core": {
"version": "0.0.9", "version": "0.0.9",
"resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz",
@ -810,6 +819,11 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -835,17 +849,6 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
}, },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -1098,6 +1101,32 @@
"resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz",
"integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==" "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ=="
}, },
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/culvert": { "node_modules/culvert": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz",
@ -1202,6 +1231,68 @@
"node": ">=16.9.0" "node": ">=16.9.0"
} }
}, },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/dom-serializer/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
]
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/ecc-jsbn": { "node_modules/ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@ -1681,6 +1772,15 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
}, },
"node_modules/genius-lyrics": {
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/genius-lyrics/-/genius-lyrics-4.4.6.tgz",
"integrity": "sha512-TeSF4qXwLm+Nl8wUX+WUTJlEhPBanMw9EWpIHE2a/Qs4y2NBK99AHYfZJc73H1HVkZj4zPfscuGWlkQbbh0pDA==",
"dependencies": {
"node-html-parser": "^6.1.9",
"undici": "^5.24.0"
}
},
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
@ -1845,6 +1945,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"bin": {
"he": "bin/he"
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -2341,6 +2449,15 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/node-html-parser": {
"version": "6.1.12",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.12.tgz",
"integrity": "sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA==",
"dependencies": {
"css-select": "^5.1.0",
"he": "1.2.0"
}
},
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "2.0.22", "version": "2.0.22",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz",
@ -2420,6 +2537,17 @@
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
"integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==" "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ=="
}, },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/oauth-sign": { "node_modules/oauth-sign": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@ -3470,14 +3598,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -3674,11 +3794,11 @@
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
}, },
"node_modules/undici": { "node_modules/undici": {
"version": "5.22.1", "version": "5.28.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz",
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==",
"dependencies": { "dependencies": {
"busboy": "^1.6.0" "@fastify/busboy": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=14.0" "node": ">=14.0"
@ -3893,6 +4013,11 @@
"ws": "^8.13.0" "ws": "^8.13.0"
} }
}, },
"@fastify/busboy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA=="
},
"@opencensus/core": { "@opencensus/core": {
"version": "0.0.9", "version": "0.0.9",
"resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz",
@ -4431,6 +4556,11 @@
"unpipe": "1.0.0" "unpipe": "1.0.0"
} }
}, },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -4453,14 +4583,6 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
}, },
"busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"requires": {
"streamsearch": "^1.1.0"
}
},
"bytes": { "bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -4654,6 +4776,23 @@
"resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz",
"integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==" "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ=="
}, },
"css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
}
},
"css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
},
"culvert": { "culvert": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz",
@ -4736,6 +4875,46 @@
"ws": "^8.13.0" "ws": "^8.13.0"
} }
}, },
"dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"requires": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"dependencies": {
"entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
}
}
},
"domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
},
"domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"requires": {
"domelementtype": "^2.3.0"
}
},
"domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"requires": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
}
},
"ecc-jsbn": { "ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@ -5076,6 +5255,15 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
}, },
"genius-lyrics": {
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/genius-lyrics/-/genius-lyrics-4.4.6.tgz",
"integrity": "sha512-TeSF4qXwLm+Nl8wUX+WUTJlEhPBanMw9EWpIHE2a/Qs4y2NBK99AHYfZJc73H1HVkZj4zPfscuGWlkQbbh0pDA==",
"requires": {
"node-html-parser": "^6.1.9",
"undici": "^5.24.0"
}
},
"get-intrinsic": { "get-intrinsic": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
@ -5194,6 +5382,11 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
}, },
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"http-errors": { "http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -5574,6 +5767,15 @@
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="
}, },
"node-html-parser": {
"version": "6.1.12",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.12.tgz",
"integrity": "sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA==",
"requires": {
"css-select": "^5.1.0",
"he": "1.2.0"
}
},
"nodemon": { "nodemon": {
"version": "2.0.22", "version": "2.0.22",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz",
@ -5635,6 +5837,14 @@
} }
} }
}, },
"nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"requires": {
"boolbase": "^1.0.0"
}
},
"oauth-sign": { "oauth-sign": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@ -6406,11 +6616,6 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}, },
"streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
},
"string_decoder": { "string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -6543,11 +6748,11 @@
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
}, },
"undici": { "undici": {
"version": "5.22.1", "version": "5.28.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz",
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==",
"requires": { "requires": {
"busboy": "^1.6.0" "@fastify/busboy": "^2.0.0"
} }
}, },
"universalify": { "universalify": {

View File

@ -1,7 +1,7 @@
{ {
"name": "subsonics-web", "name": "subsonics-web",
"author": "Raphix", "author": "Raphix",
"version": "1.1.0", "version": "2.0.0",
"nodemonConfig": { "nodemonConfig": {
"ext": "js, html", "ext": "js, html",
"ignore": [ "ignore": [
@ -19,6 +19,7 @@
"erela.js": "^2.4.0", "erela.js": "^2.4.0",
"express": "^4.18.2", "express": "^4.18.2",
"express-favicon": "^2.0.4", "express-favicon": "^2.0.4",
"genius-lyrics": "^4.4.6",
"loguix": "^1.4.2", "loguix": "^1.4.2",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",

View File

@ -16,8 +16,9 @@ module.exports = {
await interaction.reply({embeds: [membed]}) await interaction.reply({embeds: [membed]})
pm2.restart('SubSonics - Bot Discord') pm2.restart("Subsonics")
} }
} }

View File

@ -6,8 +6,6 @@ const { __glob } = require("./global-variables")
const { LogType } = require("loguix") const { LogType } = require("loguix")
const { List } = require("./sub-list") const { List } = require("./sub-list")
const nodeFinder = require("./nodes-finder") const nodeFinder = require("./nodes-finder")
const subplayer = require("./sub-player")
const nodemon = require("nodemon")
const metric = require("webmetrik") const metric = require("webmetrik")
const client = new Client({ const client = new Client({
@ -153,25 +151,6 @@ function init(dlog, config) {
function startErelaManager(dlog, config) { function startErelaManager(dlog, config) {
const elog = new LogType("Lavalink-Manager") const elog = new LogType("Lavalink-Manager")
client.on("voiceStateUpdate", (oldMember, newMember) => {
membersVoices.set(newMember.id, newMember.channelId)
let player = client.manager.players.get(oldMember.guild.id)
if(player) {
client.channels.fetch(player.options.voiceChannel).then(channel => {
if(channel.members.size <= 1) {
player.destroy()
}
})
}
})
const nodes = nodeFinder.getNodes() const nodes = nodeFinder.getNodes()
client.manager = new Manager({ client.manager = new Manager({
@ -191,19 +170,22 @@ function startErelaManager(dlog, config) {
membersVoices.set(newMember.id, newMember.channelId) membersVoices.set(newMember.id, newMember.channelId)
/* SECURITY DISABLED
let player = client.manager.players.get(oldMember.guild.id) let player = client.manager.players.get(oldMember.guild.id)
if(player) {
client.channels.fetch(player.options.voiceChannel).then(channel => {
if(player) { if(channel.members.size <= 1) {
client.channels.fetch(player.options.voiceChannel).then(channel => { player.destroy()
plog.log("[Automatic Task] Player supprimé dans : " + channel.name)
if(channel.members.size <= 1) { }
})
player.destroy()
plog.log("[Automatic Task] Player supprimé dans : " + channel.name) }*/
}
})
}
}) })
@ -261,9 +243,8 @@ function startErelaManager(dlog, config) {
if(await list.haveSongs()) { if(await list.haveSongs()) {
await player.play(list.next()) await player.play(list.next())
console.log("Lecture de la musique suivante")
} }
} }
@ -295,17 +276,4 @@ function startErelaManager(dlog, config) {
client.on("raw", d => client.manager.updateVoiceState(d)); client.on("raw", d => client.manager.updateVoiceState(d));
} }
async function closeClient() {
console.log("Fermeture du client Discord")
if(client) {
let player = await client.manager.players.get("137291455336022018")
if(player) {
await player.destroy()
}
client.destroy()
}
}

View File

@ -17,10 +17,10 @@ const __glob = {
NODES: root + path.sep + "data" + path.sep + "nodes.json", NODES: root + path.sep + "data" + path.sep + "nodes.json",
README: root + path.sep + "README.md", README: root + path.sep + "README.md",
PLAYLIST: root + path.sep + "data" + path.sep + "playlist.json", PLAYLIST: root + path.sep + "data" + path.sep + "playlist.json",
RADIO: root + path.sep + "data" + path.sep + "radios.json",
LOGS: root + path.sep + "src" + path.sep + "modules" + path.sep + "logs", LOGS: root + path.sep + "src" + path.sep + "modules" + path.sep + "logs",
METRIC_FILE: root + path.sep + "data" + path.sep + "metrics.json", METRIC_FILE: root + path.sep + "data" + path.sep + "metrics.json",
PICTURE_DIR: root + path.sep + "data" + path.sep + "pictures", PICTURE_DIR: root + path.sep + "data" + path.sep + "pictures",
PREVIOUS_FILE: root + path.sep + "data" + path.sep + "previous.json",
}; };
const webroot = __glob.WEB_DIR + path.sep const webroot = __glob.WEB_DIR + path.sep

View File

@ -91,6 +91,7 @@ module.exports.addNodes = function (data) {
nlog.step.init("add_nodes", "Ajout d'un nouveau noeud dans la base de donnée de nodes : " + data.host) nlog.step.init("add_nodes", "Ajout d'un nouveau noeud dans la base de donnée de nodes : " + data.host)
try { try {
var nodes_data = readNodesFile() var nodes_data = readNodesFile()
data.retryAmount = 1
nodes_data.push(data) nodes_data.push(data)
saveNodesFile(nodes_data) saveNodesFile(nodes_data)
nlog.step.end("add_nodes") nlog.step.end("add_nodes")

View File

@ -1,6 +1,7 @@
const { __glob, __web } = require("./global-variables"); const { __glob, __web } = require("./global-variables");
const { LogType } = require('loguix'); const { LogType } = require('loguix');
const fs = require("fs"); const fs = require("fs");
const { log } = require("console");
const alog = new LogType("Authentification") const alog = new LogType("Authentification")
@ -60,13 +61,14 @@ module.exports.getDiscordUser = function (code, session) {
reject("NOT_IN_CLP") reject("NOT_IN_CLP")
} else if(typeof userInfo.user == "undefined") { } else if(typeof userInfo.user == "undefined") {
reject("MIGRATE_ACCOUNT_ONLY") reject("MIGRATE_ACCOUNT_ONLY")
} else { } else {
// Replace existing user from the DB file if exist // Replace existing user from the DB file if exist
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
for (const user of userDB) { for (const userFromDB of userDB) {
if(user.user.id == userInfo.user.id) { if(userFromDB.user.id == userInfo.user.id) {
userInfo.token = user.token userInfo.token = userFromDB.token
user.banned = userFromDB.banned
} }
} }
@ -74,10 +76,20 @@ module.exports.getDiscordUser = function (code, session) {
if(userInfo.user.id == "486943594893017119") { if(userInfo.user.id == "486943594893017119") {
user.admin = true; user.admin = true;
user.banned = false;
} }
Object.assign(user, userInfo); Object.assign(user, userInfo);
resolve(user);
if(user.banned) {
reject("ACCOUNT_BANNED")
alog.log("Tentative de connexion d'un utilisateur banni : " + user.user.username)
} else {
resolve(user);
}
} }
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -122,11 +134,16 @@ module.exports.removeSession = function (session) {
module.exports.checkUser = function (token) { module.exports.checkUser = function (token) {
var users = this.getUsers()
for(var user of users) { for(var user of users) {
if(user[1].token.includes(token)) { if(user.token.includes(token)) {
return true if(user.banned) {
return false
} else {
return true
}
} }
} }
@ -136,11 +153,17 @@ module.exports.checkUser = function (token) {
module.exports.getUser = function (token) { module.exports.getUser = function (token) {
var users = this.getUsers()
for(var user of users) { for(var user of users) {
if(user[1].token.includes(token)) { if(user.token.includes(token)) {
if(user.banned) {
return user[1] return null
} else {
return user
}
} }
} }
@ -148,7 +171,7 @@ module.exports.getUser = function (token) {
} }
module.exports.getUsers = function () { module.exports.getUsers = function() {
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
return userDB return userDB
@ -156,7 +179,7 @@ module.exports.getUsers = function () {
} }
module.exports.getSimpleUsers = function () { module.exports.getSimpleUsers = function() {
var userList = new Array() var userList = new Array()
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
@ -172,7 +195,7 @@ module.exports.getSimpleUsers = function () {
} }
module.exports.getSimpleUser = function (token) { module.exports.getSimpleUser = function(token) {
const user = this.getUser(token) const user = this.getUser(token)
@ -184,8 +207,46 @@ module.exports.getSimpleUser = function (token) {
return ({"username": user.user.username, "global_name":user.user.global_name, "avatar": user.user.avatar, "id": user.user.id, "admin": user.admin, "picture": user.picture}) return ({"username": user.user.username, "global_name":user.user.global_name, "avatar": user.user.avatar, "id": user.user.id, "admin": user.admin, "picture": user.picture})
} }
module.exports.getOOBE = function(userId) {
const userDB = readUsersFile(__glob.USERS)
for (const user of userDB) {
if(user.user.id == userId) {
if(!user.oobe) {
return true
}
}
}
return false
}
module.exports.addUser = function (user) { module.exports.setOOBE = function(userId) {
const userDB = readUsersFile(__glob.USERS)
var selectedUser = null
for(var user of userDB) {
if(userId == user.user.id) {
selectedUser = user
}
}
if(!selectedUser) {
return
}
userDB[userDB.indexOf(selectedUser)].oobe = true
saveUsersFile(userDB)
}
module.exports.addUser = async function(user) {
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
@ -203,46 +264,56 @@ module.exports.addUser = function (user) {
if(selectedUser != null) { if(selectedUser) {
userDB[selectedUser].token = user.token userDB[selectedUser].token = user.token
if(user.user.id == "486943594893017119") {
userDB[selectedUser].banned = false
}
} else { } else {
userDB.push(user) userDB.push(user)
} }
saveUsersFile( userDB) saveUsersFile( userDB)
var OPdest = __glob.PICTURE_DIR + "/" + user.user.id + ".png" var OPdest = __glob.PICTURE_DIR + "/" + user.user.id + ".png"
if (fs.existsSync(OPdest)) { if (fs.existsSync(OPdest)) {
fs.rmSync(OPdest); fs.rmSync(OPdest);
} }
checkAllPictures() await checkAllPictures()
updateUsers() updateUsers()
alog.log("Ajout de " + user.user.username + " en tant qu'utilisateur avec le token : " + user.token) alog.log("Ajout de " + user.user.username + " en tant qu'utilisateur avec le token : " + user.token)
} }
module.exports.removeUser = function (token) { module.exports.removeUser = function(id) {
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
var selectedUser = null var selectedUser = null
for (const user of userDB) {
if(user.token == token) {
selectedUser = user
for(var user of userDB) {
if(id == user.user.id) {
selectedUser = userDB.indexOf(user)
} }
}
const index = userDB.indexOf(selectedUser)
alog.log("Supression de " + selectedUser.user.username + " en tant qu'utilisateur avec le token : " + selectedUser.token)
userDB.splice(index, 1) }
alog.log("Supression de " + userDB[selectedUser].user.username + " en tant qu'utilisateur avec le token : " + userDB[selectedUser].token)
userDB.splice(selectedUser, 1)
saveUsersFile(userDB) saveUsersFile(userDB)
updateUsers() updateUsers()
} }
module.exports.removeToken = function (token) { module.exports.removeToken = function(token) {
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
var selectedUser = null var selectedUser = null
@ -253,7 +324,7 @@ module.exports.removeToken = function (token) {
selectedUser = user selectedUser = user
} }
} }
const index = userDB.indexOf(selectedUser)
alog.log("Supression du token de " + selectedUser.user.username + " en tant qu'utilisateur avec le token : " + selectedUser.token) alog.log("Supression du token de " + selectedUser.user.username + " en tant qu'utilisateur avec le token : " + selectedUser.token)
const tokens = selectedUser.token const tokens = selectedUser.token
@ -265,17 +336,17 @@ module.exports.removeToken = function (token) {
} }
module.exports.setAdmin = function (user) { module.exports.setAdmin = function(id) {
const userDB = readUsersFile(__glob.USERS) const userDB = readUsersFile(__glob.USERS)
var selectedUser = null var selectedUser = null
for(var userI of userDB) { for(var user of userDB) {
if(user.user.id == userI.user.id) { if(id == user.user.id) {
selectedUser = userDB.indexOf(userI) selectedUser = userDB.indexOf(user)
} }
} }
@ -295,10 +366,45 @@ module.exports.setAdmin = function (user) {
saveUsersFile(userDB) saveUsersFile(userDB)
updateUsers() updateUsers()
alog.log("Ajout de " + user.user.username + " en tant qu'administrateur avec le token : " + user.token) alog.log("Ajout de " + userDB[selectedUser].user.username + " en tant qu'administrateur !")
} }
module.exports.setBan = function(id) {
const userDB = readUsersFile(__glob.USERS)
var selectedUser = null
for(var user of userDB) {
if(id == user.user.id) {
selectedUser = userDB.indexOf(user)
}
}
if(!userDB[selectedUser].banned) {
userDB[selectedUser].banned = true
console.log("[Personnal Quote] - New Ban")
} else {
userDB[selectedUser].banned = false
console.log("[Personnal Quote] - Remove Ban")
}
saveUsersFile(userDB)
updateUsers()
alog.log("Ajout de " + userDB[selectedUser].user.username + " en tant que banni !")
}
function updateUsers() { function updateUsers() {

View File

@ -2,29 +2,76 @@ const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
const { __glob } = require("../modules/global-variables"); const { __glob } = require("../modules/global-variables");
const { LogType } = require('loguix'); const { LogType } = require('loguix');
const discord = require("./discord-bot") const discord = require("./discord-bot")
const fs = require('fs')
const dlog = new LogType("Queue-List") const dlog = new LogType("Queue-List")
var next = new Array() var next = new Array()
var previous = new Array()
var current = null; var current = null;
var shuffle = false var shuffle = false
if(!fs.existsSync(__glob.PREVIOUS_FILE)) {
fs.writeFileSync(__glob.PREVIOUS_FILE, JSON.stringify(new Array(), null, 2))
}
module.exports.List = class { module.exports.List = class {
getList() { getList() {
return next return next
} }
getPreviousList() {
return getPreviousFile()
}
getCurrent() {
return current
}
removeAll() {
next = new Array()
process.emit("MUSIC_UPDATE_STATE")
}
destroy() { destroy() {
next = new Array() next = new Array()
previous = new Array()
current = null current = null
shuffle = false shuffle = false
} }
playQueue(data) {
// Play the song with the index in the queue and delete it from the queue
var index = data[0]
var list = data[1]
if(list == "next") {
const song = next[index]
next.splice(index, 1)
return song
} else if(list == "previous") {
const song = getPreviousFile()[index]
return song
}
}
changeQueue(index) {
//PREVIOUS TO NEXT
const song = getPreviousFile()[index]
next.push(song)
process.emit("MUSIC_UPDATE_STATE")
}
setShuffle(state) { setShuffle(state) {
shuffle = state shuffle = state
@ -55,10 +102,15 @@ module.exports.List = class {
} }
previous() { previous() {
const song = previous[0] const song = getPreviousFile()[0]
previous.splice(0, 1) var previousList = getPreviousFile()
previousList.splice(0, 1)
savePreviousFile(previousList)
return song return song
} }
@ -70,8 +122,12 @@ module.exports.List = class {
} }
addCurrentToPrevious() { addCurrentToPrevious() {
if(current) {
previous.unshift(current) var previousList = getPreviousFile()
previousList.unshift(current)
savePreviousFile(previousList)
}
} }
@ -88,7 +144,8 @@ module.exports.List = class {
havePreviousSongs() { havePreviousSongs() {
if(previous.length == 0) { var previousList = getPreviousFile()
if(previousList.length == 0) {
return false return false
} else{ } else{
@ -97,6 +154,8 @@ module.exports.List = class {
} }
getNextSong() { getNextSong() {
const song = next[0] const song = next[0]
@ -106,6 +165,11 @@ module.exports.List = class {
async add(song, interaction) { async add(song, interaction) {
if(!song) {
process.emit("MUSIC_UPDATE_STATE")
return
}
dlog.log("Ajout d'un titre dans la liste de lecture : '" + song.title + "' de '" + song.author + "'") dlog.log("Ajout d'un titre dans la liste de lecture : '" + song.title + "' de '" + song.author + "'")
next.push(song) next.push(song)
@ -155,21 +219,29 @@ module.exports.List = class {
} }
__previous_add(song) { __previous_add(song) {
if(song) {
previous.unshift(song) var previousList = getPreviousFile()
previousList.unshift(song)
savePreviousFile(previousList)
}
} }
__previous_remove(song) { __previous_remove(song) {
if(song) {
const index = next.indexOf(song) var previousList = getPreviousFile()
previous.splice(index, 1) previousList.splice(previousList.indexOf(song), 1)
savePreviousFile(previousList)
}
} }
__next_add(song) { __next_add(song) {
if(song) {
next.unshift(song) next.unshift(song)
}
} }
async replaceList(data) { async replaceList(data) {
@ -188,7 +260,7 @@ module.exports.List = class {
} }
async playlistAdd(playlist, interaction, userId, ) { async playlistAdd(playlist, interaction, userId, quick ) {
var client = discord.getClient() var client = discord.getClient()
let player = client.manager.players.get("137291455336022018") let player = client.manager.players.get("137291455336022018")
@ -221,13 +293,24 @@ module.exports.List = class {
} }
var numberExecuted = 0
for(var song of playlist.videos) { for(var song of playlist.videos) {
if(song.uri) { if(song.uri) {
song.url = song.uri song.url = song.uri
} }
const song_finded = await client.manager.search(song.url) const song_finded = await client.manager.search(song.url)
// Avoid if song not found
if(!song_finded.tracks[0]) {
numberExecuted += 1
continue
}
next.push(song_finded.tracks[0]) next.push(song_finded.tracks[0])
process.emit("MUSIC_UPDATE_STATE") numberExecuted++
if(numberExecuted == playlist.videos.length) {
process.emit("MUSIC_UPDATE_STATE")
}
} }
if(!player) { if(!player) {
@ -256,6 +339,11 @@ module.exports.List = class {
player.play(next[0]) player.play(next[0])
this.remove(next[0]) this.remove(next[0])
} else {
if(quick) {
player.play(next[0])
this.remove(next[0])
}
} }
@ -266,3 +354,24 @@ module.exports.List = class {
} }
/**
*
* @returns {Array}
*/
function getPreviousFile() {
return JSON.parse(fs.readFileSync(__glob.PREVIOUS_FILE, 'utf8'))
}
function savePreviousFile(db) {
// Add a security to avoid a too big file
if(db.length > 25) {
db.splice(25, db.length - 25)
}
fs.writeFileSync(__glob.PREVIOUS_FILE, (JSON.stringify(db, null, 2)))
}

View File

@ -9,6 +9,12 @@ const { Metric } = require("webmetrik");
const list = new List() const list = new List()
module.exports.getSong = async function (url) {
var client = discord.getClient()
const songs = await client.manager.search(url)
return songs.tracks[0]
}
module.exports.play = async function (client, interaction) { module.exports.play = async function (client, interaction) {
if(interaction) { if(interaction) {
@ -187,12 +193,12 @@ module.exports.getState = function(client, interaction) {
} }
module.exports.playPlaylist = function (id, data) { module.exports.playPlaylist = function (id, data, quick) {
const playlist = {} const playlist = {}
playlist.videos = data playlist.videos = data
list.playlistAdd(playlist, null, id) list.playlistAdd(playlist, null, id, quick)
} }
@ -241,6 +247,10 @@ module.exports.addSong = async function (data, userId, quick, playlist) {
player.play(songs.tracks[0]) player.play(songs.tracks[0])
if(list.getCurrent()) {
list.__previous_add(list.getCurrent())
}
} else { } else {
if(!player.playing && player.paused == false) { if(!player.playing && player.paused == false) {
@ -260,15 +270,20 @@ module.exports.addSong = async function (data, userId, quick, playlist) {
} }
module.exports.addSongsFromPlaylist = async function (data, userId) { module.exports.addSongsFromPlaylist = async function (data, userId, quick) {
var playlist = await checkPlaylist(data) var playlist = await checkPlaylist(data)
if(playlist) { if(playlist) {
if(quick) {
list.playlistAdd(playlist, null, userId) list.removeAll()
list.playlistAdd(playlist, null, userId, true)
} else {
list.playlistAdd(playlist, null, userId)
}
} }
@ -329,6 +344,7 @@ module.exports.skip = function (client, interaction) {
if(player) { if(player) {
player.stop() player.stop()
} }
@ -668,11 +684,13 @@ module.exports.updateMusicState = function (client, action) {
} }
data["queue"] = list.getList(); data["queue"] = list.getList();
data["isOnline"] = true data["isOnline"] = true
} }
data["previous"] = list.getPreviousList();
if(action == "end") { if(action == "end") {
data["current"] = null; data["current"] = null;
@ -738,6 +756,26 @@ module.exports.leave = function (client, interaction) {
} }
module.exports.moveOut = function(userId) {
var memberVoices = discord.getMemberVoices()
var channelId = memberVoices.get(userId)
console.log(channelId)
if(channelId) {
var client = discord.getClient()
var player = client.manager.players.get("137291455336022018")
if(player) {
player.voiceChannel = channelId
player.connect()
}
}
}
// FINI // FINI
async function checkPlaylist (song_name) { async function checkPlaylist (song_name) {
@ -754,6 +792,8 @@ async function checkPlaylist (song_name) {
} }
function playStats(username) { function playStats(username) {
var userMusicPlayed = new Metric("userMusicPlayed_" + username, "Nombre de musiques jouées par l'utilisateur : " + username) var userMusicPlayed = new Metric("userMusicPlayed_" + username, "Nombre de musiques jouées par l'utilisateur : " + username)
userMusicPlayed.setValue(userMusicPlayed.getValue() + 1) userMusicPlayed.setValue(userMusicPlayed.getValue() + 1)

View File

@ -3,49 +3,113 @@ const { __glob } = require("../modules/global-variables");
const { LogType } = require("loguix"); const { LogType } = require("loguix");
const subplayer = require("./sub-player") const subplayer = require("./sub-player")
const fs = require("fs"); const fs = require("fs");
const { randomUUID } = require("crypto");
const { url } = require("inspector");
var playlists = {} var playlists = {}
const plog = new LogType("Playlist-Manager") const plog = new LogType("Playlist-Manager")
check() check()
module.exports.getUser = function (id) {
module.exports.getUser = function (userId) {
check() check()
if(!playlists[id]) { var allPlaylist = new Object()
plog.log("Ajout de l'utilisateur \"" + id + "\" dans la base de donnée Playlist !") // Inject "shared" playlist object in allPlaylist
playlists[id] = {}
if(playlists[userId]) {
// Copy the keys of the user playlist to the allPlaylist object
for(var key in playlists[userId]) {
allPlaylist[key] = playlists[userId][key]
}
// Copy the keys of the shared playlist to the allPlaylist object
for(var key in playlists["shared"]) {
allPlaylist[key] = playlists["shared"][key]
}
}
if(!playlists[userId]) {
plog.log("Ajout de l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
playlists[userId] = {}
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2)) fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
return playlists[id]
return allPlaylist
} else { } else {
plog.log("L'utilisateur \"" + id + "\" existe déjà dans la base de donnée Playlist !") plog.log("L'utilisateur \"" + userId + "\" existe déjà dans la base de donnée Playlist !")
return playlists[id]
return allPlaylist
} }
} }
module.exports.addPlaylist = function (id, name) { module.exports.addPlaylist = function (userId, data) {
check() check()
if(!playlists[id][name]) { var name = data.name
plog.log("Ajout de la playlist à l'utilisateur \"" + id + "\" dans la base de donnée Playlist !") var source = data.source
playlists[id][name] = [] var content = []
if(source == "shared") {
userId = "shared"
}
var alreadyExist = false
for(var pIndex in playlists[userId]) {
if(playlists[userId][pIndex].title == name) {
alreadyExist = true
}
}
if(!alreadyExist) {
plog.log("Ajout de la playlist '" + name + "' à l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
var id = randomUUID().toString()
if(source == "youtube") {
content = data.url
}
playlists[userId][id] = {
"title": name,
"source": data.source,
"content": content
}
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2)) fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else { } else {
plog.log("L'utilisateur \"" + id + "\" à déjà une playlist avec le nom "+ name + " dans la base de donnée Playlist !") plog.log("L'utilisateur \"" + userId + "\" à déjà une playlist avec le nom " + name + " dans la base de donnée Playlist !")
} }
process.emit("PLAYLIST_REFRESH")
} }
module.exports.copyPlaylist = function (id, from, dest) { module.exports.copyPlaylist = function (userId, from, dest) {
this.getUser(dest)
check() check()
let playlistDest = playlists[dest][from] this.getUser(dest)
if(!playlistDest) {
plog.log("Ajout de la playlist à l'utilisateur \"" + id + "\" dans la base de donnée Playlist !") userId = checkSharedMusic(from, userId)
playlists[dest][from] = playlists[id][from]
var alreadyExist = false
for(var pIndex in playlists[dest]) {
if(playlists[dest][pIndex].title == playlists[userId][from].title) {
alreadyExist = true
}
}
var id = randomUUID().toString()
if(!alreadyExist) {
plog.log("Ajout de la playlist à l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
playlists[dest][id] = playlists[userId][from]
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2)) fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else { } else {
@ -54,68 +118,134 @@ module.exports.copyPlaylist = function (id, from, dest) {
} }
process.emit("PLAYLIST_REFRESH")
} }
module.exports.removePlaylist = function (id, name) { module.exports.removePlaylist = function (userId, id) {
check() check()
if(playlists[id][name]) {
plog.log("Supression de la playlist à l'utilisateur \"" + id + "\" dans la base de donnée Playlist !") userId = checkSharedMusic(id, userId)
delete playlists[id][name]
if(playlists[userId][id]) {
plog.log("Supression de la playlist à l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
delete playlists[userId][id]
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2)) fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else { } else {
plog.log("L'utilisateur \"" + id + "\" n'a pas une playlist avec le nom "+ name + " dans la base de donnée Playlist !") plog.log("L'utilisateur \"" + userId + "\" n'a pas une playlist avec l'identifiant "+ id + " dans la base de donnée Playlist !")
} }
} process.emit("PLAYLIST_REFRESH")
module.exports.addSong = function (id, name, song) {
check()
if(playlists[id][name]) {
plog.log("Ajout d'une chanson dans la playlist '" + name + "' à l'utilisateur \"" + id + "\" dans la base de donnée Playlist !")
playlists[id][name].push(song)
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else {
plog.log("L'utilisateur \"" + id + "\" n'a pas une playlist avec le nom "+ name + " dans la base de donnée Playlist !")
}
} }
module.exports.renamePlaylist = function (userId, id, newName) {
module.exports.removeSong = function (id, name, song ) {
check() check()
if(playlists[id][name]) {
plog.log("Supression d'une chanson dans la playlist '" + name + "' à l'utilisateur \"" + id + "\" dans la base de donnée Playlist !") userId = checkSharedMusic(id, userId)
playlists[id][name].splice(playlists[id][name].indexOf(song), 1)
if(playlists[userId][id]) {
plog.log("Renommage de la playlist à l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
playlists[userId][id].title = newName
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2)) fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else { } else {
plog.log("L'utilisateur \"" + id + "\" n'a pas une playlist avec le nom "+ name + " dans la base de donnée Playlist !") plog.log("L'utilisateur \"" + userId + "\" n'a pas une playlist avec l'identifiant "+ id + " dans la base de donnée Playlist !")
}
process.emit("PLAYLIST_REFRESH")
}
module.exports.addSong = async function (userId, id, urlSong) {
check()
userId = checkSharedMusic(id, userId)
if(playlists[userId][id]) {
// Check if it's not a youtube playlist
if(playlists[userId][id].source != "youtube") {
plog.log("Ajout d'une chanson dans la playlist '" + id + "' à l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
var song = await subplayer.getSong(urlSong)
playlists[userId][id].content.push(song)
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else {
plog.log("La playlist '" + id + "' à l'utilisateur \"" + userId + "\" est une playlist youtube, vous ne pouvez pas ajouter de chanson à une playlist youtube !")
}
} else {
plog.log("L'utilisateur \"" + userId + "\" n'a pas une playlist avec le nom "+ id + " dans la base de donnée Playlist !")
} }
process.emit("PLAYLIST_REFRESH")
} }
module.exports.playPlaylist = function (id, name) {
module.exports.removeSong = function (userId, id, identifier ) {
check() check()
if(playlists[id][name]) {
plog.log("Ajout de la playlist à l'utilisateur \"" + id + "\" dans la liste de lecture !") userId = checkSharedMusic(id, userId)
if(playlists[userId][id]) {
plog.log("Supression d'une chanson dans la playlist '" + id + "' à l'utilisateur \"" + userId + "\" dans la base de donnée Playlist !")
subplayer.playPlaylist(id, playlists[id][name]) // Check with the identifier the song to remove
for(var song of playlists[userId][id].content) {
if(song.identifier == identifier) {
playlists[userId][id].content.splice(playlists[userId][id].content.indexOf(song), 1)
}
}
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2))
} else { } else {
plog.log("L'utilisateur \"" + id + "\" n'a pas une playlist avec le nom "+ name + " dans la base de donnée Playlist !") plog.log("L'utilisateur \"" + userId + "\" n'a pas une playlist avec le nom "+ id + " dans la base de donnée Playlist !")
} }
process.emit("PLAYLIST_REFRESH")
}
module.exports.playPlaylist = function (userId, id, quick) {
check()
userId = checkSharedMusic(id, userId)
if(playlists[userId][id]) {
plog.log("Ajout de la playlist à l'utilisateur \"" + userId + "\" dans la liste de lecture !")
subplayer.playPlaylist(id, playlists[userId][id].content, quick)
} else {
plog.log("L'utilisateur \"" + userId + "\" n'a pas une playlist avec le nom "+ id + " dans la base de donnée Playlist !")
}
} }
@ -127,6 +257,20 @@ function check() {
playlists = JSON.parse(fs.readFileSync(__glob.PLAYLIST)) playlists = JSON.parse(fs.readFileSync(__glob.PLAYLIST))
} else { } else {
fs.writeFileSync(__glob.PLAYLIST, JSON.stringify(playlists, null, 2)) fs.writeFileSync(__glob.PLAYLIST, JSON.stringify({
"shared": {
}
}, null, 2))
} }
}
function checkSharedMusic(id, originalUserId) {
for(var playlist in playlists["shared"]) {
if(playlist == id) {
return "shared"
}
}
return originalUserId
} }

View File

@ -1,79 +0,0 @@
const { __glob } = require("../modules/global-variables");
const { LogType } = require("loguix");
var { List } = require("./sub-list")
const discord = require("./discord-bot")
const subplayer = require("./sub-player")
const fs = require("fs");
const { type } = require("os");
var radios = []
const plog = new LogType("Radio-Manager")
checkRadioFile()
module.exports.get = function () {
checkRadioFile()
return radios
}
module.exports.add = function (data) {
var radios_data = readRadioFile()
radios_data.push(data)
fs.writeFileSync(__glob.RADIO, JSON.stringify(radios_data, null, 2))
return radios
}
module.exports.remove = function(data) {
var radios_data = readRadioFile()
var radIndex = -1
for(var radio of radios_data) {
if(data.uri == radio.uri) {
radIndex = radios_data.indexOf(radio)
}
}
radios_data.splice(radIndex, 1)
saveRadioFile(radios_data)
}
function saveRadioFile(data) {
fs.writeFileSync(__glob.RADIO, JSON.stringify(data, null, 2))
}
function readRadioFile() {
if(fs.existsSync(__glob.RADIO)) {
return JSON.parse(fs.readFileSync(__glob.RADIO))
}
}
function checkRadioFile() {
if(fs.existsSync(__glob.RADIO)) {
radios = JSON.parse(fs.readFileSync(__glob.RADIO))
} else {
fs.writeFileSync(__glob.RADIO, JSON.stringify(radios, null, 2))
}
}

View File

@ -5,7 +5,7 @@ const auth = require("./sub-auth");
const cook = require("cookie") const cook = require("cookie")
const wlog = new LogType("Web") const wlog = new LogType("Web")
const subplayer = require('./sub-player'); const subplayer = require('./sub-player');
const subradio = require("./sub-radio.js")
const { List } = require("./sub-list") const { List } = require("./sub-list")
const subplaylist = require("./sub-playlist") const subplaylist = require("./sub-playlist")
const nodesfinder = require("./nodes-finder") const nodesfinder = require("./nodes-finder")
@ -13,6 +13,14 @@ const { Server } = require("socket.io")
var fs = require("fs") var fs = require("fs")
var path = require("path") var path = require("path")
const { Metric } = require("webmetrik"); const { Metric } = require("webmetrik");
const markdownit = require("markdown-it")({
html: true,
linkify: true,
typographer: true
})
const Genius = require("genius-lyrics");
const GClient = new Genius.Client("OHOV9c0B4uuyfWTK2w2YRliC9iyPjjF2Kk6ijCtZ2RtqfkZ2JpntnO2fwraF1A5h");
module.exports.WebServer = class { module.exports.WebServer = class {
@ -170,20 +178,18 @@ function IOConnection(io) {
}) })
process.on("UPDATE_RADIO", () => { process.on("PLAYLIST_REFRESH", () => {
if(io) { if(io) {
AlwaysRequest("PLAYLIST_REFRESH", "OK")
const radioList = subradio.get() }
AlwaysRequest("ALL_RADIO", radioList)
}
}) })
process.on("MUSIC_UPDATE_STATE", () => { process.on("MUSIC_UPDATE_STATE", () => {
if(io) { if(io) {
const data = subplayer.updateMusicState() const data = subplayer.updateMusicState()
AlwaysRequest("MUSIC_STATE", data) AlwaysRequest("MUSIC_STATE", data)
} }
}) })
@ -201,7 +207,12 @@ function IOConnection(io) {
const online_users_data = auth.getSimpleUser(token) const online_users_data = auth.getSimpleUser(token)
if(online_users_data) { if(online_users_data) {
usersOnline.push(online_users_data) // Check if user is already connected and if not push it
if(!usersOnline.find(item => item.username == online_users_data.username)) {
usersOnline.push(online_users_data)
}
alog.log(online_users_data.username + " - Connexion du serveur avec le socket : " + socket.id + " - " + socket.handshake.address + " - " + socket.handshake.headers["user-agent"]) alog.log(online_users_data.username + " - Connexion du serveur avec le socket : " + socket.id + " - " + socket.handshake.address + " - " + socket.handshake.headers["user-agent"])
} }
@ -271,15 +282,7 @@ function IOConnection(io) {
GetRequest("DISCONNECT", () => { GetRequest("DISCONNECT", () => {
subplayer.leave() subplayer.leave()
GetAnswer("DISCONNECT", "OK") GetAnswer("DISCONNECT", "OK")
sendUserNotification("à déconnecté le Bot de son salon vocal !")
})
GetRequest("RESTART", () => {
const pm2 = require('pm2');
pm2.restart('SubSonics - Bot Discord')
sendUserNotification("à redémarré le Bot !")
GetAnswer("RESTART", "OK")
}) })
GetRequest("NODES", () => { GetRequest("NODES", () => {
@ -292,11 +295,26 @@ function IOConnection(io) {
AlwaysRequest("ALL_CONNECTED_USER", usersOnline) AlwaysRequest("ALL_CONNECTED_USER", usersOnline)
}) })
GetRequest("ALL_RADIO", async () => { GetRequest("README", () => {
GetAnswer("ALL_RADIO", "OK") var content = markdownit.render(fs.readFileSync(__glob.README).toString())
AlwaysRequest("ALL_RADIO", await subradio.get()) GetAnswer("README", content)
}) })
GetRequest("OOBE_CHECK", () => {
GetAnswer("OOBE_CHECK", auth.getOOBE(user.user.id))
})
GetRequest("OOBE_VALID", () => {
auth.setOOBE(user.user.id)
GetAnswer("OOBE_VALID", "OK")
})
GetRequest("MOVEOUT", () => {
subplayer.moveOut(user.user.id)
GetAnswer("MOVEOUT", "OK")
})
PostRequest("SEEK", (data) => { PostRequest("SEEK", (data) => {
subplayer.seek(data) subplayer.seek(data)
@ -308,12 +326,34 @@ function IOConnection(io) {
PostAnswer("VOLUME", "OK") PostAnswer("VOLUME", "OK")
}) })
PostRequest("PLAY_QUEUE", (data) => {
var sublist = new List()
subplayer.addSong(sublist.playQueue(data), user.user.id, true)
PostAnswer("PLAY_QUEUE", "OK")
})
PostRequest("CHANGE_QUEUE", (data) => {
var sublist = new List()
sublist.changeQueue(data)
PostAnswer("CHANGE_QUEUE", "OK")
})
PostRequest("DELETE_QUEUE", (data) => { PostRequest("DELETE_QUEUE", (data) => {
var sublist = new List() var sublist = new List()
sublist.removeByIndex(data) sublist.removeByIndex(data)
PostAnswer("DELETE_QUEUE", "OK") PostAnswer("DELETE_QUEUE", "OK")
sendUserNotification("à supprimé un titre de la file d'attente !")
})
PostRequest("DELETE_ALL_QUEUE", () => {
var sublist = new List()
sublist.removeAll()
PostAnswer("DELETE_QUEUE", "OK")
}) })
PostRequest("MOVE_QUEUE", (data) => { PostRequest("MOVE_QUEUE", (data) => {
@ -321,7 +361,7 @@ function IOConnection(io) {
sublist.moveUp(data) sublist.moveUp(data)
PostAnswer("MOVE_QUEUE", "OK") PostAnswer("MOVE_QUEUE", "OK")
sendUserNotification("à déplacé un titre de la file d'attente !")
}) })
PostRequest("MOVE_QUEUE_BY_ENTIRE", (data) => { PostRequest("MOVE_QUEUE_BY_ENTIRE", (data) => {
@ -329,7 +369,7 @@ function IOConnection(io) {
sublist.replaceList(data) sublist.replaceList(data)
PostAnswer("MOVE_QUEUE_BY_ENTIRE", "OK") PostAnswer("MOVE_QUEUE_BY_ENTIRE", "OK")
sendUserNotification("à déplacé un titre tout au début de la file d'attente : <strong>" + data.title + "</strong> !")
}) })
PostRequest("REPORT", (data) => { PostRequest("REPORT", (data) => {
@ -337,7 +377,7 @@ function IOConnection(io) {
data.username = user data.username = user
subplayer.report(null, null, data) subplayer.report(null, null, data)
PostAnswer("REPORT", "OK") PostAnswer("REPORT", "OK")
sendUserNotification("à signalé un bug et a été envoyé !")
}) })
PostRequest("SEARCH", async (data) => { PostRequest("SEARCH", async (data) => {
@ -348,38 +388,46 @@ function IOConnection(io) {
PostRequest("ADD_SONG", async (data) => { PostRequest("ADD_SONG", async (data) => {
subplayer.addSong(data, user.user.id) subplayer.addSong(data, user.user.id)
PostAnswer("ADD_SONG", "OK") PostAnswer("ADD_SONG", "OK")
sendUserNotification("à ajouté un titre à la file d'attente : <strong>" + data.title + "</strong> !")
playStats(user.user.username) playStats(user.user.username)
}) })
PostRequest("ADD_SONG_NOW", async (data) => { PostRequest("ADD_SONG_NOW", async (data) => {
subplayer.addSong(data, user.user.id, true) subplayer.addSong(data, user.user.id, true)
PostAnswer("ADD_SONG_NOW", "OK") PostAnswer("ADD_SONG_NOW", "OK")
sendUserNotification("à lancé un titre : <strong>" + data.title + "</strong> !")
playStats(user.user.username) playStats(user.user.username)
}) })
PostRequest("FP_ADD_SONG", async (data) => { PostRequest("FP_ADD_SONG", async (data) => {
subplayer.addSong(data, user.user.id, false, true) subplayer.addSong(data, user.user.id, false, true)
PostAnswer("FP_ADD_SONG", "OK") PostAnswer("FP_ADD_SONG", "OK")
sendUserNotification("à ajouté un titre à la file d'attente : <strong>" + data.title + "</strong> !")
playStats(user.user.username) playStats(user.user.username)
}) })
PostRequest("FP_ADD_SONG_NOW", async (data) => { PostRequest("FP_ADD_SONG_NOW", async (data) => {
subplayer.addSong(data, user.user.id, true, true) subplayer.addSong(data, user.user.id, true, true)
PostAnswer("FP_ADD_SONG_NOW", "OK") PostAnswer("FP_ADD_SONG_NOW", "OK")
sendUserNotification("à lancé une titre : <strong>" + data.title + "</strong> !")
playStats(user.user.username) playStats(user.user.username)
}) })
PostRequest("PLAY_PLAYLIST", async (data) => { PostRequest("PLAY_PLAYLIST", async (data) => {
subplaylist.playPlaylist(user.user.id, data) subplaylist.playPlaylist(user.user.id, data)
PostAnswer("PLAY_PLAYLIST", "OK") PostAnswer("PLAY_PLAYLIST", "OK")
sendUserNotification("à ajouté une playlist à la file d'attente !")
playStats(user.user.username) playStats(user.user.username)
}) })
PostRequest("PLAY_PLAYLIST_NOW", async (data) => {
subplaylist.playPlaylist(user.user.id, data, true)
PostAnswer("PLAY_PLAYLIST_NOW", "OK")
playStats(user.user.username)
})
PostRequest("CREATE_PLAYLIST", async (data) => { PostRequest("CREATE_PLAYLIST", async (data) => {
subplaylist.addPlaylist(user.user.id, data) subplaylist.addPlaylist(user.user.id, data)
socket.emit("DO_UPDATE_PLAYLIST") socket.emit("DO_UPDATE_PLAYLIST")
@ -393,31 +441,70 @@ function IOConnection(io) {
PostAnswer("DELETE_PLAYLIST", "OK") PostAnswer("DELETE_PLAYLIST", "OK")
}) })
PostRequest("FP_PLAY_PLAYLIST", async (data) => {
subplayer.addSongsFromPlaylist(data, user.user.id)
PostAnswer("FP_PLAY_PLAYLIST", "OK")
sendUserNotification("à ajouté une playlist à la file d'attente !")
})
PostRequest("SEND_PLAYLIST", async (data) => { PostRequest("SEND_PLAYLIST", async (data) => {
subplaylist.copyPlaylist(user.user.id, data.key, data.dest) subplaylist.copyPlaylist(user.user.id, data.key, data.dest)
socket.emit("DO_UPDATE_PLAYLIST") socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("SEND_PLAYLIST", "OK") PostAnswer("SEND_PLAYLIST", "OK")
}) })
PostRequest("RENAME_PLAYLIST", async (data) => {
subplaylist.renamePlaylist(user.user.id, data.id, data.name)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("RENAME_PLAYLIST", "OK")
})
PostRequest("ADD_SONG_TO_PLAYLIST", async (data) => { PostRequest("ADD_SONG_TO_PLAYLIST", async (data) => {
subplaylist.addSong(user.user.id, data.data, data.song) subplaylist.addSong(user.user.id, data.id, data.url)
socket.emit("DO_UPDATE_PLAYLIST") socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("ADD_SONG_TO_PLAYLIST", "OK") PostAnswer("ADD_SONG_TO_PLAYLIST", "OK")
}) })
PostRequest("DELETE_SONG_TO_PLAYLIST", async (data) => { PostRequest("DELETE_SONG_TO_PLAYLIST", async (data) => {
subplaylist.removeSong(user.user.id, data.data, data.song) subplaylist.removeSong(user.user.id, data.id, data.identifier)
socket.emit("DO_UPDATE_PLAYLIST") socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("DELETE_SONG_TO_PLAYLIST", "OK") PostAnswer("DELETE_SONG_TO_PLAYLIST", "OK")
}) })
PostRequest("FP_PLAY_PLAYLIST", async (data) => {
subplayer.addSongsFromPlaylist(data, user.user.id)
PostAnswer("FP_PLAY_PLAYLIST", "OK")
})
PostRequest("FP_PLAY_PLAYLIST_NOW", async (data) => {
subplayer.addSongsFromPlaylist(data, user.user.id, true)
PostAnswer("FP_PLAY_PLAYLIST", "OK")
})
PostRequest("LYRICS", async (data) => {
const searches = await GClient.songs.search(data);
if(!searches) {
PostAnswer("LYRICS", null)
return
}
const firstSong = searches[0];
if(!firstSong) {
PostAnswer("LYRICS", null)
return
}
const lyrics = await firstSong.lyrics();
if(!lyrics) {
PostAnswer("LYRICS", null)
return
}
PostAnswer("LYRICS", lyrics)
})
if(user.admin == true) { if(user.admin == true) {
GetRequest("LOGS", () => { GetRequest("LOGS", () => {
const logs_data = new Array() const logs_data = new Array()
@ -455,37 +542,6 @@ function IOConnection(io) {
}) })
PostRequest("RADIO/ADD", async (data) => {
const music_data = await (await subplayer.search(data)).results.tracks[0]
var radioContains = null
for(var title of subradio.get()) {
if(title.uri == music_data.uri) {
radioContains = true
}
}
if(!radioContains) {
subradio.add(music_data)
console.log("[Radio] - ADD : " + data)
} else {
subradio.remove(music_data)
console.log("[Radio] - REMOVE : " + data)
}
PostAnswer("RADIO/ADD", "OK")
process.emit("UPDATE_RADIO")
})
PostRequest("USERS/ADMIN", (data) => { PostRequest("USERS/ADMIN", (data) => {
auth.setAdmin(data) auth.setAdmin(data)
PostAnswer("USERS/ADMIN", "OK") PostAnswer("USERS/ADMIN", "OK")
@ -493,13 +549,29 @@ function IOConnection(io) {
AdminRequest("USERS", users_data) AdminRequest("USERS", users_data)
}) })
PostRequest("USERS/BAN", (data) => {
auth.setBan(data)
PostAnswer("USERS/BAN", "OK")
const users_data = auth.getUsers()
AdminRequest("USERS", users_data)
})
PostRequest("USERS/DELETE", (data) => { PostRequest("USERS/DELETE", (data) => {
auth.removeUser(data.token) auth.removeUser(data)
PostAnswer("USERS/DELETE", "OK") PostAnswer("USERS/DELETE", "OK")
const users_data = auth.getUsers() const users_data = auth.getUsers()
AdminRequest("USERS", users_data) AdminRequest("USERS", users_data)
}) })
GetRequest("RESTART", () => {
const pm2 = require('pm2');
pm2.restart('Subsonics')
GetAnswer("RESTART", "OK")
})
@ -538,10 +610,7 @@ function IOConnection(io) {
} }
function sendUserNotification(text) {
io.sockets.emit("NOTIFICATION", {"image_src": "https://cdn.discordapp.com/avatars/" + user.user.id + "/" + user.user.avatar, "text": user.user.global_name + " (" + user.user.username + ") " + text})
}
}) })
@ -562,10 +631,7 @@ function IOConnection(io) {
} }
function sendNotification(image_src, text) {
io.sockets.emit("NOTIFICATION", {"image_src": image_src, "text": text})
}
function playStats(username) { function playStats(username) {
var userMusicPlayed = new Metric("userMusicPlayed_" + username, "Nombre de musiques jouées par l'utilisateur : " + username) var userMusicPlayed = new Metric("userMusicPlayed_" + username, "Nombre de musiques jouées par l'utilisateur : " + username)

View File

@ -1,3 +0,0 @@
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="black" />
</svg>

Before

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

View File

@ -0,0 +1,4 @@
<svg width="264" height="613" viewBox="0 0 264 613" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M149.792 64.8C149.792 136.7 149.692 138.2 143.192 159.8C136.892 180.4 126.292 201.3 111.892 220.8C108.092 225.9 95.092 241.2 82.992 254.8C57.192 283.7 48.492 294.3 37.892 310C15.692 342.8 4.19203 372.8 0.692033 407.7C-4.90797 462.7 23.892 519 72.092 547.2C78.492 550.9 91.392 556.7 97.592 558.5L99.792 559.1V467.8C99.792 371.2 99.992 366.3 104.692 346.9C110.792 321.2 123.292 297.9 145.492 270.7C160.592 252.1 177.992 228.7 184.692 217.9C206.792 182.3 217.892 147 216.492 116.6C215.592 95.9 210.792 77.8 201.292 58.5C193.392 42.7 184.792 30.5 173.092 18.7C165.292 10.9 152.092 8.91089e-06 150.392 8.91089e-06C150.092 8.91089e-06 149.792 29.2 149.792 64.8Z" fill="white"/>
<path d="M133.792 456.9V613H137.592C139.592 613 141.892 612.6 142.592 612.2C143.592 611.5 143.792 589.5 143.592 504.2C143.292 417.2 143.492 397 144.592 397C149.792 397 160.292 406 164.292 414.1C169.592 424.4 169.792 427.3 169.792 495.2C169.792 547.3 169.992 558 171.192 558C171.892 558 178.292 555.1 185.392 551.5C226.692 530.8 254.692 494.2 262.292 451C264.292 439.9 264.592 417.6 262.892 407.9C259.692 389 250.792 367.9 239.692 352.9C216.892 322.2 183.292 304.2 143.592 301.4L133.792 300.7V456.9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-5.6112" y1="-3.8605" x2="209.7163" y2="212.1815">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.2662" style="stop-color:#9B9B9A"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<rect x="-12.202" y="-9.773" style="fill:url(#SVGID_1_);stroke:#000000;stroke-miterlimit:10;" width="222.626" height="221.963"/>
</g>
<g>
<polygon style="fill:#FFFFFF;" points="153.605,27.568 66.499,59.327 66.498,49.578 149.843,19.207 153.6,17.838 "/>
<g>
<ellipse transform="matrix(0.938 -0.3466 0.3466 0.938 -34.4075 53.653)" style="fill:#FFFFFF;" cx="132.775" cy="123.007" rx="21.27" ry="17.78"/>
<rect x="150.06" y="19.307" style="fill:#FFFFFF;" width="3.524" height="102.982"/>
</g>
<ellipse transform="matrix(0.938 -0.3466 0.3466 0.938 -50.0962 26.5542)" style="fill:#FFFFFF;" cx="49.18" cy="153.313" rx="21.27" ry="17.78"/>
<rect x="66.465" y="49.613" style="fill:#FFFFFF;" width="3.524" height="102.982"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="31" height="23" viewBox="0 0 31 23" fill="#FF3232">
<path d="M30.549 12.5128L20.5485 22.5133C19.6556 23.4062 18.1079 22.7811 18.1079 21.5013V15.7867H10.0122C9.22054 15.7867 8.5836 15.1498 8.5836 14.3581V8.64352C8.5836 7.85182 9.22054 7.21488 10.0122 7.21488H18.1079V1.50031C18.1079 0.22644 19.6496 -0.404544 20.5485 0.488357L30.549 10.4889C31.1026 11.0484 31.1026 11.9532 30.549 12.5128ZM12.3933 22.2156V19.8346C12.3933 19.4417 12.0719 19.1202 11.679 19.1202H6.67874C5.62513 19.1202 4.77389 18.269 4.77389 17.2154V5.78624C4.77389 4.73262 5.62513 3.88138 6.67874 3.88138H11.679C12.0719 3.88138 12.3933 3.55994 12.3933 3.16706V0.785991C12.3933 0.393115 12.0719 0.0716701 11.679 0.0716701H6.67874C3.52385 0.0716701 0.964172 2.63132 0.964172 5.78624V17.2154C0.964172 20.3703 3.52385 22.9299 6.67874 22.9299H11.679C12.0719 22.9299 12.3933 22.6085 12.3933 22.2156Z" fill="#FF3232"/>
</svg>

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -34,11 +34,11 @@ function get(request) {
} }
function post(request, data, secondata, thirddata) { function post(request, data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
socket.emit("POST/" + request, data, secondata, thirddata) socket.emit("POST/" + request, data)
console.log("Envoi de la requête POST : " + request) console.log("Envoi de la requête POST : " + request)
socket.once("ANSWER/POST/" + request, (answer) => { socket.once("ANSWER/POST/" + request, (answer) => {

View File

@ -1,16 +1,41 @@
/**
* @param {string} id
* @returns element
*/
function getID(id) { function getID(id) {
return document.getElementById(id); return document.getElementById(id);
} }
// Get The position of the mouse function getTimeCode(duration) {
var max = ""
const maxhours = Math.floor(duration / 3600000);
var maxmin = Math.trunc(duration / 60000) - (Math.floor(duration / 60000 / 60) * 60);
var maxsec = Math.floor(duration / 1000) - (Math.floor(duration / 1000 / 60) * 60);
if (maxsec < 10) {
maxsec = `0${maxsec}`;
}
if(maxhours != 0) {
if (maxmin < 10) {
maxmin = `0${maxmin}`;
}
max = maxhours + ":" + maxmin + ":" + maxsec
} else {
max = maxmin + ":" + maxsec
}
return max
}
var xMousePos = 0; var xMousePos = 0;
var yMousePos = 0; var yMousePos = 0;
document.onmousemove = function(e) document.onmousemove = function(e)
{ {
xMousePos = e.clientX + window.scrollX; xMousePos = e.clientX + window.scrollX;
@ -18,170 +43,378 @@ document.onmousemove = function(e)
} }
function disableDrag() {
// Ajoutez un gestionnaire d'événement pour l'événement dragover
document.addEventListener('dragover', function (e) {
e.preventDefault(); // Empêche le comportement par défaut du navigateur
});
// Ajoutez un gestionnaire d'événement pour l'événement drop class User {
document.addEventListener('drop', function (e) { constructor(properties) {
e.preventDefault(); // Empêche le comportement par défaut du navigateur this.userImg = properties.picture
}); this.userName = properties.name
} this.userId = properties.id
// Pour réactiver le drag-and-drop, vous pouvez supprimer les gestionnaires d'événements
function enableDrag() {
// Supprimez le gestionnaire d'événement pour l'événement dragover
document.removeEventListener('dragover', function (e) {
e.preventDefault(); // Empêche le comportement par défaut du navigateur
});
// Supprimez le gestionnaire d'événement pour l'événement drop
document.removeEventListener('drop', function (e) {
e.preventDefault(); // Empêche le comportement par défaut du navigateur
});
}
function startInterval() {
interval = setInterval(() => {
if(isPlaying == true) {
setTime()
}
}, 1000)
}
function stopInterval() {
clearInterval(interval);
}
function setTime() {
durationBar.max = durationAll
durationProgress += 1000
durationBar.value = durationProgress
const maxhours = Math.floor(durationAll / 3600000);
const nowhours = Math.floor(durationProgress / 3600000);
var maxmin = Math.trunc(durationAll / 60000) - (Math.floor(durationAll / 60000 / 60) * 60);
var maxsec = Math.floor(durationAll / 1000) - (Math.floor(durationAll / 1000 / 60) * 60);
var nowmin = Math.trunc(durationProgress / 60000) - (Math.floor(durationProgress / 60000 / 60) * 60);
var nowsec = Math.floor(durationProgress / 1000) - (Math.floor(durationProgress / 1000 / 60) * 60);
console.log(durationAll)
console.log(durationProgress)
console.log("---------------------")
var now = ""
var max = ""
if (maxmin < 10) {
maxmin = `0${maxmin}`;
}
if (nowmin < 10) {
nowmin = `0${nowmin}`;
}
if (maxsec < 10) {
maxsec = `0${maxsec}`;
}
if (nowsec < 10) {
nowsec = `0${nowsec}`;
}
if(maxhours != 0) {
max = maxhours + ":" + maxmin + ":" + maxsec
} else {
max = maxmin + ":" + maxsec
}
if(nowhours != 0) {
now = nowhours + ":" + nowmin + ":" + nowsec
} else {
now = nowmin + ":" + nowsec
}
durationTextAct.innerHTML = now
durationTextTotal.innerHTML = max
}
function getTimeCode(pdurationAll) {
var pmax = ""
const pmaxhours = Math.floor(pdurationAll / 3600000);
var pmaxmin = Math.trunc(pdurationAll / 60000) - (Math.floor(pdurationAll / 60000 / 60) * 60);
var pmaxsec = Math.floor(pdurationAll / 1000) - (Math.floor(pdurationAll / 1000 / 60) * 60);
if (pmaxsec < 10) {
pmaxsec = `0${pmaxsec}`;
}
if(pmaxhours != 0) {
if (pmaxmin < 10) {
pmaxmin = `0${pmaxmin}`;
}
pmax = pmaxhours + ":" + pmaxmin + ":" + pmaxsec
} else {
pmax = pmaxmin + ":" + pmaxsec
} }
return pmax
generateHTML() {
return `<div class="ousercard_div">
<img id="ouser-img" class="ousercard_image" src="${this.userImg}"></img>
<div class="usercard_text">
<p id="ouser-name" class="ousercard_text_name">${this.userName}</p>
<p id="ouser-id" class="ousercard_text_id">${this.userId}</p>
</div>
</div>`
}
} }
function loadHome() { var ActualDroppableMenu = null
userLocation = "home" class DroppableMenu {
options = new Array()
mainView.innerHTML = WelcomeContent id = null
DMSpanInteger = null
get("ALL_CONNECTED_USER")
get("ALL_RADIO")
constructor() {
this.id = Math.random().toString(36).substring(7)
}
add(action, string) {
this.options.push("<div id='" + this.id + "_" + action + "' class='dm-element'>" + string + "</div>")
}
show() {
console.log("DROPPABLE MENU - " + this.id)
if(ActualDroppableMenu) {
ActualDroppableMenu.hide()
}
ActualDroppableMenu = this
if(xMousePos && yMousePos) {
this.DMSpanInteger = document.createElement("span")
this.DMSpanInteger.id = "dm-" + this.id
this.DMSpanInteger.className = "dm-span"
document.body.appendChild(this.DMSpanInteger);
this.DMSpanInteger.innerHTML = this.options.join('')
const menu = getID(`dm-${this.id}`)
menu.style.position = "absolute"
menu.style.left = (xMousePos - 100) + "px"
menu.style.top = (yMousePos - 40) + "px"
menu.addEventListener("mouseleave", () => {
this.hide()
})
menu.addEventListener("click", () => {
this.hide()
})
}
}
get(action) {
return getID(this.id + "_" + action)
}
hide() {
const menu = getID(`dm-${this.id}`)
if(menu) {
menu.outerHTML = ""
console.log("HIDED")
}
}
}
class ModalComponent {
Element;
constructor(properties) {
this.title = properties.title
this.content = properties.content
this.closable = true
if(properties.closable != null) {
this.closable = properties.closable
}
if(properties.width) {
this.width = properties.width
} else {
this.width = "50%"
}
}
show() {
var closableDiv = "<span id='modal-close'>&times;</span>"
if(this.closable == false) {
closableDiv = ""
}
this.Element = document.createElement("div")
this.Element.className = "modal"
this.Element.id = this.id
this.Element.innerHTML = `<div id='modal-content' class="modal-content">
<div class="modal-header">
<h2>${this.title}</h2>
${closableDiv}
</div>
<div class="modal-body">
${this.content}
</div>
</div>`
document.body.appendChild(this.Element)
this.Element.style.display = "flex"
// Edit the width of modal content
const modalContent = getID("modal-content")
modalContent.style.width = this.width
if(this.closable) {
const close = getID("modal-close")
close.addEventListener("click", () => {
this.hide()
})
}
}
hide() {
this.Element.outerHTML = ""
}
setContent(content) {
this.content = content
}
}
class VideoComponent {
constructor(data, playlist) {
if(playlist) {
this.onPlaylist = true
this.title = data.title
this.author = data.author.name
this.thumbnail = data.thumbnail_url
this.url = data.url
this.duration = data.milis_length
this.identifier = data.id
this.type = data.type
this.self = data
} else {
this.onPlaylist = false
this.title = data.title
this.author = data.author
this.thumbnail = data.thumbnail
this.url = data.uri
this.duration = data.duration
this.identifier = data.identifier
this.type = data.type
this.self = data
}
}
generateHTML(playlist, onYoutube) {
var actions = ``
var timecode = null
if(this.duration == 9223372036854776000) {
timecode = "<i class='red fa-solid fa-circle'></i> LIVE"
} else {
timecode = getTimeCode(this.duration)
}
if(playlist) {
actions = `
<span id="${this.identifier}_search_add" class="search-circle"><i class="fa fa-add"></i></span>
<span id="${this.identifier}_search_play" class="search-circle"><i class="fa fa-play"></i></span>
${!onYoutube ? `<span id="${this.identifier}_search_padd" class="search-circle"><i class="fa fa-trash"></i></span>` : ""}
`
} else {
actions = `<span id="${this.identifier}_search_add" class="search-circle"><i class="fa fa-add"></i></span>
<span id="${this.identifier}_search_play" class="search-circle"><i class="fa fa-play"></i></span>
<span id="${this.identifier}_search_padd" class="search-circle"><i class="fa fa-save"></i></span>`
}
return ` <div class="search-list-item" id="${this.identifier}_search">
<div id="${this.identifier}_search_image" class="search-list-item-image">
<span class="search-action">
${actions}
</span>
<p class='search-time-code'>${timecode}</p>
</div>
<div class="search-list-item-text">
<p class="search-list-item-text-title">${this.title}</p>
<p class="search-list-item-text-channel">${this.author}</p>
</div>
</div>`
}
loadScript(fromPlaylist, onYoutube) {
const image = getID(`${this.identifier}_search_image`)
image.style.backgroundImage = `url(${this.thumbnail})`
const play = getID(`${this.identifier}_search_play`)
const add = getID(`${this.identifier}_search_add`)
const padd = getID(`${this.identifier}_search_padd`)
add.addEventListener("click", () => {
const action = this.onPlaylist ? "FP_ADD_SONG" : "ADD_SONG";
post(action, this.onPlaylist ? this.url : this.self);
});
play.addEventListener("click", () => {
const action = this.onPlaylist ? "FP_ADD_SONG_NOW" : "ADD_SONG_NOW";
post(action, this.onPlaylist ? this.url : this.self);
});
if(!fromPlaylist) {
padd.addEventListener("click", () => {
saveToPlaylist(this.url)
})
} else {
if(onYoutube) {
padd.addEventListener("click", () => {
post("DELETE_SONG_TO_PLAYLIST", {"id": playlistId, "identifier": this.identifier})
})
}
}
}
loadPlaylist() {
const image = getID(`${this.identifier}_search_image`)
image.style.backgroundImage = `url(${this.thumbnail})`
}
}
var playlistId = null
const viewEdit = getID("view-edit")
function loadView(content) {
viewEdit.innerHTML = content
}
const tileList = new Array()
function setTileActive(tile) {
playlistId = null
// add only the 'invert' class to the selected tile by the id
tileList.forEach((element) => {
if(element) {
element.classList.remove("invert")
}
})
if(tile) {
getID(tile).classList.add("invert")
}
}
function loading(returnable) {
if(returnable) {
return `<p class='loading'><i class="fa-solid fa-rotate fa-spin"></i> Chargement en cours ... </p>`
} else {
loadView(`
<p class='loading'><i class="fa-solid fa-rotate fa-spin"></i> Chargement en cours ... </p>
`)
}
} }
const buttons = document.querySelectorAll(".sside_line"); function saveToPlaylist(url) {
get("PLAYLIST").then((res) => {
var allPlaylistOptions = new Array()
for(var playlist in res) {
var indicator = "[Privée] "
buttons.forEach(button => { if(res[playlist].source == "shared") {
button.addEventListener("click", function () { indicator = "[Partagée] "
buttons.forEach(btn => { }
if (btn === button) {
btn.style.color = "white"; if(res[playlist].source != "youtube") {
} else { allPlaylistOptions.push(`<option value="${playlist}">${indicator}${res[playlist].title}</option>`)
btn.style.color = ""; }
}
});
});
}); }
if(allPlaylistOptions.length == 0) {
//Make a modal named "Error" with close button and a message
const modalError = new ModalComponent({"title": "<i style='transform: scale(0.8);' class='fa fa-warning'></i> Erreur", width: "20%"})
modalError.setContent(`<div class="modal-form">
<p>Vous n'avez aucune playlist pour ajouter cette musique</p>
</div>`)
modalError.show()
} else {
const modal = new ModalComponent({"title": "<i style='transform: scale(0.8);' class='fa fa-music'></i> Ajouter à la playlist", width: "20%"})
modal.setContent(`
<div class="modal-form">
<select id="playlist-id">
${allPlaylistOptions.join("")}
</select>
<button id="playlist-add-confirm">Envoyer</button>
</div>
`)
modal.show()
const confirm = getID("playlist-add-confirm")
const playlistId = getID("playlist-id")
confirm.addEventListener("click", () => {
post("ADD_SONG_TO_PLAYLIST", {"id": playlistId.value, "url": url})
modal.hide()
})
}
})
}

View File

@ -0,0 +1,43 @@
const userImg = getID("user-img")
const userName = getID("user-name")
const userId = getID("user-id")
const website_list = document.getElementById("ousers-list")
const website_list_number = document.getElementById("ousers-number")
AlwaysRequest("UPDATE_SELF", () => {
initUser()
})
initUser()
function initUser() {
const userInfo = get("USER_INFO")
userInfo.then(user => {
userImg.src = user.picture
userId.innerHTML = user.user.username
userName.innerHTML = user.user.global_name
})
}
AlwaysRequest("ALL_CONNECTED_USER", (data) => {
const userToPush = new Array()
for(var user of data) {
const userC = new User({
picture: user.picture,
name: user.global_name,
id: user.username
})
userToPush.push(userC.generateHTML())
}
website_list.innerHTML = userToPush.join("")
website_list_number.innerHTML = userToPush.length
})

View File

@ -1,137 +0,0 @@
updateUsersPictures()
AlwaysRequest("UPDATE_SELF", () => {
updateUsersPictures()
})
function updateUsersPictures() {
const userInfo = get("USER_INFO")
userInfo.then(user => {
settingsBtn.style.display = "none"
if(user.admin == true) {
settingsBtn.style.display = "flex"
userAdmin = true
}
userInfoDiv.innerHTML = "<div class='INDEX_userInfo_name'><p class='INDEX_gbname'>" + user.user.global_name + "</p><p class='INDEX_usrname'>" + user.user.username + "</p></div><div class='INDEX_picture'><img src='" + user.picture +"'>" + "</div>"
})
}
userInfoDiv.addEventListener("click", () => {
if(userInfoPopup.classList.contains("invisible")) {
userInfoPopup.classList.remove("invisible")
userInfoPopup.style.left = (xMousePos - 110) + "px"
userInfoPopup.style.top = yMousePos + "px"
}
})
userInfoPopup.classList.add("invisible")
userInfoPopup.addEventListener("mouseleave", () => {
userInfoPopup.classList.add("invisible")
})
// Load users connected
AlwaysRequest("ALL_CONNECTED_USER", (data) => {
if(userLocation == "home") {
const website_list = document.getElementById("website_list")
const userToPush = new Array()
userToPush.push("<p style=' padding-bottom: 1%; font-family: Gunship, sans-serif;'><i class='fa fa-users'></i> Utilisateurs connecté(es)</p>")
for(var user of data) {
userToPush.push(`<div style=' padding-bottom: 2%; padding-top: 1%;' class="set_user_info"><img style='margin-right: 3%;' src="${user.picture}"><div style="display: flex; flex-direction: column; justify-content: center;"><p class="INDEX_gbname">${user.global_name}</p><p class="INDEX_usrname">${user.username}</p></div></div>`)
}
website_list.innerHTML = userToPush.join("")
}
})
var timeoutId = null
socket.on("NOTIFICATION", (data) => {
if(timeoutId) {
clearTimeout(timeoutId)
}
const notifDiv = document.getElementById("notif")
const notif_image = document.getElementById("notif_image")
const notif_text = document.getElementById("notif_text")
notif_image.src = data.image_src
notif_text.innerHTML = data.text
notifDiv.classList.add("notif_div_on")
timeoutId = setTimeout(() => {
notifDiv.classList.remove("notif_div_on")
}, 4000)
notifDiv.addEventListener("click", () => {
if(timeoutId) {
clearTimeout(timeoutId)
}
notifDiv.classList.remove("notif_div_on")
})
})
// Window Selector
homeBtn.style.color = "white"
homeBtn.addEventListener("click", () => {
loadHome()
})
// Restart
restartBtn.addEventListener("click", () => {
get("RESTART")
})
// Start Operation
loadHome()

View File

@ -1,68 +0,0 @@
const userInfoDiv = getID("userInfo")
const userInfoPopup = getID("userPopup")
const userInfoglobal = getID("userInfoglobal")
const musicTitle = getID("music_title")
const musicURL = getID("music_img")
const durationBar = getID("duration")
const durationTextAct = getID("durationTextAct")
const durationTextTotal = getID("durationTextTotal")
const backward = getID("backward")
const play = getID("play")
const forward = getID("forward")
const settingsBtn = getID("settings_btn")
const loop = getID("loop")
const vol = getID("volbtn")
const shuffle = getID("shuffle")
const list = getID("list_btn")
const takeCurrent = getID("takeCurrent")
const volBox = getID("volumeBox")
const volTxt = getID("volumeTxt")
const volDiv = getID("volDiv")
const volRange = getID("volumeInput")
const listBox = getID("listBox")
const listNumber = getID("listNumber")
const disconnect = getID("disconnect")
const report_dialog = getID("report_dialog")
const report_close = getID("report_close")
const reportBtn = getID("reportBtn")
const report_level = getID("report_level")
const report_desc = getID("report_desc")
const report_send = getID("report_send")
const searchBtn = getID("search_btn")
const homeBtn = getID("home_btn")
const mainView = getID("mainView")
const restartBtn = getID("restartBtn")
const WelcomeContent = mainView.firstElementChild.outerHTML
const playlistContent = getID("playlist-content")
// Get the current location of the user
var userLocation = "home"
var userAdmin = false
// Player
var durationAll = 0
var durationProgress = 0
var isPlaying = false
let interval;
// Playlist
var playlistSelected = null
var playlistValue = null
var deleteJustBefore = null
var currentSong = null
var playlistAvailable = null

View File

@ -0,0 +1,594 @@
const cgu = `
<p>En utilisant ce site, vous consentez à l'utilisation de vos données fournis par Discord (c) afin d'assurer le bon fonctionnement de la plateforme. Vous avez la possibilité de demander la suppression de vos données à tout moment en contactant Raphix (raphixscrap). Tout acte intentionnel de dégradation du bot entraînera un bannissement du site.</p>
<br>
<p>Ce bot est destiné à un usage privé exclusivement et n'est pas conçu pour être utilisé par le grand public.</p>
<br>
<p>Toutes les musiques disponibles sur ce site sont hébergées sur les plateformes suivantes : Youtube, Soundcloud, Vimeo.</p>
<br>
<p>En utilisant Subsonics, vous bénéficiez du droit d'accès au service et de l'écoute du contenu. Cependant, veuillez noter que Raphix n'est pas tenu de fournir la provenance ni l'autorisation d'exploitation des musiques par les ayants droits. Il vous incombe donc d'obtenir les autorisations nécessaires des ayants droits pour écouter le contenu.</p>
<br>
<p>Les paroles fournies sur ce site sont obtenues auprès de Genius (c).</p>
<br>
<p>En utilisant Subsonics, vous acceptez de respecter les conditions d'utilisation de Genius (c) et de ne pas utiliser les paroles à des fins commerciales.</p>
<br>
<p>En utilisant Subsonics, vous acceptez de ne pas utiliser le bot pour diffuser des contenus illégaux, violents, haineux, discriminatoires, ou à caractère sexuel.</p>
<br>
<p>En utilisant Subsonics, vous acceptez de ne pas utiliser le bot pour diffuser des contenus à caractère politique, religieux, ou incitant à la haine.</p>
<br>
<p>En utilisant Subsonics, vous acceptez de ne pas utiliser le bot pour diffuser des contenus à caractère publicitaire ou pornographique.</p>
`
get("OOBE_CHECK").then((res) => {
if(res) {
loadOOBE()
}
})
function loadOOBE() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "50%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Bienvenue sur Subsonics Web</h3>
<p>Subsonics Web est un outil pour gérer le bot Discord Subsonics.</p>
<p>Vous pouvez créer des playlists, jouer de la musique, importer des playlists depuis YouTube, et bien plus encore.</p>
<p>Avant de commencer à utiliser Subsonics Web, vous devez accepter les conditions d'utilisation.</p>
<br>
<div class="oobe-cgu">
<h3>Conditions d'utilisation</h3>
<p>En utilisant Subsonics Web, vous acceptez de respecter les conditions d'utilisation suivantes :</p>
${cgu}
</div>
<br>
<div class="oobe-accept">
<button class="btn btn-primary" id='accept-oobe'>Accepter</button>
</div>
</div>
`)
modal.show()
document.getElementById("accept-oobe").addEventListener("click", () => {
modal.hide()
oobeStep2()
})
}
function oobeStep2() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "70%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Apprenons à utiliser Subsonics Web (1/4) - Player</h3>
<p>Le player est l'élément central de Subsonics Web. C'est ici que vous pourrez contrôler la musique que vous écoutez.</p>
<br>
<div class="player">
<div class="video">
<div class="video_image"></div>
<div class="video_title">
<span class="video_title_title"><p>Titre de la vidéo</p></span>
<span class="video_title_channel"><p>Nom de la chaine</p></span>
</div>
</div>
<div class="controller">
<div class="buttons">
<span class="wh"><i class="icon fa fa-shuffle"></i></span>
<span class="wh"><i class="icon fa fa-backward"></i></span>
<span class="playicon wh"><i class="fa fa-play icon"></i></span>
<span class="wh"><i class="icon fa fa-forward"></i></span>
<span class="wh"><i class="icon fa fa-sync-alt"></i></span>
</div>
<div class="durationBar">
<span class="time">-:--</span>
<input type="range" value="0" max="100">
<span class="time">-:--</span>
</div>
</div>
<div class="actionbar">
<div>
<span class="wh"><i class="fa fa-microphone-lines icon"></i></span>
<span class="wh"><i class="fa fa-phone-slash icon"></i></span>
<span class="wh"><i class="fa fa-hand icon"></i></span>
</div>
<div>
<span><i class="fa fa-volume-up"></i></span>
<span>100%</span>
<input class='volume-oobe' type="range" value="100" max="100">
</div>
</div>
</div>
<br>
<div class='oobe-line'>
<span class="oobe wh"><i class="fa fa-play icon"></i></span>
<p>Appuyez sur ce bouton mettre en pause ou reprendre la lecture de la musique.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-backward icon"></i></span>
<p>Appuyez sur ce bouton pour revenir au début de la musique actuelle.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-forward icon"></i></span>
<p>Appuyez sur ce bouton pour passer à la musique suivante.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-sync-alt icon"></i></span>
<p>Appuyez sur ce bouton pour activer ou désactiver la répétition de la musique actuelle.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-shuffle icon"></i></span>
<p>Appuyez sur ce bouton pour activer ou désactiver la lecture aléatoire des musiques.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-microphone-lines icon"></i></span>
<p>Appuyez sur ce bouton pour afficher les paroles - <span class='oobe-ctrl'>Ctrl + Click</span> Recherche n'importe quelles paroles sur Genius.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-phone-slash icon"></i></span>
<p>Appuyez sur ce bouton pour déconnecter le bot de votre salon vocal.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-hand icon"></i></span>
<p>Appuyez sur ce bouton pour déplacer le bot dans votre salon vocal.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-volume-up icon"></i></span>
<p>Utilisez ce curseur pour régler le volume de la musique.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh">-:--</span>
<p>Utilisez ce curseur pour régler la position de la musique.</p>
</div>
<br>
<div class="oobe-accept">
<button class="btn btn-primary" id='continue-oobe'>Continuer</button>
</div>
</div>
`)
modal.show()
document.getElementById("continue-oobe").addEventListener("click", () => {
modal.hide()
oobeStep3()
})
}
function oobeStep3() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "70%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Apprenons à utiliser Subsonics Web (2/4) - Liste de lecture</h3>
<p>La liste de lecture est l'endroit vous pouvez gérer les musiques que vous souhaitez écouter.</p>
<br>
<div class="oobe-list">
<div class="wintitle">
<p>Liste de lecture</p>
<i class="fa fa-list-ol"></i>
</div>
<div class="list-options">
<div class="list-selector">
<p class="selected">À suivre</p>
<p class="">Historique</p>
</div>
<span class="list-clear"><i class="fa fa-trash"></i></span>
</div>
<a href="" target="_blank"></a>
<div class="oobe-list-content">
<div class="list-video">
<div class="list-video-div">
<div class="list-video_image"><p class='oobe-list-time-code'>-:--</p></div>
<div class="list-video_title">
<span class="list-video_title_title"><p>Titre de la vidéo</p></span>
<span class="list-video_title_channel"><p>Nom de la chaine</p></span>
</div>
</div>
<span class="oobe-list-video-elipsis"><i class="fa-solid fa-ellipsis-vertical"></i></span>
</div>
<div class="list-video">
<div class="list-video-div">
<div class="list-video_image"><p class='oobe-list-time-code'>-:--</p></div>
<div class="list-video_title">
<span class="list-video_title_title"><p>Titre de la vidéo</p></span>
<span class="list-video_title_channel"><p>Nom de la chaine</p></span>
</div>
</div>
<span class="oobe-list-video-elipsis"><i class="fa-solid fa-ellipsis-vertical"></i></span>
</div>
</div>
</div>
<br>
<div class='oobe-line'>
<div class="list-selector">
<p class="selected">À suivre</p>
<p class="">Historique</p>
</div>
<p>Utilisez ces boutons pour changer de liste de lecture.</p>
</div>
<br>
<div class='oobe-line'>
<div style='width: unset;' class="list-video-div">
<div class="list-video_image"><p class='oobe-list-time-code'>-:--</p></div>
</div>
<p>Vous pouvez déplacer les titres dans l'ordre que vous le souhaitez en glissant et en déposant</p>
</div>
<br>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-trash"></i></span>
<p>Appuyez sur ce bouton pour vider la liste de lecture.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa-solid fa-ellipsis-vertical"></i></span>
<p>Appuyez sur ce bouton pour afficher les options de la musique. - <span class='oobe-ctrl'>Ctrl + Click</span> Permet de supprimer la musique de la liste de lecture.</p>
</div>
<br>
<div class="oobe-accept">
<button class="btn btn-primary" id='continue-oobe'>Continuer</button>
</div>
</div>
`)
modal.show()
document.getElementById("continue-oobe").addEventListener("click", () => {
modal.hide()
oobeStep4()
})
}
function oobeStep4() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "70%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Apprenons à utiliser Subsonics Web (3/4) - Playlist</h3>
<p>Les playlists sont un moyen pratique de regrouper vos musiques préférées. Elles peuvent provenir de Youtube, peuvent être privé comme partagé.</p>
<br>
<div class="oobe-playlist">
<div style='margin-bottom: 5px;' class="wintitle">
<p>Playlists</p>
<button><i class="fa fa-plus"></i> Ajouter une playlist</button>
<i class="fa fa-music"></i>
</div>
<div class="playlist-item">
<div class="playlist-item-tile">
<i class="fa fa-music"></i>
</div>
<p>Playlist Privé</p>
</div>
<div class="playlist-item">
<div class="playlist-item-tile">
<i class="fab fa-youtube"></i>
</div>
<p>Playlist importé depuis Youtube</p>
</div>
<div class="playlist-item">
<div class="playlist-item-tile">
<i class="fa fa-share-alt"></i>
</div>
<p>Playlist Partagé</p>
</div>
</div>
<br>
<div class="oobe-accept">
<button class="btn btn-primary" id='continue-oobe'>Continuer</button>
</div>
`)
modal.show()
document.getElementById("continue-oobe").addEventListener("click", () => {
modal.hide()
oobeStep4b()
})
}
function oobeStep4b() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "70%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Apprenons à utiliser Subsonics Web (3/4) - Playlist</h3>
<p>Les playlists sont un moyen pratique de regrouper vos musiques préférées. Elles peuvent provenir de Youtube, peuvent être privé comme partagé.</p>
<br>
<div class="oobe-playlist-div">
<div style='padding-bottom: 15px;' class='search-playlist'>
<div class='search-playlist-info'>
<div class='playlist-item-tile'>
<i class='fa fa-music'></i>
</div>
<div class='search-playlist-div'>
<p class='search-playlist-title'>Titre de la playlist <span><i class='search-playlist-rename fa fa-pen'></i></span></p>
<div>
<p class='search-playlist-desc'>-- titres </p>
</div>
</div>
</div>
<div class='search-playlist-actions'>
<span class='wh'><i class='fa fa-add'></i></span>
<span class='wh'><i class='fa fa-play'></i></span>
<span class='wh'><i class='fa fa-paper-plane'></i></span>
<span e' class='wh'><i class='fa fa-trash'></i></span>
</div>
</div>
<hr style='width: 100%;'>
<div style='padding-bottom: 15px;' class='search-playlist'>
<div class='search-playlist-info'>
<div class='oobe-image'>
</div>
<div class='search-playlist-div'>
<p class='search-playlist-title'>Titre d'une playlist Youtube <span id='pp-rename'><i class='search-playlist-rename fa fa-pen'></i></span></p>
<div>
<p class='search-playlist-desc'>-- titres - --- vues </p>
<p class='search-playlist-desc'> Description de la playlist</p>
</div>
<div class='search-playlist-author'>
<img class='search-playlist-author-img' src='https://cdn.discordapp.com/embed/avatars/0.png'>
<p class='search-playlist-author-name'>Nom de l'auteur de la playlist</p>
</div>
</div>
</div>
<div class='search-playlist-actions'>
<span class='wh'><i class='fa fa-add'></i></span>
<span class='wh'><i class='fa fa-play'></i></span>
<span class='wh'><i class='fa fa-paper-plane'></i></span>
<span class='wh'><i class='fa fa-trash'></i></span>
</div>
</div>
</div>
<br>
<div class='oobe-line'>
<div class='search-playlist-author'>
<img class='search-playlist-author-img' src='https://cdn.discordapp.com/embed/avatars/0.png'>
<p class='search-playlist-author-name'>Nom de l'auteur de la playlist</p>
</div>
<p>Cliquez dessus pour accéder à la chaine Youtube de l'auteur de la playlist.</p>
</div>
<br>
<div class='oobe-line'>
<div class='oobe-image-min'>
</div>
<p><span class='oobe-ctrl'>Ctrl + Click</span> pour copier le lien de la playlist</p>
</div>
<br>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-add"></i></span>
<p>Appuyez sur ce bouton pour ajouter la playlist à la liste de lecture.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-play"></i></span>
<p>Appuyez sur ce bouton pour lire directement la playlist.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-paper-plane"></i></span>
<p>Appuyez sur ce bouton pour partager la playlist.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-trash"></i></span>
<p>Appuyez sur ce bouton pour supprimer la playlist.</p>
</div>
<div class='oobe-line'>
<span class="oobe-wh"><i class="fa fa-pen"></i></span>
<p>Appuyez sur ce bouton pour renommer la playlist.</p>
</div>
<br>
<div class="oobe-accept">
<button class="btn btn-primary" id='continue-oobe'>Continuer</button>
</div>
`)
modal.show()
document.getElementById("continue-oobe").addEventListener("click", () => {
modal.hide()
oobeStep5()
})
}
function oobeStep5() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "70%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Apprenons à utiliser Subsonics Web (4/4) - Recherche</h3>
<p>La recherche est un outil puissant pour trouver des musiques depuis Vimeo, Soundcloud et Youtube. Vous pouvez aussi rechercher des playlists sur Youtube.</p>
<br>
<div class="oobe-search">
<div class="search-find">
<i class="fa fa-magnifying-glass"></i>
<input disabled autocomplete="off" type="text" placeholder="Insérez des mots-clés ou un lien">
</div>
<div class="oobe-search-list">
<div class="search-list-item">
<div class="search-list-item-image">
<span class="search-action">
<span class="search-circle"><i class="fa fa-add"></i></span>
<span class="search-circle"><i class="fa fa-play"></i></span>
<span class="search-circle"><i class="fa fa-save"></i></span>
</span>
<p class='search-time-code'>-:--</p>
</div>
<div class="search-list-item-text">
<p class="search-list-item-text-title">Titre de la vidéo</p>
<p class="search-list-item-text-channel">Nom de la chaine<p>
</div>
</div>
<div class="search-list-item">
<div class="search-list-item-image">
<span class="search-action">
<span class="search-circle"><i class="fa fa-add"></i></span>
<span class="search-circle"><i class="fa fa-play"></i></span>
<span class="search-circle"><i class="fa fa-save"></i></span>
</span>
<p class='search-time-code'>-:--</p>
</div>
<div class="search-list-item-text">
<p class="search-list-item-text-title">Titre de la vidéo</p>
<p class="search-list-item-text-channel">Nom de la chaine<p>
</div>
</div>
<div class="search-list-item">
<div class="search-list-item-image">
<span class="search-action">
<span class="search-circle"><i class="fa fa-add"></i></span>
<span class="search-circle"><i class="fa fa-play"></i></span>
<span class="search-circle"><i class="fa fa-save"></i></span>
</span>
<p class='search-time-code'>-:--</p>
</div>
<div class="search-list-item-text">
<p class="search-list-item-text-title">Titre de la vidéo</p>
<p class="search-list-item-text-channel">Nom de la chaine<p>
</div>
</div>
<div class="search-list-item">
<div class="search-list-item-image">
<span class="search-action">
<span class="search-circle"><i class="fa fa-add"></i></span>
<span class="search-circle"><i class="fa fa-play"></i></span>
<span class="search-circle"><i class="fa fa-save"></i></span>
</span>
<p class='search-time-code'>-:--</p>
</div>
<div class="search-list-item-text">
<p class="search-list-item-text-title">Titre de la vidéo</p>
<p class="search-list-item-text-channel">Nom de la chaine<p>
</div>
</div>
</div>
</div>
</div>
<br>
<div class='oobe-line'>
<div style='padding-bottom:0px !important;' class="search-find">
<i class="fa fa-magnifying-glass"></i>
<input disabled autocomplete="off" type="text" placeholder="Insérez des mots-clés ou un lien">
</div>
<p>Utilisez cette barre de recherche pour trouver des musiques sur Youtube, Soundcloud et Vimeo.</p>
</div>
<div class='oobe-line'>
<span class="search-circle"><i class="fa fa-add"></i></span>
<p>Appuyez sur ce bouton pour ajouter la musique à la liste de lecture.</p>
</div>
<div class='oobe-line'>
<span class="search-circle"><i class="fa fa-play"></i></span>
<p>Appuyez sur ce bouton pour lire directement la musique.</p>
</div>
<div class='oobe-line'>
<span class="search-circle"><i class="fa fa-save"></i></span>
<p>Appuyez sur ce bouton pour sauvegarder la musique dans une playlist.</p>
</div>
<br>
<div class="oobe-accept">
<button class="btn btn-primary" id='continue-oobe'>Continuer</button>
</div>
`)
modal.show()
document.getElementById("continue-oobe").addEventListener("click", () => {
modal.hide()
oobeStep6()
})
}
function oobeStep6() {
const modal = new ModalComponent({"title": "<div class='oobe-title gunship'><img class='oobe-logo' src='/images/logo-white.svg'> Bienvenue sur Subsonics WEB </div>" , "width": "70%", "closable": false})
modal.setContent(`
<div class="oobe-content">
<h3>Vous êtes prêt à utiliser Subsonics Web</h3>
<p>Vous avez maintenant appris les bases de Subsonics Web. Vous pouvez maintenant commencer à utiliser le site.</p>
<p>Mais avant de commencer, n'oubliez pas ces quelques conseils :</p>
<ul>
<li>Avant de commencer à lancez de la musique, assurez-vous que personne ne l'écoute déjà.</li>
<li>Si vous avez des questions, n'hésitez pas à demander à Raphix (raphixscrap) sur Discord.</li>
<li>Si vous rencontrez un bug ou que vous avez des suggestions, n'hésitez pas à le signaler en utilisant /report ou en utilisant le formulaire disponible dans Paramèters</li>
<li>Si vous avez des questions sur les commandes, n'hésitez pas à consulter l'aide disponible en faisant /help</li>
<li>Vérifiez que vous entrez des commandes dans le bon salon textuel (#bots).</li>
</ul>
<h3>Amusez-vous bien !</h3>
<div class="oobe-accept">
<button class="btn btn-primary" id='continue-oobe'>Terminer</button>
</div>
`)
modal.show()
document.getElementById("continue-oobe").addEventListener("click", () => {
modal.hide()
get("OOBE_VALID")
})
}

View File

@ -1,351 +1,224 @@
AlwaysRequest("MUSIC_STATE", async (data) => { const play = getID("play")
await disableDrag() const forward = getID("forward")
await enableDrag() const backward = getID("backward")
const loop = getID("loop")
const shuffle = getID("shuffle")
const durationBar = getID("duration")
const video_img = getID("video_img")
const video_title = getID("video_title")
const video_artist = getID("video_artist")
const time_act = getID("time_act")
const time_total = getID("time_total")
const volume = getID("volume")
const volIcon = getID("volIcon")
const volTxt = getID("volTxt")
const lyrics = getID("lyrics")
const disconnect = getID("disconnect")
const moveout = getID("moveout")
var durationAct = 0
var durationTotal = 0
// 4 States : PLAYING, PAUSED, CONNECTED, DISCONNECTED, LIVE
var interval = null
var currentTitle = ""
var playerState = "DISCONNECTED"
AlwaysRequest("MUSIC_STATE", async (data) => {
durationAct = 0
durationTotal = 0
playerState = "DISCONNECTED"
currentTitle = ""
stopInterval() stopInterval()
console.log(data) console.log(data)
durationAll = 0
durationProgress = 0
isPlaying = false
if(data.isOnline) { if(data.isOnline) {
vol.classList.remove("disabled") playerState = "CONNECTED"
forward.classList.remove("disabled")
backward.classList.remove("disabled")
loop.classList.remove("disabled")
shuffle.classList.remove("disabled") shuffle.classList.remove("disabled")
list.classList.remove("disabled")
play.classList.remove("pri_disable")
disconnect.classList.remove("invisible") disconnect.classList.remove("invisible")
volRange.classList.add("disabled") moveout.classList.remove("invisible")
volume.classList.remove("invisible")
volRange.disabled = false volTxt.classList.remove("invisible")
} else { volIcon.classList.remove("invisible")
lyrics.classList.remove("invisible")
vol.classList.add("disabled")
shuffle.classList.add("disabled")
list.classList.add("disabled")
play.classList.add("pri_disable")
disconnect.classList.add("invisible")
volRange.classList.add("disabled")
volRange.disabled = true
volRange.value = 0
volTxt.innerHTML = "0%"
volBox.classList.add("invisible")
} else {
play.classList.add("disabled")
forward.classList.add("disabled")
backward.classList.add("disabled")
loop.classList.add("disabled")
shuffle.classList.add("disabled")
moveout.classList.add("invisible")
disconnect.classList.add("invisible")
volume.classList.add("invisible")
volIcon.classList.add("invisible")
volTxt.classList.add("invisible")
time_act.innerHTML = "&nbsp"
time_total.innerHTML = "&nbsp"
durationBar.classList.add("invisible")
lyrics.classList.add("invisible")
} }
if(data.shuffle == true) {
shuffle.classList.add("point")
} else {
shuffle.classList.remove("point")
}
if(data.loop == true) {
loop.classList.add("point")
} else {
loop.classList.remove("point")
}
if(data.current) {
var thumbnail = data.current.thumbnail
if(thumbnail) {
video_img.innerHTML = '<img class="showPicture" src="' + thumbnail + '">'
}
currentTitle = data.current.title
video_title.innerHTML = "<p>" + data.current.title + "</p>"
video_artist.innerHTML = "<p>" + data.current.author + "</p>"
// Get the width of the title and check if it's above 400px (the max width of the title)
var titleWidth = video_title.querySelector("p").offsetWidth
if(titleWidth > 400) {
video_title.innerHTML = "<p>" + data.current.title + " -</p>" + "<p>" + data.current.title + " -</p> "
video_title.classList.add("scroll")
} else {
video_title.classList.remove("scroll")
}
video_img.classList.remove("invisible")
video_title.classList.remove("invisible")
video_artist.classList.remove("invisible")
play.classList.remove("disabled")
setTime()
} else {
video_img.classList.add("invisible")
video_title.classList.add("invisible")
video_artist.classList.add("invisible")
play.classList.add("disabled")
currentTitle = ""
}
if(data.queue) {
loadQueue(data.queue, "next")
actualiseQueue()
} else {
loadQueue(null, "next")
actualiseQueue()
}
if(data.previous) {
loadQueue(data.previous, "previous")
actualiseQueue()
} else {
loadQueue(null, "previous")
actualiseQueue()
}
if(data.volume) { if(data.volume) {
volRange.step = 1 volume.step = 1
volRange.max = 200 volume.max = 200
volRange.min = 1 volume.min = 1
volRange.value = Math.trunc(data.volume / 10) volume.value = Math.trunc(data.volume / 10)
volTxt.innerHTML = Math.trunc(data.volume / 10) + "%" volTxt.innerHTML = Math.trunc(data.volume / 10) + "%"
var volNum = Math.trunc(data.volume / 10) var volNum = Math.trunc(data.volume / 10)
if(volNum == 1) {
volIcon.innerHTML = '<i class="red fa-solid fa-volume-mute"></i>'
} else { } else if(volNum < 99) {
volIcon.innerHTML = '<i class="fa-solid fa-volume-down"></i>'
volRange.classList.add("disabled") } else {
volRange.disabled = true volIcon.innerHTML = '<i class="fa-solid fa-volume-up"></i>'
volRange.value = 0
volTxt.innerHTML = "0%"
}
if(data.shuffle == true) {
shuffle.innerHTML = '<i class="third-join fa fa-shuffle"></i>'
} else {
shuffle.innerHTML = '<i class="fa fa-shuffle"></i>'
}
if(data.loop == true) {
loop.innerHTML = '<i class="third-join fa fa-retweet"></i>'
} else {
loop.innerHTML = '<i class="fa fa-retweet"></i>'
}
if(data.current == null) {
musicURL.innerHTML = '<img class="showPicture" src="images/black-image.svg">'
musicTitle.innerHTML = "<p>Aucun titre joué</p>"
loop.classList.add("invisible")
takeCurrent.classList.add("invisible")
} else {
var thumbnail = data.current.thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
} }
musicURL.innerHTML = '<img class="showPicture" src="' + thumbnail + '">'
musicTitle.innerHTML = "<p>" + data.current.title + "</p>"
currentSong = data.current
takeCurrent.classList.remove("invisible")
loop.classList.remove("invisible")
}
if(data.durationAll) {
durationBar.disabled = false
durationBar.classList.remove("grised")
setTime()
durationAll = data.durationAll
durationProgress = data.durationNow
durationBar.value = durationProgress
setTime()
} else {
isPlaying = false
durationAll = 0
durationProgress = 0
durationBar.disabled = true
durationBar.classList.add("grised")
durationBar.value = 0
durationTextAct.innerHTML = "-:--"
durationTextTotal.innerHTML = "-:--"
}
}
if(data.playing == 1) { if(data.playing == 1) {
play.innerHTML = '<i class="fas fa-pause"></i>' play.innerHTML = '<i class="fas fa-pause icon"></i>'
isPlaying = true playerState = "PLAYING"
startInterval() startInterval()
} else { } else {
play.innerHTML = '<i class="fas fa-play"></i>' play.innerHTML = '<i class="fas fa-play icon"></i>'
isPlaying = false playerState = "PAUSED"
} }
if(data.durationAll) {
if(data.current && data.playing == 0) { if(data.durationAll == 9223372036854776000) {
setTime() durationBar.classList.add("invisible")
time_act.innerHTML = ""
} time_total.innerHTML = "<i class='red fa-solid fa-circle'></i> LIVE"
playerState = "LIVE"
if(data.durationAll == 9223372036854776000) { } else {
isPlaying = false
durationAll = 0
durationProgress = 0
durationBar.disabled = true
durationBar.classList.add("grised")
durationBar.style.display = "none"
durationBar.value = 0
durationTextAct.innerHTML = ""
durationTextTotal.innerHTML = "<i style='color: red;' class='fa-solid fa-circle'></i> LIVE"
} else {
durationBar.style.display = "unset"
}
if(data.queue != null) {
var contentToPush = new Array()
var queueNum = 0
for(var title of data.queue) {
queueNum += 1
console.log(queueNum)
console.log(data.queue.indexOf(title) + " - " + title.title)
var thumbnail = title.thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
}
contentToPush.push(' <div class="draggable song" id="' + data.queue.indexOf(title) + '_queue_song"> <img class="list_thumbnail" src="' + thumbnail + '"><div class="list_titleSong"> <p class="list_title">' + title.title + '</p></div> <button id="' + data.queue.indexOf(title) + '_lmove" class="list_upSong"><i class="fa fa-arrow-up"></i></button> <button id="' + data.queue.indexOf(title) + '_ldelete" class="list_delete"><i class="fa fa-trash"></i></button> </div>')
}
if(contentToPush.join("") == "") {
listNumber.classList.add("invisible") durationTotal = data.durationAll
listBox.innerHTML = '<p class="list_error">Aucun morceau dans la liste de lecture !</p>' durationAct = data.durationNow
setTime()
} else { durationBar.disabled = false
listNumber.innerHTML = '<span class="numtext">' + queueNum + '</span>' durationBar.max = durationTotal
listNumber.classList.remove("invisible") durationBar.value = durationAct
listBox.innerHTML = contentToPush.join("") durationBar.classList.remove("invisible")
setTime()
} }
//CODE INTEGER QUEUE LIST MOVE
const container = document.getElementById('listBox');
const draggableItems = document.querySelectorAll('.draggable');
let draggingElement = null;
draggableItems.forEach(item => {
item.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', item.innerHTML);
draggingElement = item;
});
item.addEventListener('dragend', () => {
draggingElement = null;
setTimeout(() => {
item.style.display = 'flex'; // Restaure l'affichage de l'élément
}, 0);
updateOrder();
});
});
container.addEventListener('dragover', (e) => {
e.preventDefault();
const afterElement = getDragAfterElement(container, e.clientY);
if (draggingElement !== null) {
if (afterElement == null) {
container.appendChild(draggingElement);
} else {
const rect = afterElement.getBoundingClientRect();
if (e.clientY < rect.top + rect.height / 2) {
container.insertBefore(draggingElement, afterElement);
} else {
container.insertBefore(draggingElement, afterElement.nextElementSibling);
}
}
}
});
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')];
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
} else {
return closest;
}
}, { offset: Number.NEGATIVE_INFINITY, element: null }).element;
}
function updateOrder() {
const draggableItems = document.querySelectorAll('.draggable');
const order = [];
draggableItems.forEach(item => {
order.push(item.id.replace("_queue_song", ""));
});
console.log('Ordre des divs:', order);
post("MOVE_QUEUE_BY_ENTIRE", order)
}
// END OF CODE INTEGER
for(var title of data.queue) {
console.log(data.queue.indexOf(title) + " - " + title.title)
const titleBtn = document.getElementById(data.queue.indexOf(title)+ "_ldelete")
const moveBtn = document.getElementById(data.queue.indexOf(title)+ "_lmove")
titleBtn.addEventListener("click", () => {
post("DELETE_QUEUE", titleBtn.id.replace("_ldelete", ""), data.queue[moveBtn.id.replace("_lmove", "")].title )
})
moveBtn.addEventListener("click", () => {
post("MOVE_QUEUE", moveBtn.id.replace("_lmove", ""))
})
}
} else {
listBox.innerHTML = '<p class="list_error">Lancez un titre et ajoutez vos morceaux ici !</p>'
listNumber.classList.add("invisible")
}
})
play.addEventListener('click', () => {
get("PAUSE")
})
document.body.onkeyup = function(e) {
if ((e.key == " " ||
e.code == "Space" ||
e.keyCode == 32) &&
e.srcElement.localName != "input" && e.srcElement.localName != "textarea"
) {
play.click()
}
}
backward.addEventListener('click', () => {
get("BACKWARD")
})
forward.addEventListener("click", () => {
get("FORWARD")
})
volBox.classList.add("invisible")
listBox.classList.add("invisible")
list.addEventListener("click" , () => {
volBox.classList.add("invisible")
if(listBox.classList.contains('invisible')) {
listBox.classList.remove("invisible")
} else {
listBox.classList.add("invisible")
}
})
vol.addEventListener("click", () => {
listBox.classList.add("invisible")
if(volBox.classList.contains('invisible')) {
volBox.classList.remove("invisible")
} else {
volBox.classList.add("invisible")
}
})
volRange.addEventListener("click", () => {
} else {
post("VOLUME", volRange.value) durationBar.classList.add("invisible")
durationBar.disabled = true
time_act.innerHTML = "&nbsp"
time_total.innerHTML = "&nbsp"
}
}) })
volRange.addEventListener("input", () => {
volTxt.innerHTML = volRange.value + "%"
})
loop.addEventListener("click", () => { loop.addEventListener("click", () => {
@ -364,8 +237,190 @@ disconnect.addEventListener("click", () => {
}) })
durationBar.addEventListener("change", () => { durationBar.addEventListener("click", (event) => {
stopInterval()
post("SEEK", durationBar.value) post("SEEK", durationBar.value)
startInterval()
})
durationBar.addEventListener("input", (event) => {
stopInterval()
time_act.innerHTML = getTimeCode(durationBar.value)
})
}) volume.addEventListener("click", () => {
post("VOLUME", volume.value)
})
volume.addEventListener("dblclick", () => {
post("VOLUME", 100)
})
play.addEventListener('click', () => {
get("PAUSE")
})
forward.addEventListener('click', () => {
get("FORWARD")
})
backward.addEventListener('click', () => {
get("BACKWARD")
})
moveout.addEventListener('click', () => {
get("MOVEOUT")
})
lyrics.addEventListener('click', (e) => {
currentTitle = currentTitle.replace(/\(.*?\)/g, "").replace(/\[.*?\]/g, "").trim()
if(e.ctrlKey) {
const modal = new ModalComponent({"title": "Rechercher des paroles" , "width": "25%", "closable": true})
modal.setContent(`
<div class='lyrics-finder'>
<input id="lyrics_search" type="text" placeholder="Rechercher des paroles">
<button id="lyrics_search_btn">Rechercher</button>
</div>
`)
modal.show()
const lyricsSearch = getID("lyrics_search")
const lyricsSearchBtn = getID("lyrics_search_btn")
lyricsSearchBtn.addEventListener('click', () => {
showLyrics(lyricsSearch.value)
modal.hide()
})
} else {
if(currentTitle != "") {
showLyrics(currentTitle)
} else {
const modal = new ModalComponent({"title": "Paroles" , "width": "20%", "closable": true})
modal.setContent(`
<p class="lyrics">Lancez une musique pour rechercher les paroles ou faites Ctrl + Click !</p>
`)
modal.show()
}
}
})
function showLyrics(title) {
post("LYRICS", title).then((res) => {
if(!res) {
const modal = new ModalComponent({"title": "Paroles" , "width": "50%", "closable": true})
modal.setContent(`
<p class="lyrics">Aucune paroles trouvées pour cette musique !</p>
`)
modal.show()
} else {
const lyricsArray = new Array()
for(var line of res.split("\n")) {
if(line == "") {
lyricsArray.push("<br>")
}
// Bold the line if it's between []
if(line.startsWith("[") && line.endsWith("]")) {
lyricsArray.push("<p class='lyrics'><strong>" + line + "</strong></p>")
} else {
lyricsArray.push("<p class='lyrics'>" + line + "</p>")
}
}
lyricsArray.push("<br><br><a href='https://genius.com' target='_blank' class='lyrics-info wh'>Distribué par Genius ©️</a>")
setTileActive(null)
loadView(`
<h1>Paroles de "${title}"</h1>
<div class="lyrics-container">
<div class="lyrics-list">
${lyricsArray.join("")}
</div>
</div>
`)
}
})
}
volIcon.addEventListener('click', () => {
if(volume.value > 1) {
post("VOLUME", 1)
} else {
post("VOLUME", 100)
}
})
document.body.onkeyup = function(e) {
if ((e.key == " " ||
e.code == "Space" ||
e.keyCode == 32) &&
e.srcElement.localName != "input" && e.srcElement.localName != "textarea"
) {
play.click()
}
}
// Function with setTime
function setTime() {
durationBar.max = durationTotal
durationAct += 1000
durationBar.value = durationAct
time_act.innerHTML = getTimeCode(durationAct)
time_total.innerHTML = getTimeCode(durationTotal)
}
function startInterval() {
interval = setInterval(() => {
if(playerState == "PLAYING") {
setTime()
}
}, 1000)
}
function stopInterval() {
clearInterval(interval);
}

View File

@ -1,312 +1,450 @@
function delPlayList(key) { const playlistList = getID("playlist-list")
const playlistAdd = getID("playlist-add")
post("DELETE_PLAYLIST", key) var loadingPlaylist = false
mainView.innerHTML = WelcomeContent
playlistSelected = null
playlistValue = null
}
function playPlayList(key) { playlistAdd.addEventListener("click", () => {
const win = new ModalComponent({
"title": "<i style='transform: scale(0.8);' class='fa fa-music'></i> Ajouter une playlist",
"width": "20%",
})
post("PLAY_PLAYLIST", key) win.setContent(`
<div class="modal-form">
<input id="playlist-name" type="text" placeholder="Nom de la playlist">
<select id="playlist-source">
<option value="normal">Privée</option>
<option value="shared">Partagée</option>
<option value="youtube">Youtube</option>
</select>
<input id="playlist-url" type="text" placeholder="URL de la playlist">
<span id='playlist-add-info'></span>
<button id="playlist-add-confirm">Ajouter</button>
</div>
`)
} win.show()
function sendPlayList(key) { const confirm = getID("playlist-add-confirm")
const name = getID("playlist-name")
const source = getID("playlist-source")
const url = getID("playlist-url")
const playlist_popup = document.getElementById("playlist_popup") url.style.display = "none"
if(playlist_popup) {
get("USER_LIST").then(resp => {
const userToPush = new Array()
for(var user of resp) {
userToPush.push(`<div id='${resp.indexOf(user)}' class="popup_line"><img src="${user.picture}"><div style="display: flex; flex-direction: column; justify-content: start; text-align: start;"><p class="INDEX_gbname">${user.global_name}</p><p class="INDEX_usrname">${user.username}</p></div></div>`)
confirm.addEventListener("click", () => {
if(source.value == "youtube" && url.value.length == 0) {
getID("playlist-add-info").innerHTML = "<i class='fa fa-warning'></i> L'URL de la playlist ne peut pas être vide"
return
}
if(name.value.length > 0) {
var data = {
"name": name.value,
"source": source.value,
"url": url.value
} }
post("CREATE_PLAYLIST", data).then((data) => {
playlist_popup.innerHTML = userToPush.join("") if(data.status == "error") {
playlist_popup.style.width = '170px' getID("playlist-add-info").innerHTML = "<i class='fa fa-warning'></i>" + data.message
playlist_popup.style.top = (yMousePos - 30) + "px"
playlist_popup.style.left = (xMousePos - 165) + "px"
playlist_popup.style.overflowY = "auto";
playlist_popup.style.height = "250px"
playlist_popup.classList.remove("invisible")
playlist_popup.addEventListener("mouseleave", () => {
playlist_popup.classList.add("invisible")
})
for(var user of resp) {
const userElement = document.getElementById(resp.indexOf(user))
userElement.addEventListener("click", () => {
playlist_popup.classList.add("invisible")
post("SEND_PLAYLIST", {key: key, dest: resp[userElement.id].id})
})
}
//post("SEND_PLAYLIST", key, user.id)
})
}
}
function loadPlaylist(key, value) {
userLocation = "playlist"
var playlistToPush = new Array()
var playlist_songs = new Array()
playlistSelected = key
playlistValue = value
for(var title of value) {
var PFormatduration = getTimeCode(title.duration)
var thumbnail = title.thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
}
if(title.duration == 9223372036854776000) {
PFormatduration = "<i style='color: red;' class='fa-solid fa-circle'></i> LIVE"
}
playlist_songs.push('<div class="search_song"> <img class="search_thumbnail" src="' + thumbnail + '"><div class="search_titleSong"> <p class="search_title">' + title.title + '</p></div> <p>' + title.author + '</p><p>' + PFormatduration + '</p> <div class="search_buttons"><button id="' + value.indexOf(title) + '_padd" class="search_add"><i class="fa fa-plus"></i></button><button id="' + value.indexOf(title) + '_pplay" class="search_lmore"><i class="fa fa-play"></i></button><button id="' + value.indexOf(title) + '_pdelete" style="font-size: 20px;" class="list_delete"><i class="fa fa-trash"></i></button></div></div>')
}
playlistToPush.push(`<div class="INDEX_userPopup invisible" id="playlist_popup"></div>`)
playlistToPush.push('<div class="apPres"><div class="apTitle"><img class="apTile" src="/images/playlist-tile.svg"><p class="apName">' + key + '</p></div><div class="apButtons"><button onclick="playPlayList(\''+ key +'\')" id="'+ key +'_playlistplay" class="primary"><i class="fas fa-play"></i><button onclick="sendPlayList(\''+ key +'\')" id="sendplaylist" class="list_upSong"><i class="fas fa-paper-plane"></i></button></button><button onclick="delPlayList(\''+ key +'\')" id="playlistdelete" class="list_delete"><i class="fas fa-trash"></i></button></div></div><hr>' + playlist_songs.join(""))
if(playlistToPush.join("") == "") {
mainView.innerHTML = '<p class="error">Aucun morceau trouvé !</p>'
} else {
mainView.innerHTML = playlistToPush.join("")
}
for(var title of value) {
const add_to = document.getElementById(value.indexOf(title) + "_padd")
const playNow = document.getElementById(value.indexOf(title) + "_pplay")
const deleteBtn = document.getElementById(value.indexOf(title) + "_pdelete")
add_to.addEventListener("click", () => {
post("ADD_SONG", value[add_to.id.replace("_padd", "")])
})
playNow.addEventListener("click", () => {
post("ADD_SONG_NOW", value[add_to.id.replace("_padd", "")])
})
deleteBtn.addEventListener("click", () => {
deleteJustBefore = true
post("DELETE_SONG_TO_PLAYLIST", {data: key, song: value[add_to.id.replace("_padd", "")]})
})
}
}
function fp_play_playlist(key) {
post("FP_PLAY_PLAYLIST", key)
}
socket.on("DO_UPDATE_PLAYLIST", () => {
get("PLAYLIST")
})
get("PLAYLIST")
socket.on("ANSWER/GET/PLAYLIST", (data) => {
var contentToPush = new Array()
var selectionData = new Array()
contentToPush.push(`<p>Mes Playlists</p>`)
contentToPush.push('<div id="createPlaylist" class="playlist_div"><i class="fa-solid fa-plus"></i> Créer une playlist</div>')
for (const [key, value] of Object.entries(data)) {
contentToPush.push('<div id="' + key + '_playlist" class="playlist_div checker"><img class="tile" src="/images/playlist-tile.svg"><p>' + key + '</p></div>')
selectionData.push('<option style="color: black;">' + key + '</option>')
}
if(contentToPush.join("") == "") {
playlistContent.innerHTML = '<p class="error">Aucun morceau trouvé !</p>'
} else {
playlistContent.innerHTML = contentToPush.join("")
playlistAvailable = selectionData
}
if(playlistSelected && deleteJustBefore || playlistSelected && userLocation == "playlist") {
deleteJustBefore = null
loadPlaylist(playlistSelected, data[playlistSelected])
}
for (const [key, value] of Object.entries(data)) {
const playlist_selector = document.getElementById(key + '_playlist')
playlist_selector.addEventListener("click", () => {
loadPlaylist(key, value)
userLocation = "playlist"
})
}
const buttons = document.querySelectorAll(".checker");
buttons.forEach(button => {
button.addEventListener("click", function () {
buttons.forEach(btn => {
if (btn === button) {
btn.style.color = "white";
} else { } else {
btn.style.color = ""; win.hide()
loadPlaylistList()
} }
}); })
});
});
const addPlaylist = document.getElementById("createPlaylist")
const addPlaylist_dialog = document.getElementById("createPlaylist_dialog")
const addPlaylist_close = document.getElementById("createPlaylist_close")
const apText = document.getElementById("apText")
const apInfo = document.getElementById("apInfo")
const apCreate = document.getElementById("apCreate")
addPlaylist_close.addEventListener("click", () => {
apInfo.innerHTML = ""
addPlaylist_dialog.close()
})
addPlaylist.addEventListener("click", () => {
apText.innerHTML = ""
addPlaylist_dialog.showModal()
})
apCreate.addEventListener("click", () => {
apInfo.innerHTML = ""
var wrongName = true
const refusedChar = ['\\','/' ,':' ,'*','?' ,'"','<','>','|']
for(var char of refusedChar) {
if(apText.value.includes(char)) {
wrongName = false
}
}
if(apText.value != "" && apText.value != " " && wrongName) {
addPlaylist_dialog.close()
post("CREATE_PLAYLIST", apText.value)
} else { } else {
getID("playlist-add-info").innerHTML = "<i class='fa fa-warning'></i> Le nom de la playlist ne peut pas être vide"
apInfo.innerHTML = "<span style='red'>Le nom n'est pas valide !</style>"
} }
}) })
source.addEventListener("change", () => {
if(source.value == "youtube") {
console.log(data) url.style.display = "block"
}) } else {
url.style.display = "none"
// Current Playlist and Song
const cPlaylistManager = document.getElementById("current_playlistManager")
const cplaylistManager_close = document.getElementById("current_playlistManager_close")
const cplaylistSelection = document.getElementById("current_playlistSelection")
const cplaylist_add_music = document.getElementById("current_playlist_add_music")
const cplaylist_add_img = document.getElementById("current_playlist_add_img")
const cplaylistAddSong = document.getElementById("current_playlistAddSong")
takeCurrent.addEventListener("click", () => {
if(currentSong != null) {
var thumbnail = currentSong.thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
} }
})
cPlaylistManager.showModal()
cplaylist_add_music.innerHTML = currentSong.title
cplaylist_add_img.src = thumbnail
cplaylistSelection.innerHTML = playlistAvailable
}
}) })
cplaylistManager_close.addEventListener("click", () => { loadPlaylistList()
cPlaylistManager.close() AlwaysRequest("PLAYLIST_REFRESH", () => {
})
cplaylistAddSong.addEventListener("click", () => { loadPlaylistList()
cPlaylistManager.close()
post("ADD_SONG_TO_PLAYLIST", {data: cplaylistSelection.value , song: currentSong} )
}) })
function loadPlaylistList() {
get("PLAYLIST").then((data) => {
var playlists = new Array()
playlistList.innerHTML = ""
for(var playlist in data) {
const playlistTile = new PlaylistComponent(playlist, data[playlist])
playlists.push(playlistTile)
playlistList.innerHTML += playlistTile.generateHTML()
if(playlistId == playlist) {
loadPlaylist(playlistId, data[playlist])
}
}
for(var playlist of playlists) {
playlist.loadScript()
}
})
}
class PlaylistComponent {
constructor(id, data) {
this.title = data.title
this.id = id
this.source = data.source
this.content = data.content
this.self = data
}
generateHTML() {
var logo = "fa fa-music"
if(this.source == "shared") {
logo = "fas fa-share-alt"
} else if(this.source == "youtube") {
logo = "fab fa-youtube"
}
return `
<div id='${this.id}' class="playlist-item">
<div id='${this.id}_tile' class="playlist-item-tile">
<i class="${logo}"></i>
</div>
<p>${this.title}</p>
</div>`
}
loadScript() {
const playlist = getID(this.id)
const tile = getID(`${this.id}_tile`)
tileList.push(tile)
playlist.addEventListener("click", () => {
loadPlaylist(this.id, this.self)
})
}
}
function loadPlaylist(id, properties) {
if(loadingPlaylist) {
return
}
if(!playlistId || playlistId != id) {
loading()
}
setTileActive(id + "_tile")
playlistId = id
if(properties.source == "youtube") {
loadingPlaylist = true
post("SEARCH", properties.content).then((res) => {
if(id == playlistId) {
loadingPlaylist = false
loadYoutubePlaylist(res, id, properties)
}
})
} else {
loadingPlaylist = false
loadNormalPlaylist(id, properties)
}
}
function loadNormalPlaylist(id, properties) {
loadView(`
<div style='padding-bottom: 15px;' class='search-playlist'>
<div class='search-playlist-info'>
<div class='playlist-item-tile'>
${properties.source == "shared" ? "<i class='fas fa-share-nodes'></i>" : "<i class='fa fa-music'></i>"}
</div>
<div class='search-playlist-div'>
<p class='search-playlist-title'>${properties.title} <span id='pp-rename'><i class='search-playlist-rename fa fa-pen'></i></span></p>
<div>
<p class='search-playlist-desc'>${properties.content.length} titres </p>
</div>
</div>
</div>
<div class='search-playlist-actions'>
<span id='pp-add' class='wh'><i class='fa fa-add'></i></span>
<span id='pp-play' class='wh'><i class='fa fa-play'></i></span>
<span id='pp-send' class='wh'><i class='fa fa-paper-plane'></i></span>
<span id='pp-delete' class='wh'><i class='fa fa-trash'></i></span>
</div>
</div>
<div class="search-container">
<div class="search-list" id="playlist-video-list">
</div>
</div>
`)
loadActions(null, id, properties)
const playlistList = getID("playlist-video-list")
var songList = new Array()
playlistList.style.display = "grid"
for(var video of properties.content) {
console.log(video)
const videoTile = new VideoComponent(video, false)
songList.push(videoTile)
playlistList.innerHTML += videoTile.generateHTML(true, false)
}
// IF THE PLAYLIST IS EMPTY
if(songList.length == 0) {
playlistList.style.display = "flex"
playlistList.innerHTML = "<p class='search-no-song'>Aucun titre dans cette playlist</p>"
}
for(var song of songList) {
song.loadScript(true, true)
}
}
function loadYoutubePlaylist(res, id, properties) {
var author = ""
console.log(res.results.author)
if(res.results.author) {
author = `
<a target='_blank' style='text-decoration: none;' href='${res.results.author.url}'><div class='search-playlist-author'>
<img class='search-playlist-author-img' src='${res.results.author.avatar_url}'>
<p class='search-playlist-author-name'>${res.results.author.name}</p>
</div></a>
`
}
loadView(`
<div style='padding-bottom: 15px;' class='search-playlist'>
<div class='search-playlist-info'>
<div id='search-image-link' class='search-playlist-image'>
<img src='${res.results.thumbnail_url}' class='showPicture'>
</div>
<div class='search-playlist-div'>
<p id='playlist-title' class='search-playlist-title'>${res.results.title} <span id='pp-rename'><i class='search-playlist-rename fa fa-pen'></i></span></p>
<div>
<p class='search-playlist-desc'>${res.results.videos.length} titres - ${res.results.view_count} vues </p>
<p class='search-playlist-desc'> ${res.results.description}</p>
</div>
${author}
</div>
</div>
<div class='search-playlist-actions'>
<span id='pp-add' class='wh'><i class='fa fa-add'></i></span>
<span id='pp-play' class='wh'><i class='fa fa-play'></i></span>
<span id='pp-send' class='wh'><i class='fa fa-paper-plane'></i></span>
<span id='pp-delete' class='wh'><i class='fa fa-trash'></i></span>
</div>
</div>
<div class="search-container">
<div class="search-list" id="playlist-video-list">
</div>
</div>
`)
loadActions(res, id, properties)
const playlistList = getID("playlist-video-list")
const searchImageLink = getID("search-image-link")
const playlistTitle = getID("playlist-title")
searchImageLink.addEventListener("click", function(e) {
if(e.ctrlKey) {
// Put in the clipboard properties.content
navigator.clipboard.writeText(properties.content)
// Set the title green for 1 second
playlistTitle.style.color = "#32FF32"
setTimeout(() => {
playlistTitle.style.color = "white"
}, 1000)
} else {
window.open(properties.content, '_blank');
}
})
var songList = new Array()
console.log(res.results.videos)
for(var video of res.results.videos) {
const videoTile = new VideoComponent(video, true)
songList.push(videoTile)
playlistList.innerHTML += videoTile.generateHTML(true, true)
}
for(var song of songList) {
song.loadScript(true)
}
}
function loadActions(res, id, properties) {
const ppAdd = getID("pp-add")
const ppPlay = getID("pp-play")
const ppSend = getID("pp-send")
const ppDelete = getID("pp-delete")
const ppRename = getID("pp-rename")
ppRename.addEventListener("click", () => {
const win = new ModalComponent({
"title": "<i style='transform: scale(0.8);' class='fa fa-music'></i> Renommer la playlist",
"width": "20%",
})
win.setContent(`
<div class="modal-form">
<input id="playlist-rename-name" type="text" placeholder="Nom de la playlist" value="${properties.title}">
<button id="playlist-rename-confirm">Renommer</button>
</div>
`)
win.show()
const confirm = getID("playlist-rename-confirm")
const name = getID("playlist-rename-name")
confirm.addEventListener("click", () => {
if(name.value.length > 0) {
post("RENAME_PLAYLIST", {id: id, name: name.value})
win.hide()
}
})
})
ppAdd.addEventListener("click", () => {
if(res) {
post("FP_PLAY_PLAYLIST", res.results.url)
} else {
post("PLAY_PLAYLIST", id)
}
})
ppPlay.addEventListener("click", () => {
if(res) {
post("FP_PLAY_PLAYLIST_NOW", res.results.url)
} else {
post("PLAY_PLAYLIST_NOW", id)
}
})
ppDelete.addEventListener("click", () => {
// Make a confirmation modal
const win = new ModalComponent({
"title": "<i style='transform: scale(0.8);' class='fa fa-trash'></i> Supprimer la playlist",
"width": "15%",
})
win.setContent(`
<div class="modal-form">
<p style='text-align: center;'>Êtes-vous sûr de vouloir supprimer la playlist ?</p>
<button id="playlist-delete-confirm">Supprimer</button>
</div>
`)
win.show()
const confirm = getID("playlist-delete-confirm")
confirm.addEventListener("click", () => {
post("DELETE_PLAYLIST", id)
win.hide()
loadSearch()
})
})
ppSend.addEventListener("click", () => {
get("USER_LIST").then((data) => {
var userList = new Array()
for(var userPS of data) {
console.log(userPS)
if(userPS.username != userId.innerHTML) {
userList.push(userPS)
}
}
const win = new ModalComponent({
"title": "<i style='transform: scale(0.8);' class='fa fa-music'></i> Envoyer la playlist",
"width": "20%",
})
win.setContent(`
<div class="modal-form">
<select id="playlist-user">
${userList.map((userPS) => `<option value="${userPS.id}">${userPS.username}</option>`)}
</select>
<button id="playlist-send-confirm">Envoyer</button>
</div>
`)
win.show()
const confirm = getID("playlist-send-confirm")
const userS = getID("playlist-user")
confirm.addEventListener("click", () => {
post("SEND_PLAYLIST", {key: id, dest: userS.value})
win.hide()
})
})
})
}

View File

@ -0,0 +1,261 @@
const listDiv = document.getElementById("list-div");
const listNext = document.getElementById("list-next");
const listPrevious = document.getElementById("list-previous");
const listClear = document.getElementById("list-clear");
var selectedQueue = "next"
var previousQueue = new Array()
var nextQueue = new Array()
listClear.addEventListener("click", function() {
post("DELETE_ALL_QUEUE")
})
listNext.addEventListener("click", function() {
listClear.style.display = "flex"
listPrevious.classList.remove("selected")
listNext.classList.add("selected")
selectedQueue = "next"
showQueue(nextQueue, "next")
})
listPrevious.addEventListener("click", function() {
listClear.style.display = "none"
listNext.classList.remove("selected")
listPrevious.classList.add("selected")
selectedQueue = "previous"
showQueue(previousQueue, "previous")
})
function loadQueue(queue, type) {
if(type == "next") {
nextQueue = queue
} else if(type == "previous") {
previousQueue = queue
}
}
function showQueue(queue, type) {
listDiv.innerHTML = ""
if(!queue) {
listDiv.innerHTML = "<p class='no-song'>Subsonics est déconnecté</p>"
if(type == "previous") {
listDiv.innerHTML = "<p class='no-song'>Aucune musique n'a été jouée</p>"
}
} else if(queue.length > 0) {
console.log(queue)
var videoList = new Array()
for(var song of queue) {
if(type == "next") {
song.type = "next"
} else {
song.type = "previous"
}
song.numList = queue.indexOf(song)
var video = new VideoQueue(song)
listDiv.innerHTML += video.generateHTML()
videoList.push(video)
}
for(var video of videoList) {
video.loadScript()
}
const container = listDiv;
const draggableItems = document.querySelectorAll('.draggable');
let draggingElement = null;
draggableItems.forEach(item => {
item.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', item.innerHTML);
draggingElement = item;
});
item.addEventListener('dragend', () => {
draggingElement = null;
setTimeout(() => {
item.style.display = 'flex'; // Restaure l'affichage de l'élément
}, 0);
updateOrder();
});
});
container.addEventListener('dragover', (e) => {
e.preventDefault();
const afterElement = getDragAfterElement(container, e.clientY);
if (draggingElement !== null) {
if (afterElement == null) {
container.appendChild(draggingElement);
} else {
const rect = afterElement.getBoundingClientRect();
if (e.clientY < rect.top + rect.height / 2) {
container.insertBefore(draggingElement, afterElement);
} else {
container.insertBefore(draggingElement, afterElement.nextElementSibling);
}
}
}
});
} else {
if(type == "next") {
listDiv.innerHTML = "<p class='no-song'>Aucune musique n'est en attente</p>"
} else if(type == "previous") {
listDiv.innerHTML = "<p class='no-song'>Aucune musique n'a été jouée</p>"
}
}
}
function actualiseQueue() {
if(selectedQueue == "next") {
showQueue(nextQueue, "next")
} else if(selectedQueue == "previous") {
showQueue(previousQueue, "previous")
}
}
class VideoQueue {
constructor(data) {
console.log(data)
this.title = data.title
this.author = data.author
this.thumbnail = data.thumbnail
this.url = data.uri
this.duration = data.duration
this.identifier = data.numList + "_" + data.identifier
this.type = data.type
this.numList = data.numList
}
generateHTML() {
var dragOn = ""
var idOn = ""
if(this.type == "next") {
dragOn = "draggable"
idOn = `${this.numList}_queue_song`
}
var timecode = null
// Check if live
if(this.duration == 9223372036854776000) {
timecode = "<i class='red fa-solid fa-circle'></i> LIVE"
} else {
timecode = getTimeCode(this.duration)
}
return `
<div id='${idOn}' class="list-video ${dragOn}">
<div class="list-video-div">
<div class="list-video_image"><img class="showPicture" src="${this.thumbnail}"><p class='list-time-code'>${timecode}</p></div>
<div class="list-video_title">
<span class="list-video_title_title"><p>${this.title}</p></span>
<span class="list-video_title_channel"><p>${this.author}</p></span>
</div>
</div>
<span id='${this.identifier}' class="list-video-elipsis"><i class="fa-solid fa-ellipsis-vertical"></i></span>
</div>`
}
loadScript() {
const identifier = getID(this.identifier)
const menu = new DroppableMenu()
menu.add("play", "<i class='fa fa-play'></i> Lire")
if(this.type == "next") {
menu.add("up", "<i class='fa fa-list-ol'></i> <p>Placer au dessus</p>")
menu.add("delete", "<i class='fa fa-trash'></i> <p>Supprimer</p>")
} else {
menu.add("add", "<i class='fa fa-list-ol'></i> <p>Ajouter à la file d'attente</p>")
}
// Add to a playlist
menu.add("playlist", "<i class='fa fa-plus'></i> <p>Ajouter à une playlist</p>")
identifier.addEventListener("click", (event) => {
if(event.ctrlKey || event.metaKey) {
post("DELETE_QUEUE", this.numList, this.title)
} else {
menu.show()
const play = getID(`${menu.id}_play`)
const playlist = getID(`${menu.id}_playlist`)
playlist.addEventListener("click", () => {
saveToPlaylist(this.url)
})
play.addEventListener("click", () => {
post("PLAY_QUEUE", [this.numList, this.type])
})
if(this.type == "next") {
const up = getID(`${menu.id}_up`)
const deleteEl = getID(`${menu.id}_delete`)
up.addEventListener("click", () => {
post("MOVE_QUEUE", this.numList)
})
deleteEl.addEventListener("click", () => {
post("DELETE_QUEUE", this.numList, this.title)
})
} else {
const add = getID(`${menu.id}_add`)
add.addEventListener("click", () => {
post("CHANGE_QUEUE", this.numList)
})
}
}
})
}
}
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')];
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
} else {
return closest;
}
}, { offset: Number.NEGATIVE_INFINITY, element: null }).element;
}
function updateOrder() {
const draggableItems = document.querySelectorAll('.draggable');
const order = [];
draggableItems.forEach(item => {
order.push(item.id.replace("_queue_song", ""));
});
console.log('Ordre des divs:', order);
post("MOVE_QUEUE_BY_ENTIRE", order)
}

View File

@ -1,100 +0,0 @@
AlwaysRequest("ALL_RADIO", (resp) => {
if(userLocation == "home") {
const radio_list = document.getElementById("radio_list")
const radioToPush = new Array()
radioToPush.push("<p style='font-family: Gunship, sans-serif;'><i class='fa fa-radio'></i> Radio</p>")
radioToPush.push(`
<dialog class="report_dialog" id="radio_dialog">
<div class="rlineclose">
<p class="rtitle"><i class="fa fa-radio"></i> Ajout d'une radio</p>
<button id="radio_close" class="report_close"><i class="fa-solid fa-xmark"></i></button>
</div>
<p id='radio_info' style='text-align: center; color: red;'></p>
<div class="rcontent">
<p class="runder">URL</p>
<input type='text' id="radio_host">
<button id="radio_send" class="rsend"><i class="fa-solid fa-plus"></i> Ajouter</button>
</div>
</dialog>
`)
for(var title of resp ) {
var thumbnail = title.thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
}
radioToPush.push(`<div style='grid-template-columns: 0.5fr 7fr 1fr !important;' class="search_song"> <img style='width: 60px;height: 45px; margin-right: 10px;' src="${thumbnail}"><div class="search_titleSong"> <p class="search_title">${title.title} - ${title.author}</p></div><button id='${resp.indexOf(title)}_radio_pplay' class='primary'><i class='fa fa-play'></i></button></div>`)
}
if(userAdmin) {
radioToPush.push(`
<div id="radio_add" class="playlist_div"><i style='margin-right: 10px;' class='fa fa-plus'></i> Ajouter une radio</div>`)
}
radio_list.innerHTML = radioToPush.join("")
if(userAdmin) {
const radio_dialog = document.getElementById("radio_dialog")
const radio_close = document.getElementById("radio_close")
const radio_send = document.getElementById("radio_send")
const radio_add = document.getElementById("radio_add")
const radio_info = document.getElementById("radio_info")
const radio_host = document.getElementById("radio_host")
if(radio_add) {
radio_add.addEventListener("click", () => {
radio_info.innerHTML = ""
radio_host.value = ""
radio_dialog.showModal()
})
radio_close.addEventListener("click", () => {
radio_info.innerHTML = ""
radio_dialog.close()
})
radio_send.addEventListener("click", () => {
if(radio_host.value != '') {
post("RADIO/ADD", radio_host.value)
radio_dialog.close()
} else {
radio_info.innerHTML = "Remplissez une URL !"
}
})
}
}
for(var title of resp ) {
const playBtn = document.getElementById(resp.indexOf(title) +'_radio_pplay')
playBtn.addEventListener("click", () => {
post("ADD_SONG_NOW", resp[playBtn.id.replace("_radio_pplay", "")])
})
}
}
})

View File

@ -1,18 +0,0 @@
reportBtn.addEventListener("click", () => {
report_desc.value = ""
report_level.value = "Majeur"
report_dialog.showModal()
})
report_close.addEventListener("click", () => {
report_dialog.close()
})
report_send.addEventListener("click", () => {
post("REPORT", {"level":report_level.value, "desc": report_desc.value})
report_dialog.close()
})

View File

@ -1,214 +1,145 @@
searchBtn.addEventListener("click", () => {
mainView.innerHTML = '<div class="findbar"><i class="fa fa-search"></i><input autofocus id="searchBar" placeholder="Insérez des mots-clés ou un lien" type="text"></div><div class="search_middle"></div><div id="search_content"></div>' function loadSearchView() {
const searchBar = document.getElementById("searchBar") const searchList = getID("search-list")
const searchcontent = document.getElementById("search_content") const searchInput = getID("search-input")
const playlistInfo = getID("playlist-info")
searchBar.addEventListener("change", () => { loadSplash()
searchInput.addEventListener("change", () => {
post("SEARCH", searchBar.value).then(answerOfResult => {
searchList.style.display = "flex"
searchList.style.flexDirection = "column"
searchList.innerHTML = loading(true)
playlistInfo.innerHTML = ""
if(searchInput.value != '') {
searchResults(searchInput.value)
var results = answerOfResult.results if(searchInput.value.includes("https://") || searchInput.value.includes("http://")) {
var playlistReconnised = answerOfResult.playlist
if(searchBar.value.includes("https://") || searchBar.value.includes("http://")) { searchInput.value= ""
searchBar.value= ""
} }
} else {
loadSplash()
}
if(!playlistReconnised) {
if(results.tracks != null) {
const data = results.tracks
console.log(data)
var contentToPush = new Array()
for(var title of data) {
var thumbnail = title.thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
}
var PFormatduration = getTimeCode(title.duration)
if(title.duration == 9223372036854776000) {
PFormatduration = "<i style='color: red;' class='fa-solid fa-circle'></i> LIVE"
}
contentToPush.push(' <div class="search_song"> <img class="search_thumbnail" src="' + thumbnail + '"><div class="search_titleSong"> <p class="search_title">' + title.title + '</p></div> <p>' + title.author + '</p><p>' + PFormatduration + '</p> <div class="search_buttons"><button id="' + data.indexOf(title) + '_ladd" class="search_add"><i class="fa fa-plus"></i></button> <div class="searchMoreDiv"><button id="' + data.indexOf(title) + '_lmore" class="search_lmore"><i class="fa-solid fa-ellipsis"></i></button></div><div class="searchPopup" id="' + data.indexOf(title) + '_popup"><div id="' + data.indexOf(title) + '_playNow" class="INDEX_line"><i class="fa-solid fa-play"></i> Lire maintenant</div><div id="' + data.indexOf(title) +'_goPlaylist" class="INDEX_line"><i class="fa-regular fa-square-plus"></i> Ajouter à une playlist</div><div id="' + data.indexOf(title) +'_copy" class="INDEX_line"><i class="fa-regular fa-copy"></i> Copier le lien</div></div></div><dialog id="' + data.indexOf(title) + 'playlistManager" class="report_dialog"><div class="rlineclose"><p class="rtitle"><i class="fa fa-square-plus"></i> Ajouter à une playlist</p><button id="' + data.indexOf(title) + 'playlistManager_close" class="report_close"><i class="fa-solid fa-xmark"></i></button></div><div class="apContent"><img id="' + data.indexOf(title) + 'playlist_add_img" class="ppTile" src="/images/playlist-tile.svg"><p style="padding: 1%;" id="' + data.indexOf(title) + 'playlist_add_music"></p><p>Selectionner la playlist</p><select style=" color: white; background-color: transparent; border: solid 2px #2c3df4;padding: 1%; border-radius: 12px;" id="' + data.indexOf(title) + 'playlistSelection"></select><button id="' + data.indexOf(title) + 'playlistAddSong" class="rsend"><i class="fa fa-plus"></i> Ajouter</button></div></dialog></div>')
}
if(contentToPush.join("") == "") {
searchcontent.innerHTML = '<p class="error">Aucun morceau trouvé !</p>'
} else {
searchcontent.innerHTML = contentToPush.join("")
}
for(var title of data) {
const add_to = document.getElementById(data.indexOf(title) + "_ladd")
const test_lmore = document.getElementById(data.indexOf(title) + "_lmore")
const testPopup = document.getElementById(data.indexOf(title) + "_popup")
const playNow = document.getElementById(data.indexOf(title) + "_playNow")
const copy = document.getElementById(data.indexOf(title) + "_copy")
const addPlaylist = document.getElementById(data.indexOf(title) + "_goPlaylist")
const PlaylistManager = document.getElementById(data.indexOf(title) + "playlistManager")
const playlistManager_close = document.getElementById(data.indexOf(title) + "playlistManager_close")
const playlistSelection = document.getElementById(data.indexOf(title) + "playlistSelection")
const playlist_add_music = document.getElementById(data.indexOf(title) + "playlist_add_music")
const playlist_add_img = document.getElementById(data.indexOf(title) + "playlist_add_img")
const playlistAddSong = document.getElementById(data.indexOf(title) + "playlistAddSong")
var thumbnail = data[add_to.id.replace("_ladd", "")].thumbnail
if(!thumbnail) {
thumbnail = "/images/black-image.svg"
}
testPopup.style.display = "none"
add_to.addEventListener("click", () => {
post("ADD_SONG", data[add_to.id.replace("_ladd", "")])
})
copy.addEventListener("click", () => {
navigator.clipboard.writeText(data[add_to.id.replace("_ladd", "")].uri)
testPopup.style.display = "none"
})
addPlaylist.addEventListener("click", () => {
PlaylistManager.showModal()
playlist_add_music.innerHTML = data[add_to.id.replace("_ladd", "")].title
playlist_add_img.src = thumbnail
playlistSelection.innerHTML = playlistAvailable
})
playlistManager_close.addEventListener("click", () => {
PlaylistManager.close()
})
playlistAddSong.addEventListener("click", () => {
PlaylistManager.close()
post("ADD_SONG_TO_PLAYLIST", {data: playlistSelection.value , song: data[add_to.id.replace("_ladd", "")]})
})
test_lmore.addEventListener("click",( ) => {
testPopup.style.display = "flex"
testPopup.style.top = yMousePos + "px"
})
testPopup.addEventListener("mouseleave", () => {
testPopup.style.display = "none"
})
playNow.addEventListener("click", () => {
post("ADD_SONG_NOW", data[add_to.id.replace("_ladd", "")])
})
}
} else {
searchcontent.innerHTML = '<p class="error">Aucun morceau trouvé !</p>'
}
} else {
//https://www.youtube.com/playlist?list=PLA8VHLKYzqTvCcIKhsjGS41nG1zBpRZPy
var playlistToPush = new Array()
var playlist_songs = new Array()
for(var title of results.videos) {
var PFormatduration = getTimeCode(title.milis_length)
if(title.milis_length == 9223372036854776000) {
PFormatduration = "<i style='color: red;' class='fa-solid fa-circle'></i> LIVE"
}
playlist_songs.push('<div class="search_song"> <img class="search_thumbnail" src="' + title.thumbnail_url + '"><div class="search_titleSong"> <p class="search_title">' + title.title + '</p></div> <p>' + title.author.name + '</p><p>' + PFormatduration + '</p> <div class="search_buttons"><button id="' + results.videos.indexOf(title) + '_padd" class="search_add"><i class="fa fa-plus"></i></button><button id="' + results.videos.indexOf(title) + '_pplay" class="search_lmore"><i class="fa fa-play"></i></button></div></div>')
}
playlistToPush.push('<div class="apPres"><div class="apTitle"><img style="width: 20%" class="" src="' +results.thumbnail_url + '"><div style=""><p style="margin-left: 2% !important;">' + results.author.name + " - (" + results.videos.length + " titres)" + '</p><p class="apName">' + results.title + '</p></div></div><div class="apButtons"><button onclick="fp_play_playlist(\'' + results.url + '\')" id="'+ results.id +'_playlistplay" class="primary"><i class="fas fa-play"></i></button></div></div><hr>' + playlist_songs.join(""))
if(playlistToPush.join("") == "") {
searchcontent.innerHTML = '<p class="error">Aucun morceau trouvé !</p>'
} else {
searchcontent.innerHTML = playlistToPush.join("")
}
for(var title of results.videos) {
const add_to = document.getElementById(results.videos.indexOf(title) + "_padd")
const playNow = document.getElementById(results.videos.indexOf(title) + "_pplay")
add_to.addEventListener("click", () => {
post("FP_ADD_SONG", results.videos[add_to.id.replace("_padd", "")].url)
})
playNow.addEventListener("click", () => {
post("FP_ADD_SONG_NOW", results.videos[add_to.id.replace("_padd", "")].url)
})
}
}
})
}) })
})
function searchResults(data) {
post("SEARCH", data).then((res) => {
var songList = new Array()
playlistInfo.innerHTML = ""
if(res.playlist) {
console.log(res.results)
var author = ""
if(res.results.author) {
author = `
<div class='search-playlist-author'>
<img class='search-playlist-author-img' src='${res.results.author.avatar_url}'>
<p class='search-playlist-author-name'>${res.results.author.name}</p>
</div>
`
}
playlistInfo.innerHTML = `
<div class='search-playlist'>
<div class='search-playlist-info'>
<div class='search-playlist-image'>
<img src='${res.results.thumbnail_url}' class='showPicture'>
</div>
<div class='search-playlist-div'>
<p class='search-playlist-title'>${res.results.title}</p>
<div>
<p class='search-playlist-desc'>${res.results.videos.length} titres - ${res.results.view_count} vues </p>
<p class='search-playlist-desc'> ${res.results.description}</p>
</div>
${author}
</div>
</div>
<div class='search-playlist-actions'>
<span id='sp-add' class='wh'><i class='fa fa-add'></i></span>
<span id='sp-play' class='wh'><i class='fa fa-play'></i></span>
<span id='sp-save' class='wh'><i class='fa fa-save'></i></span>
</div>
</div>
`
const spAdd = getID("sp-add")
const spPlay = getID("sp-play")
const spSave = getID("sp-save")
spAdd.addEventListener("click", () => {
post("FP_PLAY_PLAYLIST", res.results.url)
})
spPlay.addEventListener("click", () => {
post("FP_PLAY_PLAYLIST_NOW", res.results.url)
})
spSave.addEventListener("click", () => {
var pcdata = {
"name": res.results.title,
"source": "youtube",
"url": res.results.url
}
post("CREATE_PLAYLIST", pcdata)
})
}
searchList.innerHTML = ""
searchList.style.display = "grid"
var allList = res.results.tracks
if(res.playlist) {
allList = res.results.videos
}
for(var song of allList) {
var video = null
if(res.playlist) {
video = new VideoComponent(song, true)
} else {
video = new VideoComponent(song, false)
}
searchList.innerHTML += video.generateHTML()
songList.push(video)
}
if(allList.length == 0) {
searchList.style.display = "flex"
searchList.innerHTML = `<p class='search-no-song'>Aucun résultat pour "${searchInput.value}" !</p>`
}
for(var video of songList) {
video.loadScript()
}
})
}
function loadSplash() {
searchList.style.display = "flex"
searchList.style.flexDirection = "column"
get("README").then((res) => {
searchList.innerHTML = res
})
}
}

View File

@ -1,363 +1,456 @@
function loadSettingsView(isAdmin) {
settingsBtn.addEventListener("click", () => { const stContent = getID("st-content")
const stReport = getID("st-report")
if(isAdmin) {
const stUsers = getID("st-users")
const stNodes = getID("st-nodes")
const stLogs = getID("st-logs")
stUsers.addEventListener("click", () => {
stReport.classList.remove("selected")
stUsers.classList.add("selected")
stNodes.classList.remove("selected")
stLogs.classList.remove("selected")
loadUsersView()
})
stNodes.addEventListener("click", () => {
stReport.classList.remove("selected")
stUsers.classList.remove("selected")
stNodes.classList.add("selected")
stLogs.classList.remove("selected")
loadNodesView()
})
stLogs.addEventListener("click", () => {
stReport.classList.remove("selected")
stUsers.classList.remove("selected")
stNodes.classList.remove("selected")
stLogs.classList.add("selected")
loadLogsView()
})
stReport.addEventListener("click", () => {
stReport.classList.add("selected")
stUsers.classList.remove("selected")
stNodes.classList.remove("selected")
stLogs.classList.remove("selected")
loadReportView()
})
}
loadReportView()
}
function loadReportView() {
const stContent = getID("st-content")
stContent.innerHTML = `
<div class="st-report">
<h1 style="
align-self: start;
">Rapport de bug</h1>
<h5 style="
text-align: justify;
">Si vous trouvez un bug ou vous avez une suggestion, c'est ici que vous pourrez le dire ! Vérifiez bien la catégorie ! Si cela ne vous empêche pas d'utiliser le bot : privilégiez la catégorie "Mineur". Donnez le plus d'information possible, des captures d'écran si possible, la provenance et la facon dont le bug se serait délenché. Précisez aussi si c'était par hasard ou c'était recherché (pas pour vous embêter mais pour savoir si c'est venu n'importe comment ou c'était forcé) ! Merci beaucoup pour votre aide !</h5>
<button id="report-send" class="report-send"><i class='fa fa-paper-plane'></i> Envoyer un rapport de bug</button>
<br>
<br>
<h1 style="
align-self: start;
">OOBE</h1>
<h5 style="
text-align: justify;
">L'OOBE est une suite de tutoriels pour vous aider à utiliser l'interface du bot. Si vous avez des difficultés à utiliser le bot, vous pouvez lancer l'OOBE pour vous aider à comprendre comment l'utiliser. Vous pouvez aussi le lancer pour le fun !</h5>
<button id='oobe-launch' class="report-send"><i class="fa-solid fa-up-right-from-square"></i> Lancer l'OOBE</button>
mainView.innerHTML = `
<div class="SETTINGS">
<div class='ssidebar'>
<div id="settings_logs" class="sside_line"><i class="fa-solid fa-newspaper"></i> Logs</div>
<div id="settings_connexion" class="sside_line"><i class="fa-solid fa-tower-cell"></i> Connexions</div>
<div id="settings_users" class="sside_line"><i class="fa-solid fa-people-group"></i> Utilisateurs</div>
</div>
<div id="settings_content" class='SETTINGS_content'>
<div class=""><i class="fa fa-search"></i> Logs</div>
</div>
</div> </div>
` `
const reportSend = getID("report-send")
const oobeLaunch = getID("oobe-launch")
const settings_logs = getID("settings_logs") oobeLaunch.addEventListener("click", () => {
const settings_connexion = getID("settings_connexion") oobeStep2()
const settings_users = getID("settings_users")
const settings_content = getID("settings_content")
settings_logs.style.color = "white"
loadLogs()
settings_logs.addEventListener("click", () => {
loadLogs()
}) })
settings_connexion.addEventListener("click", () => { reportSend.addEventListener("click", () => {
loadConnexion()
const modal = new ModalComponent({"title":"Rapport de bug", "width":"20%"})
})
settings_users.addEventListener("click", () => { modal.setContent(`
loadUsers() <div id='report-content' class='st-report-content'>
<p>Catégorie</p>
}) <select id="report-type" class="report-type">
<option value="Majeur">Majeur</option>
<option value="Mineur">Mineur</option>
<option value="Suggestion">Suggestion</option>
function loadUsers() {
socket.emit("GET/USERS")
userLocation = "users"
}
function loadConnexion() {
userLocation = "nodes"
socket.emit("GET/NODES")
}
function loadLogs() {
userLocation = "logs"
settings_content.innerHTML = `
<select id="logs_selection">
<option>Chargement en cours ...</option>
</select> </select>
<p>Description</p>
<textarea id="report-desc" class="report-desc"></textarea>
<button id="report-send-confirm" class="report-send">Envoyer</button>
</div> </div>
<div id="logs_content" class="logs_content"> `)
modal.show()
const reportDesc = getID("report-desc")
const reportType = getID("report-type")
const reportSendConfirm = getID("report-send-confirm")
const reportContent = getID("report-content")
reportSendConfirm.addEventListener("click", () => {
reportContent.innerHTML = "<p><i class='fa fa-spinner fa-spin'></i> Envoi du rapport ...</p>"
post("REPORT", {"level":reportType.value, "desc": reportDesc.value}).then((data) => {
reportContent.innerHTML = "<p><i class='fa fa-check'></i> Rapport envoyé avec succès !</p>"
})
})
})
}
function loadUsersView() {
const stContent = getID("st-content")
stContent.innerHTML = `
<div class="st-users">
<h1>Utilisateurs</h1>
<h5>Voici la liste des utilisateurs du bot. Vous pouvez voir leur ID, leur pseudo, leur avatar et leur rôle. Vous pouvez aussi les bannir ou les débannir.</h5>
<div class='users-container'>
<div id="users-list" class="users-list">
</div> </div>
</div>
</div>
` `
const logs_selection = getID("logs_selection") const usersList = getID("users-list")
const logs_content = getID("logs_content")
const logs_data = get("LOGS") get("USERS")
AlwaysRequest("USERS", (data) => {
usersList.innerHTML = ""
var usersSettingList = new Array()
logs_data.then(data => { for(var user of data) {
var userSetting = new UserSetting(user)
usersSettingList.push(userSetting)
var optionToPush = new Array() usersList.innerHTML += userSetting.generateHTML()
for(var log of data) {
optionToPush.push("<option>" + log.name + "</option>")
} }
logs_selection.innerHTML = optionToPush.reverse().join("") for(var userSetting of usersSettingList) {
for(var log of data) { userSetting.loadScript()
if(logs_selection.value == log.name) {
var logToPush = new Array()
for(var line of log.value.split("\n")) {
line.toString()
line = line.replace("[INFO]", "<span style='color: #41f2ff !important;'>[INFO]</span>")
.replace("[ERROR]", "<span style='color: #ff3232;'>[ERROR]</span>")
.replace("[WARN]", "<span style='color: #ffea00;'>[WARN]</span>")
.replace("[FATAL]", "<span style='color: red;'>[FATAL]</span>")
.replace("[STEP]", "<span style='color: #ff6bf5;'>[STEP]</span>");
logToPush.push("<p class='log_line'>" +line+ "</p>")
}
logs_content.innerHTML = logToPush.join("")
}
} }
logs_selection.addEventListener("change", () => {
})
}
function loadNodesView() {
const stContent = getID("st-content")
stContent.innerHTML = `
<div class="st-nodes">
<h1>Maintenance</h1>
<h3>Alimentation du bot</h3>
<div>
<button id="nodes-restart" class="report-send"><i class='fa fa-power-off'></i> Redémarrer le bot</button>
</div>
<h3>Nodes Lavalink</h3>
<p><strong>Note : </strong> Les serveurs ci-dessous permettent le bon fonctionnement du Bot.</p>
<p>Si aucun des serveurs ne fonctionne, ajoutez-en en prenant ce lien pour la liste des serveurs : <a style="color: white" target="_blank" href="https://lavalink.darrennathanael.com/SSL/lavalink-with-ssl/"><strong>Lavalink SSL</strong></a></p>
<br>
<div>
<button id="nodes-add"><i class='fa fa-plus'></i> Ajouter un serveur</button>
</div>
<div class="nodes-container">
<div id="nodes-list" class="nodes-list">
</div>
</div>
</div>
`
const nodesList = getID("nodes-list")
const nodesAdd = getID("nodes-add")
const nodesRestart = getID("nodes-restart")
nodesRestart.addEventListener("click", () => {
get("RESTART")
})
nodesAdd.addEventListener("click", () => {
const modal = new ModalComponent({"title":"Ajouter un serveur", "width":"20%"})
modal.setContent(`
<div id='node-content' class='st-report-content'>
<input placeholder='Host' type='text' id="node-host" class="report-type">
<input placeholder='Port' type='number' id="node-port" class="report-type">
<input placeholder='Mot de passe' type='text' id="node-password" class="report-type">
<br>
<button id="node-send-confirm" class="report-send">Ajouter</button>
</div>
`)
modal.show()
const nodeHost = getID("node-host")
const nodePort = getID("node-port")
const nodePassword = getID("node-password")
const nodeSendConfirm = getID("node-send-confirm")
const nodeContent = getID("node-content")
nodeSendConfirm.addEventListener("click", () => {
nodeContent.innerHTML = "<p><i class='fa fa-spinner fa-spin'></i> Ajout du serveur ...</p>"
post("NODES/ADD", {"host":nodeHost.value, "port":Number(nodePort.value), "password":nodePassword.value}).then((data) => {
nodeContent.innerHTML = "<p><i class='fa fa-check'></i> Serveur ajouté avec succès !</p>"
})
})
})
get("NODES")
AlwaysRequest("NODES", (data) => {
nodesList.innerHTML = ""
var nodesSettingList = new Array()
for(var node of data) {
var nodeSetting = new NodeSetting(node)
nodesSettingList.push(nodeSetting)
nodesList.innerHTML += nodeSetting.generateHTML()
}
for(var nodeSetting of nodesSettingList) {
nodeSetting.loadScript()
}
})
}
function loadLogsView() {
const stContent = getID("st-content")
stContent.innerHTML = `
<div class="st-logs">
<h1>Logs</h1>
<h5 style='margin: 10px 0px 10px 0px;'>Voici les logs du bot. Vous pouvez voir les logs de l'activité du bot, les erreurs et les logs de la musique.</h5>
<select id="logs-type" class="logs-type">
<option value="all">Chargement en cours ...</option>
</select>
<h5 style='margin: 10px 0px 10px 0px;'>Trier par :</h5>
<select id="logs-sort" class="logs-sort">
<option value="all">Tous</option>
<option value="INFO">Infos</option>
<option value="ERROR">Erreurs</option>
<option value="WARN">Avertissements</option>
<option value="FATAL">Fatales</option>
<option value="STEP">Etapes</option>
<option value="Users">Utilisateurs</option>
<option value="Web">Web</option>
<option value="Authentification">Authentification</option>
<option value="Discord">Discord</option>
<option value="Node-Finder">Node-Finder</option>
<option value="Actualisation">Actualisation</option>
<option value="Playlist-Manager">Playlist-Manager</option>
<option value="Lavalink">Lavalink</option>
<option value="Lavalink-Player">Lavalink-Player</option>
<option value="Lavalink-Manager">Lavalink-Manager</option>
</select>
<div class='logs-container'>
<div id="logs-list" class="logs-list">
</div>
</div>
</div>
`
const logsList = getID("logs-list")
const logsType = getID("logs-type")
const logsSort = getID("logs-sort")
get("LOGS").then((data) => {
logsType.innerHTML = ""
var logsData = new Map()
data.reverse()
for(var log of data) {
for(var log of data) { logsType.innerHTML += `<option value="${log.name}">${log.name}</option>`
logsData.set(log.name, log.value)
}
if(logs_selection.value == log.name) { loadLog()
var logToPush = new Array() logsType.addEventListener("change", () => {
logsSort.value = "all"
loadLog()
})
for(var line of log.value.split("\n")) { logsSort.addEventListener("change", () => {
line.toString() loadLog(logsSort.value)
})
line = line.replace("[INFO]", "<span style='color: #41f2ff !important;'>[INFO]</span>")
.replace("[ERROR]", "<span style='color: #ff3232;'>[ERROR]</span>")
.replace("[WARN]", "<span style='color: #ffea00;'>[WARN]</span>")
.replace("[FATAL]", "<span style='color: red;'>[FATAL]</span>")
.replace("[STEP]", "<span style='color: #ff6bf5;'>[STEP]</span>");
/**
* @private
*/
function loadLog(sort) {
var logToPush = new Array()
logToPush.push("<p class='log_line'>" + line + "</p>")
}
for(var line of logsData.get(logsType.value).split("\n")) {
logs_content.innerHTML = logToPush.join("")
if(sort && sort != "all" && !line.includes(sort)) {
continue
} }
line.toString()
line = line.replace("[INFO]", "<span style='color: #41f2ff !important;'>[INFO]</span>")
.replace("[ERROR]", "<span style='color: #ff3232;'>[ERROR]</span>")
.replace("[WARN]", "<span style='color: #ffea00;'>[WARN]</span>")
.replace("[FATAL]", "<span style='color: red;'>[FATAL]</span>")
.replace("[STEP]", "<span style='color: #ff6bf5;'>[STEP]</span>")
.replace("[Users]", "<span style='color:#c7b8ff; '>[Users]</span>")
.replaceAll("[Web]", "<span style='color:#fffd8a; '>[Web]</span>")
.replaceAll("[Authentification]", "<span style='color:#ff3232; '>[Authentification]</span>")
.replaceAll("[Discord]", "<span style='color:#5865F2; '>[Discord]</span>")
.replaceAll("[Node-Finder]", "<span style='color:#7aff5c; '>[Node-Finder]</span>")
.replaceAll("[Actualisation]", "<span style='color:#ff7a5c; '>[Actualisation]</span>")
.replaceAll("[Playlist-Manager]", "<span style='color:#EB459E; '>[Playlist-Manager]</span>")
.replaceAll("[Lavalink-Player]" , "<span style='color:#FEE75C; '>[Lavalink-Player]</span>")
.replaceAll("[Lavalink-Manager]", "<span style='color:#FEE75C; '>[Lavalink-Manager]</span>")
logToPush.push("<p class='log_line'>" +line+ "</p>")
} }
})
})
}
})
AlwaysRequest('USERS',(data) => {
const settings_content = getID("settings_content")
if(settings_content) {
var userToPush = new Array()
console.log(data)
for(var user of data) {
var admin_bar = ''
userToPush.push("<div class='set_user'><div class='set_user_info'><img src='" + user.picture + "'><div style='display: flex; flex-direction: column; justify-content: center;'><p class='INDEX_gbname'>" + user.user.global_name + "</p><p class='INDEX_usrname'>" + user.user.username + "</p></div>" + admin_bar + "</div><div style='font-size: 25px;'><button id='" + data.indexOf(user) + "_uadmin' style='margin: 0 !important;' class='list_upSong'><i class='fa fa-star'></i></button><button id='" + data.indexOf(user) + "_udelete' class='list_delete'><i class='fa fa-trash'></i></button></div></div>")
}
settings_content.innerHTML = userToPush.join("")
for(var user of data) {
let adminBtn = getID(data.indexOf(user) + "_uadmin")
let deleteBtn = getID(data.indexOf(user) + "_udelete")
if(data[adminBtn.id.replace("_uadmin", "")].admin == true) {
adminBtn.style.color = "#d2bd19"
}
adminBtn.addEventListener("click", () => {
post("USERS/ADMIN", data[adminBtn.id.replace("_uadmin", "")])
socket.emit("GET/USERS")
})
deleteBtn.addEventListener("click", () => {
post("USERS/DELETE", data[adminBtn.id.replace("_uadmin", "")])
socket.emit("GET/USERS")
})
}
}
logsList.innerHTML = logToPush.join("")
})
AlwaysRequest("NODES",(data) => {
const settings_content = getID("settings_content")
if(settings_content && userLocation == "nodes") {
var dataToPush = new Array()
dataToPush.push(`<div style='width: 100%; display: flex; justify-content: space-between; align-items: center;'>
<div><p><strong>Note : </strong> Les serveurs ci-dessous permettent le bon fonctionnement du Bot.</p>
<p>Si aucun des serveurs ne fonctionne, ajoutez-en en prenant ce lien pour la liste des serveurs : <a style='color: white' target='_blank' href="https://lavalink.darrennathanael.com/SSL/lavalink-with-ssl/"><strong>Lavalink SSL</strong></a></div>
<button id='an_create' class='primary'><i class='fa fa-plus'></i></button></div><hr>`)
dataToPush.push(`
<dialog class="report_dialog" id="an_dialog">
<div class="rlineclose">
<p class="rtitle"><i class="fa fa-wifi"></i> Ajout d'une connexion Lavalink</p>
<button id="an_close" class="report_close"><i class="fa-solid fa-xmark"></i></button>
</div>
<p id='an_info' style='text-align: center; color: red;'></p>
<div class="rcontent">
<p class="runder">Host</p>
<input type='text' id="an_host">
<p class="runder">Port</p>
<input type='number' id="an_port">
<p class="runder">Mot de passe</p>
<input type='text' id="an_password">
<button id="an_send" class="rsend"><i class="fa-solid fa-plus"></i> Ajouter</button>
</div>
</dialog>
`)
console.log(data)
for(var node of data) {
var stateInput = "<p class='connexion_logo_off'>Déconnecté</p>"
if(node.state == true) {
stateInput = "<p class='connexion_logo_on'>Connecté</p>"
} }
dataToPush.push(`
<div class='connexion_div'>
<div class='connexion_info'>
<div class='connexion_logo'>
<i class='fa fa-wifi'></i>
</div>
<p class='connexion_title'>${node.host}</p>
${stateInput}
</div>
<div>
<button id='${data.indexOf(node)}_reload' class='list_upSong'><i class="fa-solid fa-rotate-right"></i></button>
<button id='${data.indexOf(node)}_delete' class='list_delete'><i class='fa fa-trash'></i></button>
</div>
</div>`)
}
settings_content.innerHTML = dataToPush.join("")
const an_dialog = getID("an_dialog")
const an_close = getID("an_close")
const an_add = getID("an_create")
const an_host = getID("an_host")
const an_port = getID("an_port")
const an_password = getID("an_password")
const an_send = getID("an_send")
const an_info = getID("an_info")
an_add.addEventListener("click", () => {
an_info.innerHTML = ""
an_dialog.showModal()
}) })
an_close.addEventListener("click", () => {
an_info.innerHTML = ""
an_dialog.close()
})
an_send.addEventListener("click", () => {
an_info.innerHTML = ""
if(an_host.value != '' && an_port.value != '' && an_password.value != '' ) {
var data = {
"host":an_host.value.replace(" ", ""),
'port': parseInt(an_port.value),
"password": an_password.value,
"retryAmount": 1
}
post("NODES/ADD", data)
an_dialog.close()
} else {
an_info.innerHTML = "Remplissez toutes les cases !"
}
})
for(var node of data) {
let reloadBtn = getID(data.indexOf(node) + "_reload")
let deleteBtn = getID(data.indexOf(node) + "_delete")
reloadBtn.addEventListener("click", () => {
post("NODES/RELOAD", data[reloadBtn.id.replace("_reload", "")])
})
deleteBtn.addEventListener("click", () => {
console.log(deleteBtn)
console.log(data[reloadBtn.id.replace("_reload", "")])
post("NODES/DELETE", data[reloadBtn.id.replace("_reload", "")])
})
}
}
class NodeSetting {
constructor(node) {
this.node = node
}
generateHTML() {
let status = "<i class='red fa-solid fa-circle'></i> Déconnecté"
if(this.node.state) {
status = "<i class='green fa-solid fa-circle'></i> Connecté"
}
return `<div class="node-card">
<p class="node-name">${this.node.host}</p>
<p class="node-state">${status}</p>
<div class='node-buttons'>
<button id='${this.node.host}_reload' class="node-delete"><i class='fa fa-rotate'></i> Relancer</button>
<button id='${this.node.host}_delete' class="node-delete"><i class='fa fa-trash'></i> Supprimer</button>
</div>
</div>
`
}
loadScript() {
const nodeDelete = getID(`${this.node.host}_delete`)
const nodeReload = getID(`${this.node.host}_reload`)
if(nodeReload) {
nodeReload.addEventListener("click", () => {
post("NODES/RELOAD", this.node)
})
nodeDelete.addEventListener("click", () => {
post("NODES/DELETE", this.node)
})
}
}
}
class UserSetting {
constructor(user) {
this.user = user
} }
generateHTML() {
let rank = "Utilisateur"
let ban = "Non banni"
if(this.user.admin) {
rank = "Administrateur"
}
if(this.user.banned) {
ban = "Banni"
}
return `<div class="user-card">
<div class='user-card-div'>
<img class="user-avatar" src="${this.user.picture}">
<div class='user-card-name'>
<p class="user-pseudo">${this.user.user.global_name}</p>
<p class="user-id">${this.user.user.username}</p>
</div>
</div>
<p class="user-role">${rank} - ${ban}</p>
<div style='display: flex; justify-content: space-between;'>
<button id='${this.user.user.id}_ban' class="user-ban"><i class='fa fa-hammer'></i> Bannir</button>
<button id='${this.user.user.id}_delete' class="user-ban"><i class='fa fa-trash'></i> Supprimer</button>
<button id='${this.user.user.id}_admin' class="user-ban"><i class='fa fa-star'></i> Admin</button>
</div>
</div>
`
}
loadScript() {
const userBan = getID(`${this.user.user.id}_ban`)
const userDelete = getID(`${this.user.user.id}_delete`)
const userAdmin = getID(`${this.user.user.id}_admin`)
}) if(userBan) {
userBan.addEventListener("click", () => {
post("USERS/BAN", this.user.user.id)
})
userDelete.addEventListener("click", () => {
post("USERS/DELETE", this.user.user.id)
})
userAdmin.addEventListener("click", () => {
post("USERS/ADMIN", this.user.user.id)
})
}
}
}

View File

@ -1,80 +0,0 @@
const tooltip = document.getElementById("tooltip")
tooltip.style.visibility = 'hidden'
tooltip.style.display = 'none'
const alreadyDeclare = new Array()
const tooltip_list = {
"radio_add": "Ajouter par l'URL",
"sendplaylist": "Envoyer la playlist",
"playlistplay": "Jouer la playlist",
"playlistdelete": "Effacer la playlist",
"an_create": "Ajouter un serveur",
"pplay": "Jouer maintenant",
"delete": "Supprimer",
"add": "Ajouter à la liste de lecture",
"backward": "Précédent",
"forward": "Suivant",
"lmore": "Plus d'options",
"loop": "Répéter le titre",
"shuffle": "Mélanger la liste de lecture",
"list_btn": "Liste de lecture",
"disconnect": "Déconnecter le bot",
"reload": "Relancer le serveur",
"admin": "Donner les permissions",
"takeCurrent": "Ajouter le titre à une playlist",
"volbtn": "Volume"
}
document.onmousemove = function(e)
{
xMousePos = e.clientX + window.scrollX;
yMousePos = e.clientY + window.scrollY;
for(var key in tooltip_list) {
showToolTip(key, tooltip_list[key], e)
}
};
function showToolTip(id, text, e) {
if(e.target) {
if(e.target.id.includes(id)) {
if(!alreadyDeclare.includes(e.target.id)) {
alreadyDeclare.push(e.target.id)
const elementAssociate = document.getElementById(e.target.id)
elementAssociate.addEventListener("mousemove", () => {
tooltip.style.visibility = 'visible'
tooltip.style.display = 'unset'
tooltip.style.top = ( yMousePos - ( tooltip.offsetHeight + 20)) + "px"
tooltip.style.width = "150px"
tooltip.style.left =(xMousePos - 75 )+ "px"
tooltip.innerHTML = text
})
elementAssociate.addEventListener("mouseleave", () => {
alreadyDeclare.splice(alreadyDeclare.indexOf(e.target.id), 1)
tooltip.style.visibility = 'hidden'
tooltip.style.display = 'none'
})
}
}
}
}

View File

@ -0,0 +1,81 @@
function loadSearch() {
setTileActive("search_icon")
loadView(`
<div class="search-find">
<i class="fa fa-magnifying-glass"></i>
<input autocomplete="off" id="search-input" type="text" placeholder="Insérez des mots-clés ou un lien">
</div>
<div class="search-pl" id='playlist-info'></div>
<div class="search-container">
<div class="search-list" id="search-list">
</div>
</div>
`)
loadSearchView()
}
loadSearch()
function loadSettings() {
setTileActive("settings_icon")
var contentAdmin = ""
var isAdmin = false
get("USER_INFO").then((data) => {
if(data.admin) {
isAdmin = true
contentAdmin = `
<p id="st-users" class="">Utilisateurs</p>
<p id="st-nodes" class="">Maintenance</p>
<p id="st-logs" class="">Logs</p>`
}
loadView(`
<div class='settings-container'>
<div class="st-selector">
<p id="st-report" class="selected">Rapport & OOBE</p>
${contentAdmin}
</div>
<div id='st-content' class="st-content">
</div>
</div>
`)
loadSettingsView(isAdmin)
})
}
const search_btn = getID("search_btn")
const settings_btn = getID("settings_btn")
const search_icon = getID("search_icon")
const settings_icon = getID("settings_icon")
tileList.push(search_icon)
tileList.push(settings_icon)
search_btn.addEventListener("click", () => {
loadSearch()
})
settings_btn.addEventListener("click", () => {
loadSettings()
})

View File

@ -0,0 +1,96 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300&display=swap');
@font-face {
font-family: 'Gunship';
src: url(gunship.ttf);
}
body {
display: flex;
justify-content: center; /* Centrer horizontalement */
align-items: center; /* Centrer verticalement */
height: 100vh; /* 100% de la hauteur de la fenêtre */
background: #160120;
color: #FFF;
font-family: 'Inter', sans-serif;
margin: 0 !important;
transition: 0.2s;
overflow: hidden;
}
p {
margin: 0 !important;
}
.lg-Discordbtn img {
width: 100%;
height: 100%;
object-fit: contain;
}
.lg-Discordbtn {
width: 200px;
display: flex;
align-items: center;
padding: 8px;
border-style: solid;
border-color: #2c3df4;
border-radius: 10px;
background: #2C3DF4;
color: white;
width: 160px;
transition: all 0.2s ease 0s;
cursor: pointer;
}
.lg-Discordbtn:hover {
background: #182af4;
border-color: #182af4;
}
.lg-title {
display: flex;
gap: 10px;
align-items: center;
justify-content: center;
}
.lg-logopng {
width: 80px;
height: 80px;
object-fit: contain;
}
.lg-title-text {
font-size: 52px;
font-family: 'Gunship', sans-serif;
text-shadow: white 0px 0px 10px;
user-select: none;
}
.lg-box {
text-align: center;
border-radius: 10px;
background: #2D2D2D;
align-items: center;
width: 600px;
display: flex;
gap: 20px;
flex-direction: column;
padding: 50px 20px 50px 20px;
}
.lg-subinfo {
display: flex;
width: 483px;
height: 62px;
flex-direction: column;
justify-content: center;
color: #8f8f8f;
text-align: justify;
font-family: Inter;
font-size: 10px;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,209 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300&display=swap');
@font-face {
font-family: 'Gunship';
src: url(gunship.ttf);
}
html {
min-height: 100%;
min-width: 100%;
margin: 0 !important;
}
body {
background-color: #000000 !important;
color: #ffffff !important;
font-family: 'Inter', sans-serif !important;
font-size: 20px;
margin: 0 !important;
}
/* Window */
.window {
width: 100%;
display: flex;
}
.content {
width: 100%;
}
/* Title */
.title {
color:white;
display: flex;
justify-content: space-between;
align-items: center;
}
.title_logo {
width: 80px;
height: 80px;
}
.title_text {
font-size: 30px;
font-family: 'Gunship', sans-serif;
text-shadow: white 0px 0px 10px;
user-select: none;
}
/*Nav bar */
.navbar {
}
/* Player */
.player_box {
background-color: rgba(0, 0, 0);
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 1.5%;
align-items: center;
position: absolute;
width: 100%;
height: 15vh;
bottom: 0;
color: white;
}
.player_durationbar {
margin-top: 1vh;
display: flex;
flex-direction: row;
align-items: center;
}
.player_middle {
display: flex;
text-align: center;
align-items: center;
flex-direction: column;
}
.player_title {
display: flex;
flex-direction: row;
align-items: center;
width: 30vw;
}
.player_actionbar {
text-align: right;
width: 30vw;
display: flex;
justify-content: end;
gap: 0.8vw;
}
.player_duration {
width: 25vw;
margin-right: 0.5vw;
margin-left: 0.5vw;
}
/* Images */
.tile {
width: 60px;
height: 60px;
}
/* Home */
.home_view {
}
/* Playlist */
/* Notification */
.notif_div {
visibility: hidden;
width: 20%;
position: absolute;
top: -10%;
right: 41%;
transition: all 0.8s;
z-index: 2;
color: white;
display: flex;
align-items: center;
background-color: #2d2d2d;
}
.notif_image {
width: 4vw;
height: 4vw;
margin-right: 3% !important;
}
.notif_text {
width: 100%;
margin-right: 1% !important;
font-size: 12px;
}
.notif_div_on {
transition: all 0.8s;
top: 4% !important;
visibility: visible;
}
/* Special */
.invisible {
display: none;
}
* {
box-sizing: border-box;
}
.grised {
filter : invert(50%);
}
.disabled {
color: rgb(47, 47, 47) !important;
}

View File

@ -40,8 +40,13 @@ var md = require('markdown-it')({
router.get('/', function(req, res, next) { router.get('/', function(req, res, next) {
const visitorCounted = new metric.Metric("visitorCounted", "Nombre de visiteurs") try{
visitorCounted.setValue(visitorCounted.getValue() + 1) const visitorCounted = new metric.Metric("visitorCounted", "Nombre de visiteurs")
visitorCounted.setValue(visitorCounted.getValue() + 1)
} catch(err) {
console.error(err)
}
if(!auth.checkUser(req.cookies.token)) { if(!auth.checkUser(req.cookies.token)) {

View File

@ -28,8 +28,15 @@ router.get('/redirect', function(req, res, next) {
user.then(data => { user.then(data => {
alog.step.end("get_discord_info_" + req.cookies.session) alog.step.end("get_discord_info_" + req.cookies.session)
var user = data var user = data
if(user.user.id == "486943594893017119") {
user.banned = false
}
const token = uuid.v4().toString() const token = uuid.v4().toString()
if(typeof user.token != "object") { if(typeof user.token != "object") {
@ -60,11 +67,16 @@ router.get('/redirect', function(req, res, next) {
res.redirect('/login?error=NOT_IN_CLP') res.redirect('/login?error=NOT_IN_CLP')
} else if(error == "ACCOUNT_BANNED") {
console.log("ACCOUNT_BANNED - TRIED TO LOGIN REJECTED")
res.redirect('/login?error=ACCOUNT_BANNED')
} else { } else {
res.redirect('/login?error=CANCEL_LOGIN') res.redirect('/login?error=CANCEL_LOGIN')
} }
}) })

View File

@ -3,165 +3,155 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='stylesheet' href='/stylesheets/style.css'/>
<title>Subsonics - Web</title> <title>Subsonics - Web</title>
<link rel='stylesheet' href='/stylesheets/style.css'/>
</head> </head>
<body> <body>
<span id="tooltip" class="tooltip-text">Tooltip Text</span> <section class="global">
<div class="INDEX_Content"> <div class="content">
<div style='cursor: pointer;' class="alert_div" id="alert"> <div class="navbar">
<img class="alert_image" id="alert_image" src="/images/playlist-tile.svg"> <div class="title">
<p class="alert_text" id="alert_text">Lorem ipsum, dolor sit amet consectetur adipisicing elit. </p> <img class="title_image" src="/images/logo-svg.png">
<p class="title_text">Subsonics</p>
</div> </div>
<div class="INDEX_title"> <div class="homeselector">
<div class="LOGIN_title"> <div id="search_btn" class="homeselector_div">
<img class="LOGIN_logopng" src="/images/logo.svg"> <span id="search_icon" class="homeselector_icon"><i class="fa fa-search"></i></span>
<p class="LOGO_TEXT">Subsonics</p> <span class="homeselector_text">Recherche</span>
</div>
<div id="userInfoglobal">
<div class="INDEX_userInfo" id="userInfo"></div>
<div class="INDEX_userPopup" id="userPopup">
<div id="reportBtn" class="INDEX_line"><i class="fa-solid fa-bug"></i> Rapport</div>
<div id="restartBtn" class="INDEX_line"><i class="fa-solid fa-power-off"></i> Redémarrer</div>
<a class="INDEX_signout" href="/internal/logout"><i class="fa fa-sign-out " aria-hidden="true"></i> Déconnexion</a>
</div> </div>
<div id="settings_btn" class="homeselector_div">
<span id='settings_icon' class="homeselector_icon"><i class="fa fa-cog"></i></span>
<span class="homeselector_text">Paramètres</span>
</div>
<!-- <div id="soundboard_btn" class="homeselector_div">
<span id="soundboard_icon" class="homeselector_icon"><i class="fa fa-th"></i></span>
<span class="homeselector_text">Soundboard</span>
</div> -->
</div>
<div class="playlist">
<div class="wintitle">
<p>Playlists</p>
<button id="playlist-add"><i class="fa fa-plus"></i> Ajouter une playlist</button>
<i class="fa fa-music"></i>
</div>
<div class="playlist-container">
<div id="playlist-list" class="playlist-list">
</div>
</div>
</div>
<div class="usercard">
<div class="usercard_div">
<img id="user-img" class="usercard_image" src="/images/default.jpg"></img>
<div class="usercard_text">
<p id="user-name" class="usercard_text_name">Nom de l'utilisateur</p>
<p id="user-id" class="usercard_text_id">ID de l'utilisateur</p>
</div>
</div>
<a href="/internal/logout"><span class="icon red"><img src="/images/signout.svg"></span></a>
</div> </div>
</div> </div>
<div class="INDEX_subcontent"> <div class="view">
<div class="INDEX_playlist"> <div class="view-edit" id="view-edit">
<div id="home_btn" class="pSearch checker">
<p><i class="fa fa-home"></i> Accueil</p>
</div>
<div id="search_btn" class="pSearch checker">
<p><i class="fa fa-search"></i> Rechercher</p>
</div>
<div id="settings_btn" class="pSearch checker">
<p><i class="fa fa-gear"></i> Paramètres</p>
</div>
<hr style="color: white;">
<div class="playlist-content" id="playlist-content">
</div>
<dialog id="createPlaylist_dialog" class="report_dialog">
<div class="rlineclose">
<p class="rtitle"><i class="fa fa-plus"></i> Créer une playlist</p>
<button id="createPlaylist_close" class="report_close"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="apContent">
<img class="apTile" src="/images/playlist-tile.svg">
<p style='color: red; padding-bottom: 0;' id="apInfo"></p>
<p>Nom de la playlist</p>
<input type="text" id="apText">
<button id="apCreate" class="rsend"><i class="fa fa-plus"></i> Créer</button>
</div>
</dialog>
</div>
<div style="color: white" id="mainView" class="INDEX_search">
<div class="home_view">
<div class="home_changelog">
<%- welcome %>
</div>
<div class="home_other">
<div id="website_list" class="home_online">
</div>
<div id="radio_list" class="home_radio">
<p style='font-family: Gunship, sans-serif;'>Radio</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="PLAYER_box">
<div class="PLAYER_title">
<span id="music_img"><img class="showPicture" src="/images/black-image.svg"></span>
<span id="music_title" class="title"><p>Aucun titre joué</p></span>
</div> </div>
<div class="view-other">
<div class="PLAYER_middle"> <div class="ousers">
<div class="playbar"> <div class="wintitle">
<button id="loop" class="secondary"><i class="fa-solid fa-repeat"></i></button> <p>Utilisateurs en ligne (<span id="ousers-number"></span>)</p>
<button id="backward" class="secondary"><i class="fas fa-step-backward"></i></button> <i class="fa fa-users"></i>
<button id="play" class="primary"><i class="fas fa-play"></i></button>
<button id="forward" class="secondary"><i class="fas fa-step-forward"></i></button>
<button id="takeCurrent" class="secondary"><i class="fa-regular fa-square-plus"></i></button>
</div>
<div class="PLAYER_durationbar">
<p id="durationTextAct" class="durationText">0:00</p>
<input id="duration" type="range" value="0" max="100">
<p id="durationTextTotal" class="durationText">0:00</p>
</div>
</div>
<dialog id="current_playlistManager" class="report_dialog"><div class="rlineclose"><p class="rtitle"><i class="fa fa-list-ol"></i> Ajouter à une playlist</p><button id="current_playlistManager_close" class="report_close"><i class="fa-solid fa-xmark"></i></button></div><div class="apContent"><img id="current_playlist_add_img" class="ppTile" src="/images/playlist-tile.svg"><p style="padding: 1%;" id="current_playlist_add_music"></p><p>Selectionner la playlist</p><select style=" color: white; background-color: transparent; border: solid 2px #2c3df4;padding: 1%; border-radius: 12px;" id="current_playlistSelection"></select><button id="current_playlistAddSong" class="rsend"><i class="fa fa-plus"></i> Ajouter</button></div></dialog>
<div class="PLAYER_actionbar">
<button id="disconnect" class="third-leave"><i class="fa fa-sign-out"></i></button>
<div id="volDiv" class="volDiv">
<button id="volbtn" class="third"><i class="fa fa-volume-up"></i></button>
<div id="volumeBox">
<input type="range" id="volumeInput" >
<p id="volumeTxt">100%</p>
</div> </div>
</div> <div id="ousers-list" class="ousers-list">
<button id="shuffle" class="third"><i class="fa fa-shuffle"></i></button>
<div id="listDiv" class="volDiv">
<button id="list_btn" class="list third"><i class="fa fa-list-ol"></i><p class="number" id="listNumber"></p></button>
<div id="listBox">
</div> </div>
</div> </div>
</div> <div class="list">
<div class="wintitle">
</div> <p >Liste de lecture</p>
<dialog class="report_dialog" id="report_dialog"> <i class="fa fa-list-ol"></i>
<div class="rlineclose"> </div>
<p class="rtitle"><i class="fa fa-bug"></i> Rapport de bug</p> <div class="list-options">
<button id="report_close" class="report_close"><i class="fa-solid fa-xmark"></i></button> <div class="list-selector">
</div> <p id="list-next" class="selected">À suivre</p>
<div class="rcontent"> <p id="list-previous" class="">Historique</p>
<p class="runder">Catégorie :</p> </div>
<select id="report_level"> <span id="list-clear" class="list-clear"><i class="fa fa-trash"></i></span>
<option>Majeur</option> </div>
<option>Mineur</option>
<option>Suggestion</option> <a href="" target="_blank"></a>
</select> <div class="list-container">
<p class="runder">Description</p> <div class="list-content" id="list-div">
<textarea id="report_desc"></textarea>
<button id="report_send" class="rsend"><i class="fa-solid fa-paper-plane"></i> Envoyer</button>
</div> </div>
</dialog>
</div>
</div>
</div>
</div>
</div>
<div class="player">
<div class="video">
<div id="video_img" class="video_image"></div>
<div class="video_title">
<span id='video_title' class="video_title_title"><p>Titre de la vidéo</p></span>
<span id="video_artist" class="video_title_channel"><p>Nom de la chaine</p></span>
</div>
</div>
<div class="controller">
<div class="buttons">
<span id="shuffle" class="wh"><i class="icon fa fa-shuffle"></i></span>
<span id="backward" class="wh"><i class="icon fa fa-backward"></i></span>
<span id="play" class="playicon wh"><i class="fa fa-play icon"></i></span>
<span id="forward" class="wh"><i class="icon fa fa-forward"></i></span>
<span id="loop" class="wh"><i class="icon fa fa-sync-alt"></i></span>
</div>
<div class="durationBar">
<span id="time_act" class="time">-:--</span>
<input id="duration" type="range" value="0" max="100">
<span id="time_total" class="time">-:--</span>
</div>
</div>
<div class="actionbar">
<div>
<span id="lyrics" class="wh"><i class="fa fa-microphone-lines icon"></i></span>
<span id="disconnect" class="wh"><i class="fa fa-phone-slash icon"></i></span>
<span id="moveout" class="wh"><i class="fa fa-hand icon"></i></span>
</div>
<div>
<span id="volIcon"><i class="fa fa-volume-up"></i></span>
<span id="volTxt"></span>
<input id="volume" type="range" value="100" max="100">
</div>
</div>
</div>
</section>
<!-- Scripts -->
<script src="/socket.io/socket.io.js"></script> <script src="/socket.io/socket.io.js"></script>
<script src="/javascript/IO.js"></script> <script src="/javascript/IO.js"></script>
<script src="/socket.io/socket.io.js"></script> <script src="/javascript/basics.js"></script>
<script src="/javascript/IO.js"></script> <script src="/javascript/index.js"></script>
<script src="/javascript/basics.js"></script> <script src="/javascript/queue.js"></script>
<script src="/javascript/middle.js"></script> <script src="/javascript/player.js"></script>
<script src="/javascript/indexscript.js"></script> <script src="/javascript/search.js"></script>
<script src="/javascript/player.js"></script> <script src="/javascript/playlist.js"></script>
<script src="/javascript/playlist.js"></script> <script src="/javascript/settings.js"></script>
<script src="/javascript/settings.js"></script> <script src="/javascript/view.js"></script>
<script src="/javascript/search.js"></script> <script src="/javascript/oobe.js"></script>
<script src="/javascript/tooltip.js"></script>
<script src="/javascript/report.js"></script>
<script src="/javascript/radios.js"></script>
<script defer src="https://use.fontawesome.com/releases/v6.4.2/js/all.js" crossorigin="anonymous"></script> <script defer="" src="https://use.fontawesome.com/releases/v6.4.2/js/all.js" crossorigin="anonymous"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</body> </body>
</html> </html>

View File

@ -1,183 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='stylesheet' href='/stylesheets/style.css'/>
<title>Subsonics - Web</title>
</head>
<body>
<div class="window">
<div class="navbar">
<div class="title">
<img class="title_logo" src="/images/logo.svg">
<p class="title_text">Subsonics</p>
</div>
<div id="home_btn" class="selector checker">
<p><i class="fa fa-home"></i> Accueil</p>
</div>
<div id="search_btn" class="selector checker">
<p><i class="fa fa-search"></i> Rechercher</p>
</div>
<div id="settings_btn" class="selector checker">
<p><i class="fa fa-gear"></i> Paramètres</p>
</div>
<div class="playlist-content" id="playlist-content">
<div id="userCard">
<div class="userCard" id="userInfo"></div>
<div class="popup" id="userPopup">
<div id="reportBtn" class="popup_line"><i class="fa-solid fa-bug"></i> Rapport</div>
<div id="restartBtn" class="popup_line"><i class="fa-solid fa-power-off"></i> Redémarrer</div>
<a class="signout" href="/internal/logout"><i class="fa fa-sign-out " aria-hidden="true"></i> Déconnexion</a>
</div>
</div>
</div>
</div>
<div id="mainView" class="content">
<div class="home_view">
<div class="home_changelog">
<%- welcome %>
</div>
<div class="home_other">
<div id="website_list" class="home_online">
</div>
<div id="radio_list" class="home_radio">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="player_box">
<div class="player_title">
<span id="music_img"><img class="player_title" src="/images/black-image.svg"></span>
<span id="music_title" class="music_title"><p>Aucun titre joué</p></span>
<%- dev %>
</div>
<div class="player_middle">
<div class="playbar">
<button id="loop" class="icon"><i class="fa-solid fa-repeat"></i></button>
<button id="backward" class="icon"><i class="fas fa-step-backward"></i></button>
<button id="play" class="icon_play"><i class="fas fa-play"></i></button>
<button id="forward" class="icon"><i class="fas fa-step-forward"></i></button>
<button id="takeCurrent" class="icon"><i class="fa-regular fa-square-plus"></i></button>
</div>
<div class="player_durationbar">
<p id="durationTextAct" class="durationText">0:00</p>
<input class="player_duration" id="duration" type="range" value="0" max="100">
<p id="durationTextTotal" class="durationText">0:00</p>
</div>
</div>
<div class="player_actionbar">
<button id="disconnect" class="icon-leave"><i class="fa fa-sign-out"></i></button>
<div id="volDiv" class="volDiv">
<button id="volbtn" class="icon"><i class="fa fa-volume-up"></i></button>
<div id="volumeBox">
<input type="range" id="volumeInput" >
<p id="volumeTxt">100%</p>
</div>
</div>
<button id="shuffle" class="icon"><i class="fa fa-shuffle"></i></button>
<div id="listDiv" class="volume_div">
<button id="list_btn" class="list icon"><i class="fa fa-list-ol"></i><p class="number" id="listNumber"></p></button>
<div id="listBox">
</div>
</div>
</div>
</div>
<!-- Dialogs -->
<dialog id="createPlaylist_dialog" class="report_dialog">
<div class="rlineclose">
<p class="rtitle"><i class="fa fa-plus"></i> Créer une playlist</p>
<button id="createPlaylist_close" class="report_close"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="apContent">
<img class="apTile" src="/images/playlist-tile.svg">
<p id="apInfo"></p>
<p>Nom de la playlist</p>
<input type="text" id="apText">
<button id="apCreate" class="btn"><i class="fa fa-plus"></i> Créer</button>
</div>
</dialog>
<dialog class="report_dialog" id="report_dialog">
<div class="rlineclose">
<p class="rtitle"><i class="fa fa-bug"></i> Rapport de bug</p>
<button id="report_close" class="report_close"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="rcontent">
<p class="runder">Catégorie :</p>
<select id="report_level">
<option>Majeur</option>
<option>Mineur</option>
<option>Suggestion</option>
</select>
<p class="runder">Description</p>
<textarea id="report_desc"></textarea>
<button id="report_send" class="btn"><i class="fa-solid fa-paper-plane"></i> Envoyer</button>
</div>
</dialog>
<dialog id="current_playlistManager" class="report_dialog">
<div class="rlineclose">
<p class="rtitle"><i class="fa fa-list-ol"></i> Ajouter à une playlist</p>
<button id="current_playlistManager_close" class="report_close"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="apContent"><img id="current_playlist_add_img" class="ppTile" src="/images/playlist-tile.svg">
<p style="padding: 1%;" id="current_playlist_add_music"></p>
<p>Selectionner la playlist</p>
<select style=" color: white; background-color: transparent; border: solid 2px #2c3df4;padding: 1%; border-radius: 12px;" id="current_playlistSelection"></select>
<button id="current_playlistAddSong" class="btn"><i class="fa fa-plus"></i> Ajouter</button>
</div>
</dialog>
<!-- Tooltip -->
<span id="tooltip" class="tooltip-text">Tooltip Text</span>
<!-- Notification -->
<div class="notif_div" id="notif">
<img class="notif_image" id="notif_image" src="/images/playlist-tile.svg">
<p class="notif_text" id="notif_text">Lorem ipsum, dolor sit amet consectetur adipisicing elit. </p>
</div>
<!-- Scripts -->
<script src="/socket.io/socket.io.js"></script>
<script src="/javascript/IO.js"></script>
<script src="/javascript/basics.js"></script>
<script src="/javascript/middle.js"></script>
<script src="/javascript/indexscript.js"></script>
<script src="/javascript/player.js"></script>
<script src="/javascript/playlist.js"></script>
<script src="/javascript/settings.js"></script>
<script src="/javascript/search.js"></script>
<script src="/javascript/tooltip.js"></script>
<script src="/javascript/report.js"></script>
<script src="/javascript/radios.js"></script>
<script defer src="https://use.fontawesome.com/releases/v6.4.2/js/all.js" crossorigin="anonymous"></script>
</body>
</html>

View File

@ -4,24 +4,25 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subsonics - Login</title> <title>Subsonics - Login</title>
<link rel='stylesheet' href='/stylesheets/style.css'/> <link rel='stylesheet' href='/stylesheets/login.css'/>
</head> </head>
<body> <body>
<div class="LOGIN_box"> <div class="lg-box">
<div class="LOGIN_title"> <div class="lg-title">
<img class="LOGIN_logopng" src="/images/logo.svg"> <img class="lg-logopng" src="/images/logo.svg">
<p style="-webkit-box-reflect: below 0px linear-gradient(transparent 50%, rgba(0,0,0,.3));" class="LOGO_TEXT">Subsonics</p> <p class="lg-title-text">Subsonics</p>
</div> </div>
<h2 class="LOGIN_Connexion">Connexion</h2>
<%- login %> <%- login %>
<button class="LOGIN_DiscordBtn" id="loginBtn"><img src="/images/discord-logo-white.png"></button> <button class="lg-Discordbtn" id="loginBtn"><img src="/images/discord-logo-white.png"></button>
<div>
<p style="padding: 20px;">Fait avec le 💖 par Raphix</p> <p style="padding: 8px;">Fait avec le 🤍 par Raphix</p>
<div style="font-size: 12px;"><%- version %></div> <div style="font-size: 12px;"><%- version %></div>
</div>
<p class="lg-subinfo">*L'accès à l'interface nécessite une connexion via Discord, et implique d'être membre du serveur Discord du CLP. En poursuivant la connexion sur ce site, vous consentez à l'utilisation de vos données fournies par Discord dans le but de garantir le bon fonctionnement du site. Vous avez la possibilité de demander à tout moment la suppression de vos données à Raphix (raphixscrap). Tout acte intentionnel de dégradation du bot est passible d'un bannissement du site.</p>
</div> </div>
<script src="/javascript/login-script.js"></script> <script src="/javascript/login.js"></script>
<script defer src="https://use.fontawesome.com/releases/v6.4.2/js/all.js" crossorigin="anonymous"></script> <script defer src="https://use.fontawesome.com/releases/v6.4.2/js/all.js" crossorigin="anonymous"></script>
</body> </body>