From 7c9ab231bcd2e05104a5e0c67ee7ee8711475aed Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sun, 29 May 2022 19:28:04 +0700 Subject: [PATCH 01/27] 2.0 ? --- Indo.md | 81 +++++++++++ README.md | 136 +++++++----------- config.yml | 83 ++++++----- events/ready.js | 308 +++------------------------------------- handlers/checkStatus.js | 125 ++++++++++++++++ handlers/postStatus.js | 153 ++++++++++++++++++++ index.js | 56 ++++++-- package.json | 15 +- 8 files changed, 529 insertions(+), 428 deletions(-) create mode 100644 Indo.md create mode 100644 handlers/checkStatus.js create mode 100644 handlers/postStatus.js diff --git a/Indo.md b/Indo.md new file mode 100644 index 0000000..74b6970 --- /dev/null +++ b/Indo.md @@ -0,0 +1,81 @@ +
+ +![PteroStats Banner](https://cdn.discordapp.com/attachments/626755594526916629/978478722489393153/20220524_090325.png) + +## Bahasa / Language +[[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.MD) | [[Inggris]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) + +
+ +## Pengenalan +PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl dan dikirim ke server discord + +## Instalasi + +### Mendapatkan apikey dari pterodactyl +- Pergi ke `panel admin pterodactyl` dan pergi ke `Application API` + + ![Idk](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) + +- Klik tombol `Create New` + + ![Admin Panel](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) + +- Set semua permission ke `read` dan untuk description kamu bisa mengisi apa saja + + ![Application API](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) + +- Copy apikey-nya. + + ![Copy the apikey](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) + +### Membuat Discord Bot +Kalian bisa cek [website ini](https://discordjs.guide/preparations/setting-up-a-bot-application.html) + +### Menginvite Discord Bot +Kalian bisa cek [website ini](https://discordjs.guide/preparations/adding-your-bot-to-servers.html) + +### Mendapatkan Channel ID +1. Aktifkan `Developer Mode` di settings discord kamu + + ![User Settings](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) + +2. Copy Channel ID-nya + + ![Channel ID](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) + +### Memulai Bot +- Masukan `token` bot discord di `line token` yang terdapat di file `config.yml` +- Copy `id channel` diserver discord kamu dan masukan ke line `channel` di file `config.yml` +- Masukan `apikey` dan `url` pterodactyl di `line panel` di file `config.yml` +- Jalankan command `npm install` di folder yang berisi file bot +- Jalankan command `node index` dan kamu selesai! + +Jika kamu mendapat masalah bisa dm `Hirzi#8701` didiscord atau join [server support kami](https://discord.gg/zv6maQRah3) + +### Mengunakan custom emoji +1. ketik `\` di server yang ada custom emojinya + + ![Idk](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) + +2. Pilih custom emoji yang kamu mau + + ![Idk](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) + +3. Copy textnya! + + ![Idk](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) + +## Permission apikey + +Pilih Aktifkan `read` di semua opsi permission, jika tetap error pilih `read & write` di semua opsi permission + +![Admin Apikey Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) + +## Links + +- [Pterodactyl Panel](https://pterodactyl.io) +- [Pterodactyl Api Documentation](https://dashflo/docs/api/pterodactyl/v1) +- [Pterodactyl Discord Server]((https://discord.gg/pterodactyl)) +- [PteroBot Support Server](https://discord.gg/zv6maQRah3) +- [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) \ No newline at end of file diff --git a/README.md b/README.md index 46124a1..d84f81b 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,81 @@ -# THIS BUILD HASN'T BEEN TESTED WITH NODE THAT WINGS DOWN +
-# PteroStats +![PteroStats Banner](https://cdn.discordapp.com/attachments/626755594526916629/978478722489393153/20220524_090325.png) -![GitHub](https://img.shields.io/github/package-json/v/HirziDevs/PteroStats?style=flat-square) -![GitHub](https://img.shields.io/github/license/HirziDevs/PteroStats?style=flat-square) +## Language / Bahasa +[[English]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) | [[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.MD) -![img](https://media.discordapp.net/attachments/796259732683227157/861126504246411264/20210704_130856.jpg) +
## Introduction - PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server -- Written in Javascript, CloudServer is faster and more stable. -- PteroControl can be used with any server on Pterodactyl, irregardless of whether it's on shared hosting or your own hosted panel - -PteroStats is still **under development** and we welcome contributions. - -### How it works? - -PteroStats checks [pterodactyl](https://pterodactyl.io) nodes wings with [axios](https://www.npmjs.com/package/axios) to get nodes wings status, if the api didn't reply that mean the node is having [wings/daemon](https://pterodactyl.io/wings/1.0/installing.html) down and mark the node as offline - -### Screenshot - -- [**ItzyStore**](https://discord.gg/PS4Mf6DBzt) (No screenshot for resource becouse it will be long image) -![img](https://media.discordapp.net/attachments/796259732683227157/863359897210060820/IMG_20210710_164939.jpg) -- [**SpaceCloud**](https://discord.gg/28z8CYmPEY) -![img](https://media.discordapp.net/attachments/586738538448420881/866624597171372032/IMG_20210719_171633.jpg) - ## Installation -- `fill in the required informations in the config.yml file` -- `Run npm install in the root directory of the bot files` -- `Run node index.js and you are done` +### Getting apikey from pterodactyl +- Go to your `pterodactyl admin page` and go to `Application API`. -if you need help contact me on discord `Hirzi#8701` or join [our discord server here](https://discord.gg/zv6maQRah3) + ![Idk](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) -### Setuping Config +- Click on the `Create New` button -You need to put right config to make the bot work at [config.yml](https://github.com/HirziDevs/PteroStats/blob/main/config.yml) file -``` -# PteroStats config -# If you need help, join our discord server: https://discord.gg/zv6maQRah3 + ![Idk](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) -# Bot Info's -token: 'BOT TOKEN' # Put bot token here, check https://discord.dev to create and get bot token -botstatus: - enable: false # Enable Custom Status (MUST BE "true" OR "false") - text: 'Hosting Panel' # Bot Status Message - type: 'WATCHING' # Bot Status Type. Ex: PLAYING, WATCHING, LISTENING, STREAMING +- Set all options permission to `read` and for description you can put whatever you want -# Channel and RefreshTime Configuration -channel: 'CHANNEL ID' # Put channel id here where the embed will be sended -refreshtime: 60 # Time when the embed edited/refreshed (MUST BE A SECONDS) (RECOMMENDED MORE THAN 20 SECONDS) + ![Idk](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) -# Panel Info's -panel: - url: 'HOST PANEL LINK' # Put panel url here. Example: https://panel.purenodes.net - adminkey: 'ADMIN APIKEY' # Put Admin Apikey here. check https://your.host.url/admin/api (your.host.url is an example link) to get the Admin ApiKey +- Copy the apikey. -# Embed Configuration -embed: - title: 'EMBED TITLE' # Embed Title here. Ex: PureNodes Stats - color: 'E5BE11' # Embed Hex color here. - description: - enable: false # Enable Embed Description (MUST BE "true" OR "false") - text: 'EMBED DESCRIPTION' # Embed Description - footer: - enable: true # Enable Embed Footer (MUST BE "true" OR "false") - text: 'By Hirzi#8701' # Embed Footer - timestamp: true # Enable Embed TimeStamp (MUST BE "true" OR "false") + ![Idk](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) -# Status Message Configuration -status: - online: ':green_circle: Online' # Message if the status is Online - offline: ':red_circle: Offline' # Message if the status is Offline - check: ':orange_circle: Checking' # Message if the status is Checking +### Creating Discord Bot +Please refer to [this website](https://discordjs.guide/preparations/setting-up-a-bot-application.html) -# Node Resource -resource: - enable: false # Enable resource option ex [Ram: 2gb/5gb] bellow node name (MUST BE "true" OR "false") - servers: true # Enable Total server on the node to resource text (MUST BE "true" OR "false") - allocations: true # Enable Total Allocation on the node to resource text (MUST BE "true" OR "false") - location: true # Enable location short name on the node to resource text (MUST BE "true" OR "false") - unit: 'gb' # Must be 'mb', 'gb', or 'percent' +### Inviting Discord Bot +Please refer to [this website](https://discordjs.guide/preparations/adding-your-bot-to-servers.html) -# Developers feature -debug: false # Enable and Disable debug log to console -debugaxios: false #Enable and Disable axios error logs -``` +### Getting Channel ID +1. Enable Developer Feature at your discord settings -## Other -### FAQ + ![Idk](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) -Q: Can i use pterodactyl v0.7? +2. Copy Channel ID -A: No, the pterodactyl v0.7 is not supported + ![Idk](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) -- +### Starting bot +- Put discord bot token in `config.yml` at `token line`. +- Put your pterodactyl `apikey` and `url` in `config.yml` at `panel line`. +- Copy `channel id` from your discord server and put it in `config.yml` file at `channel line`. +- Run `npm install` in the root directory of the bot files. +- Run `node index` and you are done. -Q: How much nodes can i add? +if you need help contact me on discord `Hirzi#8701` or join [our discord support server](https://discord.gg/zv6maQRah3) -A: You can add as much your panel have +### Using Custom Emoji +1. type `\` in guild that has custom emoji you want -- + ![Idk](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) -Q: How i can get support? +2. Select custom emoji you want -A: You can join our [discord server](https://discord.gg/zv6maQRah3) + ![Idk](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) -### Links +3. Copy the text! -* __[PteroBot Discord](https://discord.gg/zv6maQRah3)__ -* __[Pterodactyl Panel](https://pterodactyl.io)__ -* __[Pterodactyl API](https://dashflo.net/docs/api/pterodactyl/v1)__ + ![Idk](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) + +## Admin Apikey Permission + +enable `read` on all options, if still didn't work enable `read & write` on all options + +![Admin Apikey Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) + +## Links + +- [Pterodactyl Panel](https://pterodactyl.io) +- [Pterodactyl Api Documentation](https://dashflo/docs/api/pterodactyl/v1) +- [Pterodactyl Discord Server]((https://discord.gg/pterodactyl)) +- [PteroBot Support Server](https://discord.gg/zv6maQRah3) +- [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) \ No newline at end of file diff --git a/config.yml b/config.yml index 2c8a473..98a358b 100644 --- a/config.yml +++ b/config.yml @@ -1,48 +1,65 @@ # PteroStats config # If you need help, join our discord server here: https://discord.gg/zv6maQRah3 -# Bot Info's -token: 'BOT TOKEN' # Put bot token here, check https://discord.dev to create and get bot token -botstatus: - enable: false # Enable Custom Status (MUST BE "true" OR "false") - text: 'Hosting Panel' # Bot Status Message - type: 'WATCHING' # Bot Status Type. Ex: PLAYING, WATCHING, LISTENING, STREAMING +# Bot Configuration +token: 'Put bot token here' +bot_status: + enable: false + text: 'Hosting Panel' + type: 'WATCHING' # can be 'WATCHING', 'PLAYING', 'LISTENING', or 'COMPETING'. for 'STREAMING' is not working for now -# Channel and RefreshTime Configuration -channel: 'CHANNEL ID' # Put channel id here where the embed will be sended -refreshtime: 60 # Time when the embed edited/refreshed (MUST BE A SECONDS) (RECOMMENDED MORE THAN 20 SECONDS) +# Discord Channel and Refresh Time Configuration +channel: 'Put channel id here' +refresh: 60 -# Panel Info's +# Panel Configuration panel: - url: 'HOST PANEL LINK' # Put panel url here. Example: https://panel.purenodes.net - adminkey: 'ADMIN APIKEY' # Put Admin Apikey here. check https://your.host.url/admin/api (your.host.url is an example link) to get the Admin ApiKey + url: 'Put panel url here' + key: 'Put panel apikey here' # Embed Configuration +# set to false if you want to disable embed option embed: - title: 'EMBED TITLE' # Embed Title here. Ex: PureNodes Stats - color: 'E5BE11' # Embed Hex color here. - description: - enable: false # Enable Embed Description (MUST BE "true" OR "false") - text: 'EMBED DESCRIPTION' # Embed Description - footer: - enable: true # Enable Embed Footer (MUST BE "true" OR "false") - text: 'By Hirzi#8701' # Embed Footer - timestamp: true # Enable Embed TimeStamp (MUST BE "true" OR "false") + title: 'PteroStats' + color: '5865F2' + description: 'Next update {{time}}' # You can use {{time}} to make "in X seconds" time format + footer: 'By Hirzi#8701' + timestamp: true + thumbnail: false + image: false + field: + enable: false + title: 'Custom Field' + description: 'Custom Field' # You can use {{time}} to make "in X seconds" time format +# Message Button Configuration +button: + enable: true + btn1: + label: 'PteroStats' + url: 'https://github.com/HirziDevs/PteroStats' + btn2: + label: '' + url: '' + btn3: + label: '' + url: '' + btn4: + label: '' + url: '' + btn5: + label: '' + url: '' + # Status Message Configuration status: - online: ':green_circle: Online' # Message if the status is Online - offline: ':red_circle: Offline' # Message if the status is Offline - check: ':orange_circle: Checking' # Message if the status is Checking + online: ':green_circle: Online' # TODO how to use custom emoji + offline: ':red_circle: Offline' # Node Resource resource: - enable: true # Enable resource option ex [Ram: 2gb/5gb] bellow node name (MUST BE "true" OR "false") - servers: true # Enable Total server on the node to resource text (MUST BE "true" OR "false") - allocations: true # Enable Total Allocation on the node to resource text (MUST BE "true" OR "false") - location: true # Enable location short name on the node to resource text (MUST BE "true" OR "false") - unit: 'gb' # Must be 'mb', 'gb', or 'percent' - -# Developers feature -debug: false # Enable and Disable debug log to console -debugaxios: false #Enable and Disable axios error logs + enable: false + servers: true + location: true + allocations: true + unit: 'gb' # You can use "gb", "mb", or "percent" \ No newline at end of file diff --git a/events/ready.js b/events/ready.js index fed6075..0f3aa4b 100644 --- a/events/ready.js +++ b/events/ready.js @@ -1,295 +1,29 @@ -module.exports = client => { +const chalk = require('chalk') +const checkStatus = require('../handlers/checkStatus') - //Code are very sensitive, please changes things on config.yml instead - - const { MessageEmbed } = require('discord.js') - const axios = require('axios') - const db = require('quick.db') - const nodetable = new db.table('node') - const paneltable = new db.table('panel') - const chalk = require('chalk') - const config = client.config +module.exports = { + name: 'ready', + once: true, + async execute(client) { + console.log(chalk.cyan('[PteroStats]') + chalk.green(' Bot is up!')) + console.log(chalk.cyan('[PteroStats]') + chalk.green(' If you need support you can join our discord server https://discord.gg/zv6maQRah3')) - let enablecs = config.botstatus.enable - let cs = config.botstatus.text - let stype = config.botstatus.type - let ch = client.channels.cache.find(cn => cn.id === config.channel) - let time = config.refreshtime + if (client.guilds.cache.size === 0) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' There is bot is not in servers, please invite the bot first!')) - let hosturl = config.panel.url - let adminapikey = config.panel.adminkey - - let statusonline = config.status.online - let statusoffline = config.status.offline - let checking = config.status.check - let resource = config.resource.enable - let serverres = config.resource.servers - let serverport = config.resource.allocations - let serverloc = config.resource.location - let unit = config.resource.unit - - let title = config.embed.title - let color = config.embed.color - let desc = config.embed.description.text - let footer = config.embed.footer.text - let enablets = config.embed.timestamp - let enabledesc = config.embed.description.enable - let enablef = config.embed.footer.enable - - let debug = config.debug - let debugerror = config.debugaxios - - if (debug === true) { - console.log(chalk.red('=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=')) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Debug Mode: ') + chalk.cyan('true')) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Debug Axios Mode: ') + chalk.cyan(debugerror)) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Resource: ') + chalk.cyan(resource)) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Custom Status: ') + chalk.cyan(enablecs)) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Enable Timestamp: ') + chalk.cyan(enablets)) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Enable Description: ') + chalk.cyan(enabledesc)) - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.green('Enable Footer: ') + chalk.cyan(enablef)) - } - - if (!hosturl.includes('http')) hosturl = 'http://' + hosturl - let unapi = hosturl + '/api' - let api = unapi.replace('//api', '/api') - - if (enablecs === true) { - client.user.setActivity(cs, { type: stype }) - } else { - client.user.setActivity(title + ' Panel Stats', { type: 'WATCHING' }) - } - - console.log(chalk.red('=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=')) - console.log(chalk.green('Name: ') + chalk.cyan('PteroStats')) - console.log(chalk.green('Version: ') + chalk.cyan('Stable pre-v1.5.0')) - console.log(chalk.green('Refresh Time: ') + chalk.cyan(time + ' Seconds')) - console.log(chalk.green('Bot Status: ') + chalk.cyan('Online')) - console.log(chalk.green('Support: ') + chalk.cyan('https://discord.gg/zv6maQRah3')) - console.log(chalk.red('=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=')) - console.log(chalk.red('You are using dev build, something not wanted might be happen!')) - - if(paneltable.get('URL') === null) console.log(chalk.cyan('It seems you are using our bot for first time, thank you for choosing our bot, if you need help you can join our support server!')) - if(paneltable.get('URL') !== api) console.log(chalk.cyan('Panel url changed, please allow the bot to check the nodes status for ' + time + ' seconds')) - paneltable.set('URL',api) - - setInterval(() => { - if (isNaN(time)) return console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red(time + ' is not a number!')) - if (!hosturl.includes('.')) return console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red(hosturl + ' is invalid url!')) - if (adminapikey.length < 48) return console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red('Invalid Admin Apikey!!')) - - let list = [] - axios(api + '/application/nodes/', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + adminapikey - } - }).then(response => { - let data = response.data.data - data.forEach(nodes => { - let id = nodes.attributes.id - axios(api + '/application/nodes/' + id + '?include=servers,location,allocations', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + adminapikey - } - }).then(node => { - axios(api + '/application/nodes/' + id + '/configuration', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + adminapikey + if (client.config.bot_status.enable) { + if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.status.type)) { + console.log('Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"') + } else { + client.user.setActivity(client.config.status.text, { type: client.config.status.type }) } - }).then(data => { - axios(node.data.attributes.scheme + '://' + node.data.attributes.fqdn + ':' + node.data.attributes.daemon_listen + '/api/servers', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + data.data.token - } - }).then(status => { - let ram = 'temp' - let disk = 'temp' - - const mode = node.data.attributes.maintenance_mode - const loc = '[Locations: ' + node.data.attributes.relationships.location.attributes.short + ']' - const port = '[Allocations: ' + node.data.attributes.relationships.allocations.data.length + ']' - const servers = '[Servers: ' + node.data.attributes.relationships.servers.data.length + ']' - const rampercent = '[Ram: ' + Math.floor(node.data.attributes.allocated_resources.memory / node.data.attributes.memory * 100) + '%/100%]' - const diskpercent = '[Disk: ' + Math.floor(node.data.attributes.allocated_resources.disk / node.data.attributes.disk * 100) + '%/100%]' - const rammega = '[Ram: ' + node.data.attributes.allocated_resources.memory + 'MB/' + node.data.attributes.memory + 'MB]' - const diskmega = '[Disk: ' + node.data.attributes.allocated_resources.disk + 'MB/' + node.data.attributes.disk + 'MB]' - const ramgiga = '[Ram: ' + Math.floor(node.data.attributes.allocated_resources.memory / 1000) + 'GB/' + Math.floor(node.data.attributes.memory / 1000) + 'GB]' - const diskgiga = '[Disk: ' + Math.floor(node.data.attributes.allocated_resources.disk / 1000) + 'GB/' + Math.floor(node.data.attributes.disk / 1000) + 'GB]' - if (unit === 'mb') { - disk = diskmega - ram = rammega - } - if (unit === 'gb') { - disk = diskgiga - ram = ramgiga - } - if (unit === 'percent') { - disk = diskpercent - ram = rampercent - } - - nodetable.set('node' + id, { - ram: ram, - disk: disk, - status: true, - servers: servers, - location: loc, - port: port, - mode: mode - }) - - }).catch((err) => { - let servers = '[Servers: N/A]' - let loc = '[Location: N/A]' - let port = '[Allocations: N/A]' - let ram = '[Ram: N/A]' - let disk = '[Disk: N/A]' - - console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red(node.data.attributes.name + ' is down!')) - if (debugerror === true) console.log(chalk.magenta('[PteroStats Debug] ') + chalk.red(err) + chalk.cyan(' Need Support? https://discord.gg/zv6maQRah3')) - - nodetable.set('node' + id, { - ram: ram, - disk: disk, - status: false, - servers: servers, - location: loc, - port: port, - mode: false - }) - }) - }).catch((err) => { - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.red(err) + chalk.cyan(' Need Support? https://discord.gg/zv6maQRah3')) - }) - }).catch((err) => { - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.red(err) + chalk.cyan(' Need Support? https://discord.gg/zv6maQRah3')) - }) - - let stats = nodetable.get('node' + id) - let msgStats = '' - if (stats === null) msgStats = '**' + nodes.attributes.name + '**: ' + checking - if (stats) { - let statsname = '**' + nodes.attributes.name + '**: ' - - if (stats.status === true) statsname = statsname + statusonline - if (stats.status === false) statsname = statsname + statusoffline - - if (stats.mode === true) statsname = statsname + ' [Maintance]' - - if (resource === true) statsname = statsname + '\n```\n' + stats.ram + '\n' + stats.disk - if (serverloc === true) statsname = statsname + '\n' + stats.location - if (serverport === true) statsname = statsname + '\n' + stats.port - if (serverres === true) statsname = statsname + '\n' + stats.servers - if (resource === false) statsname = statsname + '\n' - - if (resource === true) msgStats = statsname + '```\n' } - if (debug === true) console.log(chalk.magenta('[PteroStats Debug] ') + chalk.blue(nodes.attributes.name + ': ' + stats.status)) - list.push(msgStats) - }) + if (client.config.refresh < 10) console.log('Refresh below 10 seconds is not recommended!') - axios(api + '/application/servers', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + adminapikey - } - }).then(ser => { - let res = ser.data.meta.pagination.total - paneltable.set('serverCount', res) - }).catch((err) => { - paneltable.set('serverCount', 'N/A') - console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red('Panel is down')) - if (debugerror === true) console.log(chalk.magenta('[PteroStats Debug] ') + err) - }) + checkStatus(client) - axios(api + '/application/users', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + adminapikey - } - }).then(usr => { - let res = usr.data.meta.pagination.total - paneltable.set('userCount', res) - }).catch((err) => { - paneltable.set('userCount', 'N/A') - console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red('Panel is down!')) - if (debugerror === true) console.log(chalk.magenta('[PteroStats Debug] ') + err) - }) - - let userCount = paneltable.get('userCount') - let serverCount = paneltable.get('serverCount') - - if (userCount === null) userCount = checking - if (serverCount === null) serverCount = checking - - if (userCount !== 'N/A') paneltable.set('panel', '**Panel**: ' + statusonline) - if (userCount === 'N/A') { - paneltable.set('panel', '**Panel**: ' + statusoffline) - console.log(chalk.cyan('[PteroStats Checker] ') + chalk.red('panel is down!')) - } - if (userCount === checking) paneltable.set('panel', '**Panel**: ' + checking) - let panel = paneltable.get('panel') + '\n\nUsers: ' + userCount + '\nServers: ' + serverCount - - if (panel === null) panel = '**Panel**: ' + checking + '\n\nUsers: ' + userCount + '\nServers: ' + serverCount - - let nodes - list.forEach((d) => { - if (!nodes) return nodes = d - nodes = nodes + d - }) - - console.log(chalk.cyan(['[PteroStats Checker] ']) + chalk.green('Connected to ' + list.length + ' nodes') - let nodeCount = '[Total ' + list.length + ']' - - if (debug === true) console.log(chalk.magenta('[PteroStats Debug] ') + chalk.blue(nodes)) - if (nodes === undefined) { - nodes = checking + ' Please wait ' + time + ' seconds' - console.log(chalk.cyan(['[PteroStats Checker] ']) + chalk.yellow(checking + ' Please wait ' + time + ' seconds')) - } - - let embedfooter = 'Updated every ' + time + ' seconds' - if (enablef === true) embedfooter = 'Updated every ' + time + ' seconds | ' + footer - - let embed = new MessageEmbed() - .setTitle(title) - .setColor(color) - .addField('Panel Stats', panel) - .setFooter(embedfooter) - .setThumbnail(client.user.avatarURL()) - if (enablets === true) { - embed.setTimestamp() - } - if (enabledesc === true) { - embed.setDescription(desc + '\n**Nodes Stats' + nodeCount + '**\n' + nodes) - } else { - embed.setDescription('\n**Nodes Stats' + nodeCount + '**\n' + nodes) - } - - ch.send(embed).then(msg => { msg.delete({ timeout: time + '000' }) }) - - console.log(chalk.cyan('[PteroStats Checker] ') + chalk.green('Posted Stats')) - if (panel !== null) console.log(chalk.cyan('[PteroStats Checker] ') + chalk.green('Stats Updated')) - console.log(chalk.cyan('[PteroStats Checker] ') + chalk.green('Updating Stats in ' + time + ' Seconds')) - - }).catch((err) => { - console.log(chalk.magenta('[PteroStats Debug] ') + chalk.red(err) + chalk.cyan(' Need Support? https://discord.gg/zv6maQRah3')) - }) - }, time + '000') -} + setInterval(async () => { + checkStatus(client) + }, client.config.refresh * 1000) + } +} \ No newline at end of file diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js new file mode 100644 index 0000000..e06c184 --- /dev/null +++ b/handlers/checkStatus.js @@ -0,0 +1,125 @@ +const axios = require('axios') +const chalk = require('chalk') + +const postStatus = require('./postStatus') + +module.exports = async function checkStatus(client) { + + const nodes = [] + + const panel = { + id: 1, + status: false, + total_servers: -1, + total_users: -1, + } + console.log(chalk.cyan('[PteroStats]') + chalk.green(' Getting nodes stats')) + const panelStats = new Promise((resolve, reject) => { + axios(client.config.panel.url + '/api/application/users', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then(usr => { + axios(client.config.panel.url + '/api/application/servers', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then(async (ser) => { + panel.total_users = usr.data.meta.pagination.total + panel.total_servers = ser.data.meta.pagination.total + panel.status = true + + resolve() + }) + }).catch(async (err) => { + if (err.response) { + if (err.response.status === 403) { + console.log('[PteroStats] Err! Invalid apikey') + console.log('[PteroStats] 1. Make sure the apikey is from admin page not account page') + console.log('[PteroStats] 2. Make sure the apikey has read permission on all options') + console.log('[PteroStats] 3. Make sure the apikey is exist') + } else if (err.response.status === 404) { + console.log('[PteroStats] Err! Invalid URL Panel') + console.log('[PteroStats] 1. Make sure the panel url is like "https://panel.example.com"') + } else { + console.log(err) + } + } else { + console.log('[PteroStats] ' + err) + } + resolve() + }) + }) + + const nodeStats = new Promise((resolve, reject) => { + axios(client.config.panel.url + '/api/application/nodes?include=servers,location,allocations', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then(async (res) => { + res.data.data.forEach(async (node, i) => { + axios(client.config.panel.url + '/api/application/nodes/' + node.attributes.id + '/configuration', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then(async (data) => { + const body = { + id: node.attributes.id, + name: node.attributes.name, + location: node.attributes.relationships.location.attributes.short, + allocations: node.attributes.relationships.allocations.data.length, + status: true, + maintenance: node.attributes.maintenance_mode, + total_servers: node.attributes.relationships.servers.data.length, + memory_min: node.attributes.allocated_resources.memory, + memory_max: node.attributes.memory, + disk_min: node.attributes.allocated_resources.disk, + disk_max: node.attributes.disk, + } + + const stats = new Promise((statsResolve, statsReject) => { + axios(node.attributes.scheme + '://' + node.attributes.fqdn + ':' + node.attributes.daemon_listen + '/api/servers', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + data.data.token + } + }).then(async (status) => { + statsResolve() + }).catch(async (err) => { + body.status = false + statsResolve() + }) + }) + stats.then(() => { + nodes.push(body) + resolve() + }) + }).catch(async (err) => { + resolve() + }) + }) + }).catch(async (err) => { + resolve() + }) + }) + + panelStats.then(() => { + nodeStats.then(() => { + postStatus(client, panel, nodes) + }) + }) +} \ No newline at end of file diff --git a/handlers/postStatus.js b/handlers/postStatus.js new file mode 100644 index 0000000..6c0026d --- /dev/null +++ b/handlers/postStatus.js @@ -0,0 +1,153 @@ +const { MessageEmbed, Formatters, MessageActionRow, MessageButton } = require('discord.js') +const chalk = require('chalk') + +module.exports = async function postStatus(client, panel, nodes) { + + const channel = await client.channels.cache.get(client.config.channel) + + if (!channel) return console.log('Invalid Channel ID') + + let messages = await channel.messages.fetch({ limit: 10 }) + messages = messages.filter(m => m.author.id === client.user.id).last(); + if (messages && messages.embeds.length === 0) { + messages.delete() + messages = null + } + + const format = await Formatters.time(new Date(Date.now() + client.config.refresh * 1000), 'R') + const embed = new MessageEmbed() + + let text = '' + let desc = '' + + if (client.config.embed.title) embed.setTitle(client.config.embed.title) + if (client.config.embed.description) desc = client.config.embed.description.replaceAll('{{time}}', format) + '\n' + if (client.config.embed.color) embed.setColor(client.config.embed.color) + if (client.config.embed.footer) embed.setFooter({ text: client.config.embed.footer }) + if (client.config.embed.thumbnail) embed.setThumbnail(client.config.embed.thumbnail) + if (client.config.embed.image) embed.setImage(client.config.embed.image) + + panel.total_users = panel.total_users.toLocaleString() + panel.total_servers = panel.total_servers.toLocaleString() + + const stats = new Promise((resolve, reject) => { + if (nodes.length !== 0) { + nodes.forEach((data, i) => { + const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + let description = '```' + '\n' + + 'Status : ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n' + + switch (client.config.resource.unit) { + case 'gb': + description = description + + 'Memory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' Gb /' + Math.floor(data.memory_max / 1000).toLocaleString() + ' Gb\n' + + 'Disk : ' + Math.floor(data.disk_min / 1000).toLocaleString() + 'Gb /' + Math.floor(data.disk_max / 1000).toLocaleString() + ' Gb\n' + break; + case 'percent': + description = description + + 'Memory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %\n' + + 'Disk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %\n' + break; + default: + description = description + + 'Memory : ' + data.memory_min.toLocaleString() + ' Mb /' + data.memory_max.toLocaleString() + ' Mb\n' + + 'Disk : ' + data.disk_min.toLocaleString() + 'Mb /' + data.disk_max.toLocaleString() + ' Mb\n' + } + + if (client.config.resource.location) description = description + 'Location: ' + data.location + '\n' + if (client.config.resource.allocations) description = description + 'Servers : ' + data.allocations.toLocaleString() + '\n' + if (client.config.resource.servers) description = description + 'Servers : ' + data.total_servers.toLocaleString() + '\n' + + description = description + '```' + + if (client.config.resource.enable) { + text = text + '\n**' + title.replace(':', ':**') + '\n' + description + } else { + text = text + '\n**' + title.replace(':', ':**') + } + + if (i + 1 === nodes.length) resolve() + }) + } else if (nodes.length === 0) { + if (!messages) { + text = 'There is no nodes to display' + resolve() + } else { + text = messages.embeds[0].fields[0].value.replaceAll(client.config.status.online, client.config.status.offline) + if (!panel.status && String(String(messages.embeds[0].fields[1].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[2]).length - 1] !== '`') { + panel.total_users = String(String(messages.embeds[0].fields[1].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[2]).length - 1] + panel.total_servers = String(String(messages.embeds[0].fields[1].value).split('\n')[3]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[3]).length - 1] + } + resolve() + } + } + }) + + stats.then(async () => { + + embed.setDescription(desc + '\n**Nodes Stats [' + nodes.length + ']**' + text) + embed.addField('Panel Stats', + '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' + + 'Users: ' + String(panel.total_users).replace('-1', '`Unknown`') + '\n' + + 'Servers: ' + String(panel.total_servers).replace('-1', '`Unknown`') + ) + + if (client.config.embed.field.enable) { + embed.addField(client.config.embed.field.title, client.config.embed.field.description.replaceAll('{{time}}', format)) + } + + embed.setTimestamp() + + let row = [] + + if (client.config.button.enable) { + row = new MessageActionRow + if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.label.link.length !== 0) { + row.addComponents( + new MessageButton() + .setLabel(client.config.button.btn1.label) + .setStyle('LINK') + .setURL(client.config.button.btn1.url) + ) + } + if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.label.link.length !== 0) { + row.addComponents( + new MessageButton() + .setLabel(client.config.button.btn2.label) + .setStyle('LINK') + .setURL(client.config.button.btn2.url) + ) + } + if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.label.link.length !== 0) { + row.addComponents( + new MessageButton() + .setLabel(client.config.button.btn3.label) + .setStyle('LINK') + .setURL(client.config.button.btn3.url) + ) + } + if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.label.link.length !== 0) { + row.addComponents( + new MessageButton() + .setLabel(client.config.button.btn4.label) + .setStyle('LINK') + .setURL(client.config.button.btn4.url) + ) + } + if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.label.link.length !== 0) { + row.addComponents( + new MessageButton() + .setLabel(client.config.button.btn5.label) + .setStyle('LINK') + .setURL(client.config.button.btn5.url) + ) + } + + row = [row] + } + + if (!messages) channel.send({ embeds: [embed] }) + else messages.edit({ embeds: [embed], components: row }) + console.log(chalk.cyan('[PteroStats]') + chalk.green(' stats posted!')) + }) +} \ No newline at end of file diff --git a/index.js b/index.js index 4cf5d39..122ea6e 100644 --- a/index.js +++ b/index.js @@ -1,18 +1,44 @@ -const { Client, Collection } = require('discord.js') -const fs = require('fs') -const client = new Client() -const yaml = require('js-yaml') -const config = yaml.load(fs.readFileSync('./config.yml', 'utf8')) +const fs = require('fs'); + +if (Number(process.version.split('.')[0]) < 16) { + console.log('Invalid NodeJS Version!, Please use NodeJS 16.x or upper') + process.exit() +} +if (fs.existsSync('./node_modules')) { + const check = require('./node_modules/discord.js/package.json') + if (Number(check.version.split('.')[0]) !== 13) { + console.log('Invalid Discord.JS Version!, Please use Discord.JS 13.x') + process.exit() + } +} else { + console.log('There is no node_modules!, please install the package first by using "npm i"') + process.exit() +} + +const yaml = require('js-yaml'); +const { Client, Intents } = require('discord.js'); +const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); + +// Load Config +const config = yaml.load(fs.readFileSync('./config.yml', 'utf8')); client.config = config -fs.readdir('./events/', (err, files) => { - if (err) return console.error(err) - files.forEach(file => { - const event = require(`./events/${file}`) - const eventName = file.split('.')[0] - client.on(eventName, event.bind(null, client)) - }) -}) +// Read Events Files +const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); -if (config.token === 'BOT TOKEN') console.log(chalk.blue('[PteroStats Checker] ') + chalk.red('Invalid Token, Check ') + chalk.green('config.yml') + chalk.red(' file to change token')) -client.login(config.token) +for (const file of eventFiles) { + const event = require(`./events/${file}`); + if (event.once) { + client.once(event.name, (client) => event.execute(client)); + } else { + client.on(event.name, (client) => event.execute(client)); + } +} + +// Login to bot +try { + client.login(config.token); +} catch (Err) { + console.log('Invalid discord bot token') + process.exit() +} \ No newline at end of file diff --git a/package.json b/package.json index 498bad0..397c07f 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,24 @@ { "name": "pterostats", - "version": "v1.5.0", + "version": "v2.0.0", "description": "PteroStats is a bot designed to check Panel, Nodes, and Databases status and post it to your discord server", "license": "Apache-2.0", "repository": "HirziDevs/PteroStats", "homepage": "https://pterostats.hirzidevs.net", "bugs": { - "email": "hirzigamingyt@gmail.com", + "email": "hirzidevs@gmail.com", "url": "https://github.com/HirziDevs/PteroStats" }, "scripts": { "start": "node index.js" }, "dependencies": { - "axios": "^0.21.1", - "chalk": "^4.1.1", - "js-yaml": "^4.1.0", - "discord.js": "^12.5.3", - "quick.db": "^7.1.3" + "axios": "^0.26.1", + "chalk": "4.1.1", + "discord.js": "^13.7.0", + "js-yaml": "^4.1.0" }, "engines": { - "node": "^12.x" + "node": "16.x" } } From 13552a0e3b19af4e0a39d1a9c797d28c31f3df79 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sun, 29 May 2022 19:29:23 +0700 Subject: [PATCH 02/27] typo --- Indo.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Indo.md b/Indo.md index 74b6970..834cc3b 100644 --- a/Indo.md +++ b/Indo.md @@ -3,7 +3,7 @@ ![PteroStats Banner](https://cdn.discordapp.com/attachments/626755594526916629/978478722489393153/20220524_090325.png) ## Bahasa / Language -[[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.MD) | [[Inggris]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) +[[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.md) | [[Inggris]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) diff --git a/README.md b/README.md index d84f81b..1bc0036 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![PteroStats Banner](https://cdn.discordapp.com/attachments/626755594526916629/978478722489393153/20220524_090325.png) ## Language / Bahasa -[[English]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) | [[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.MD) +[[English]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) | [[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.md) From b85266c904428e5d80da3996d6c9ddfdbb754010 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sun, 29 May 2022 19:32:55 +0700 Subject: [PATCH 03/27] typo --- Indo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Indo.md b/Indo.md index 834cc3b..96b679f 100644 --- a/Indo.md +++ b/Indo.md @@ -76,6 +76,6 @@ Pilih Aktifkan `read` di semua opsi permission, jika tetap error pilih `read & w - [Pterodactyl Panel](https://pterodactyl.io) - [Pterodactyl Api Documentation](https://dashflo/docs/api/pterodactyl/v1) -- [Pterodactyl Discord Server]((https://discord.gg/pterodactyl)) +- [Pterodactyl Discord Server](https://discord.gg/pterodactyl) - [PteroBot Support Server](https://discord.gg/zv6maQRah3) - [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) \ No newline at end of file From af65a593596bd09773be6ef169864c5a4ad525b6 Mon Sep 17 00:00:00 2001 From: tlkh40 <72644753+tlkh40@users.noreply.github.com> Date: Sun, 29 May 2022 19:35:00 +0700 Subject: [PATCH 04/27] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1bc0036..b107c52 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,6 @@ enable `read` on all options, if still didn't work enable `read & write` on all - [Pterodactyl Panel](https://pterodactyl.io) - [Pterodactyl Api Documentation](https://dashflo/docs/api/pterodactyl/v1) -- [Pterodactyl Discord Server]((https://discord.gg/pterodactyl)) +- [Pterodactyl Discord Server](https://discord.gg/pterodactyl) - [PteroBot Support Server](https://discord.gg/zv6maQRah3) -- [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) \ No newline at end of file +- [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) From 88dd52cf4621ae4d95833713d11d200dee1979d5 Mon Sep 17 00:00:00 2001 From: Scoooolzs <84376629+Scoooolzs@users.noreply.github.com> Date: Sun, 29 May 2022 20:30:51 +0700 Subject: [PATCH 05/27] Update index.js --- index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 122ea6e..1e56344 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ const fs = require('fs'); +const child = require("child_process") if (Number(process.version.split('.')[0]) < 16) { console.log('Invalid NodeJS Version!, Please use NodeJS 16.x or upper') @@ -11,7 +12,9 @@ if (fs.existsSync('./node_modules')) { process.exit() } } else { - console.log('There is no node_modules!, please install the package first by using "npm i"') + console.log("You are not installing package first, please wait until Auto Installer complete.") + child.execSync("npm i") + console.log("Auto Installer complete! Please re run this bot!") process.exit() } @@ -41,4 +44,4 @@ try { } catch (Err) { console.log('Invalid discord bot token') process.exit() -} \ No newline at end of file +} From 4a267ff22cefff9b4056b33c8bd24cddc4338b6c Mon Sep 17 00:00:00 2001 From: Scoooolzs <84376629+Scoooolzs@users.noreply.github.com> Date: Sun, 29 May 2022 20:32:36 +0700 Subject: [PATCH 06/27] Update index.js --- index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 1e56344..043a589 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,10 @@ if (fs.existsSync('./node_modules')) { } } else { console.log("You are not installing package first, please wait until Auto Installer complete.") - child.execSync("npm i") + child.execSync("npm i").catch((err) => { + console.log("An error detected: ", err) + console.log("If you want") + }) console.log("Auto Installer complete! Please re run this bot!") process.exit() } From 81f81a6609aeb1288bda090f452260bcbc77a8b3 Mon Sep 17 00:00:00 2001 From: Scoooolzs <84376629+Scoooolzs@users.noreply.github.com> Date: Sun, 29 May 2022 20:37:15 +0700 Subject: [PATCH 07/27] Update index.js --- index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 043a589..599a3dc 100644 --- a/index.js +++ b/index.js @@ -12,10 +12,11 @@ if (fs.existsSync('./node_modules')) { process.exit() } } else { - console.log("You are not installing package first, please wait until Auto Installer complete.") - child.execSync("npm i").catch((err) => { - console.log("An error detected: ", err) - console.log("If you want") + console.log('You are not installing package first, please wait until Auto Installer complete.') + child.execSync('npm i').catch((err) => { + console.log('An error detected: ', err) + console.log('Need Support? https://discord.gg/zv6maQRah3') + process.exit() }) console.log("Auto Installer complete! Please re run this bot!") process.exit() From 4894211fcd1cb0f8df4763e1e70679b29fecb6b7 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Mon, 30 May 2022 08:27:29 +0700 Subject: [PATCH 08/27] Fixed issue with bot status and embed field, also now you can disable panel stats users and servers --- config.yml | 10 ++++++++-- events/ready.js | 2 +- handlers/postStatus.js | 16 ++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/config.yml b/config.yml index 98a358b..e543a4a 100644 --- a/config.yml +++ b/config.yml @@ -53,7 +53,7 @@ button: # Status Message Configuration status: - online: ':green_circle: Online' # TODO how to use custom emoji + online: ':green_circle: Online' offline: ':red_circle: Offline' # Node Resource @@ -62,4 +62,10 @@ resource: servers: true location: true allocations: true - unit: 'gb' # You can use "gb", "mb", or "percent" \ No newline at end of file + unit: 'gb' # You can use "gb", "mb", or "percent" + +# Panel Users and Servers +panel_resource: + enable: true + servers: true + users: true \ No newline at end of file diff --git a/events/ready.js b/events/ready.js index 0f3aa4b..ea01800 100644 --- a/events/ready.js +++ b/events/ready.js @@ -11,7 +11,7 @@ module.exports = { if (client.guilds.cache.size === 0) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' There is bot is not in servers, please invite the bot first!')) if (client.config.bot_status.enable) { - if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.status.type)) { + if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type)) { console.log('Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"') } else { client.user.setActivity(client.config.status.text, { type: client.config.status.type }) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 6c0026d..7aeb268 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -73,7 +73,7 @@ module.exports = async function postStatus(client, panel, nodes) { text = 'There is no nodes to display' resolve() } else { - text = messages.embeds[0].fields[0].value.replaceAll(client.config.status.online, client.config.status.offline) + text = messages.embeds[0].description.replaceAll(client.config.status.online, client.config.status.offline) if (!panel.status && String(String(messages.embeds[0].fields[1].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[2]).length - 1] !== '`') { panel.total_users = String(String(messages.embeds[0].fields[1].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[2]).length - 1] panel.total_servers = String(String(messages.embeds[0].fields[1].value).split('\n')[3]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[3]).length - 1] @@ -86,11 +86,15 @@ module.exports = async function postStatus(client, panel, nodes) { stats.then(async () => { embed.setDescription(desc + '\n**Nodes Stats [' + nodes.length + ']**' + text) - embed.addField('Panel Stats', - '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' + - 'Users: ' + String(panel.total_users).replace('-1', '`Unknown`') + '\n' + - 'Servers: ' + String(panel.total_servers).replace('-1', '`Unknown`') - ) + + if (client.config.panel_resource.enable) { + let stats = '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' + + if (client.config.panel_resource.users) stats = stats + 'Users: ' + String(panel.total_users).replace('-1', '`Unknown`') + '\n' + if (client.config.panel_resource.servers) stats = stats + 'Servers: ' + String(panel.total_servers).replace('-1', '`Unknown`') + + embed.addField('Panel Stats', stats) + } if (client.config.embed.field.enable) { embed.addField(client.config.embed.field.title, client.config.embed.field.description.replaceAll('{{time}}', format)) From bd7684bb98f9a5dcd2171827d61d4d28393c505b Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Thu, 2 Jun 2022 19:51:24 +0700 Subject: [PATCH 09/27] Check the bot if it's on discord server or not --- handlers/checkStatus.js | 22 ++++++++++------------ handlers/postStatus.js | 16 +++++++++------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index e06c184..f0bd5b4 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -13,7 +13,9 @@ module.exports = async function checkStatus(client) { total_servers: -1, total_users: -1, } + console.log(chalk.cyan('[PteroStats]') + chalk.green(' Getting nodes stats')) + const panelStats = new Promise((resolve, reject) => { axios(client.config.panel.url + '/api/application/users', { method: 'GET', @@ -40,19 +42,15 @@ module.exports = async function checkStatus(client) { }).catch(async (err) => { if (err.response) { if (err.response.status === 403) { - console.log('[PteroStats] Err! Invalid apikey') - console.log('[PteroStats] 1. Make sure the apikey is from admin page not account page') - console.log('[PteroStats] 2. Make sure the apikey has read permission on all options') - console.log('[PteroStats] 3. Make sure the apikey is exist') + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid apikey')) + console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the apikey is from admin page not account page')) + console.log(chalk.cyan('[PteroStats]') + chalk.red(' 2. Make sure the apikey has read permission on all options')) + console.log(chalk.cyan('[PteroStats]') + chalk.red(' 3. Make sure the apikey is exist')) } else if (err.response.status === 404) { - console.log('[PteroStats] Err! Invalid URL Panel') - console.log('[PteroStats] 1. Make sure the panel url is like "https://panel.example.com"') - } else { - console.log(err) - } - } else { - console.log('[PteroStats] ' + err) - } + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid URL Panel')) + console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the panel url is like "https://panel.example.com"')) + } else console.log(chalk.cyan('[PteroStats] ') + err) + } else console.log(chalk.cyan('[PteroStats] ') + err) resolve() }) }) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 7aeb268..38a977f 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -3,9 +3,11 @@ const chalk = require('chalk') module.exports = async function postStatus(client, panel, nodes) { + if (client.guilds.cache.size === 0) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' This bot is not on any discord servers')) + const channel = await client.channels.cache.get(client.config.channel) - if (!channel) return console.log('Invalid Channel ID') + if (!channel) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' Invalid Channel ID')) let messages = await channel.messages.fetch({ limit: 10 }) messages = messages.filter(m => m.author.id === client.user.id).last(); @@ -106,7 +108,7 @@ module.exports = async function postStatus(client, panel, nodes) { if (client.config.button.enable) { row = new MessageActionRow - if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.label.link.length !== 0) { + if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.url.length !== 0) { row.addComponents( new MessageButton() .setLabel(client.config.button.btn1.label) @@ -114,7 +116,7 @@ module.exports = async function postStatus(client, panel, nodes) { .setURL(client.config.button.btn1.url) ) } - if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.label.link.length !== 0) { + if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.url.length !== 0) { row.addComponents( new MessageButton() .setLabel(client.config.button.btn2.label) @@ -122,7 +124,7 @@ module.exports = async function postStatus(client, panel, nodes) { .setURL(client.config.button.btn2.url) ) } - if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.label.link.length !== 0) { + if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.url.length !== 0) { row.addComponents( new MessageButton() .setLabel(client.config.button.btn3.label) @@ -130,7 +132,7 @@ module.exports = async function postStatus(client, panel, nodes) { .setURL(client.config.button.btn3.url) ) } - if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.label.link.length !== 0) { + if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.url.length !== 0) { row.addComponents( new MessageButton() .setLabel(client.config.button.btn4.label) @@ -138,7 +140,7 @@ module.exports = async function postStatus(client, panel, nodes) { .setURL(client.config.button.btn4.url) ) } - if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.label.link.length !== 0) { + if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.url.length !== 0) { row.addComponents( new MessageButton() .setLabel(client.config.button.btn5.label) @@ -152,6 +154,6 @@ module.exports = async function postStatus(client, panel, nodes) { if (!messages) channel.send({ embeds: [embed] }) else messages.edit({ embeds: [embed], components: row }) - console.log(chalk.cyan('[PteroStats]') + chalk.green(' stats posted!')) + console.log(chalk.cyan('[PteroStats]') + chalk.green(' Stats posted!')) }) } \ No newline at end of file From e8602adaabdbabcaaabef15f778fcc87153217d2 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Thu, 2 Jun 2022 21:38:42 +0700 Subject: [PATCH 10/27] Update ReadMe --- Indo.md | 22 +++++++++++----------- README.md | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Indo.md b/Indo.md index 96b679f..c51f8a5 100644 --- a/Indo.md +++ b/Indo.md @@ -15,19 +15,19 @@ PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl da ### Mendapatkan apikey dari pterodactyl - Pergi ke `panel admin pterodactyl` dan pergi ke `Application API` - ![Idk](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) + ![Admin Panel](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) - Klik tombol `Create New` - ![Admin Panel](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) + ![Application API Page](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) - Set semua permission ke `read` dan untuk description kamu bisa mengisi apa saja - ![Application API](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) + ![Create Application API](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) - Copy apikey-nya. - ![Copy the apikey](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) + ![Application API List](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) ### Membuat Discord Bot Kalian bisa cek [website ini](https://discordjs.guide/preparations/setting-up-a-bot-application.html) @@ -38,11 +38,11 @@ Kalian bisa cek [website ini](https://discordjs.guide/preparations/adding-your-b ### Mendapatkan Channel ID 1. Aktifkan `Developer Mode` di settings discord kamu - ![User Settings](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) + ![Discord User Settings](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) -2. Copy Channel ID-nya +2. Klik kanan teks channel dan pilih `Copy ID` - ![Channel ID](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) + ![Klik Kanan Channel](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) ### Memulai Bot - Masukan `token` bot discord di `line token` yang terdapat di file `config.yml` @@ -56,21 +56,21 @@ Jika kamu mendapat masalah bisa dm `Hirzi#8701` didiscord atau join [server supp ### Mengunakan custom emoji 1. ketik `\` di server yang ada custom emojinya - ![Idk](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) + ![Type \ on the chat](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) 2. Pilih custom emoji yang kamu mau - ![Idk](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) + ![Select Custom Emoji](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) 3. Copy textnya! - ![Idk](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) + ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) ## Permission apikey Pilih Aktifkan `read` di semua opsi permission, jika tetap error pilih `read & write` di semua opsi permission -![Admin Apikey Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) +![Application API Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) ## Links diff --git a/README.md b/README.md index b107c52..0ef2e7c 100644 --- a/README.md +++ b/README.md @@ -15,19 +15,19 @@ PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and pos ### Getting apikey from pterodactyl - Go to your `pterodactyl admin page` and go to `Application API`. - ![Idk](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) + ![Admin Panel](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) - Click on the `Create New` button - ![Idk](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) + ![Application API Page](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) - Set all options permission to `read` and for description you can put whatever you want - ![Idk](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) + ![Create Application API](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) - Copy the apikey. - ![Idk](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) + ![Application API List](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) ### Creating Discord Bot Please refer to [this website](https://discordjs.guide/preparations/setting-up-a-bot-application.html) @@ -38,11 +38,11 @@ Please refer to [this website](https://discordjs.guide/preparations/adding-your- ### Getting Channel ID 1. Enable Developer Feature at your discord settings - ![Idk](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) + ![Discord User Settings](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) -2. Copy Channel ID +2. Right Click text channel and select `Copy ID` - ![Idk](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) + ![Right Click Channel](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) ### Starting bot - Put discord bot token in `config.yml` at `token line`. @@ -56,21 +56,21 @@ if you need help contact me on discord `Hirzi#8701` or join [our discord support ### Using Custom Emoji 1. type `\` in guild that has custom emoji you want - ![Idk](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) + ![Type \ on the chat](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) 2. Select custom emoji you want - ![Idk](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) + ![Select Custom Emoji](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) 3. Copy the text! - ![Idk](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) + ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) ## Admin Apikey Permission enable `read` on all options, if still didn't work enable `read & write` on all options -![Admin Apikey Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) +![Application API Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) ## Links @@ -78,4 +78,4 @@ enable `read` on all options, if still didn't work enable `read & write` on all - [Pterodactyl Api Documentation](https://dashflo/docs/api/pterodactyl/v1) - [Pterodactyl Discord Server](https://discord.gg/pterodactyl) - [PteroBot Support Server](https://discord.gg/zv6maQRah3) -- [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) +- [PteroBot Support Server (Indonesia)](https://discord.gg/EYaFB7WSg6) \ No newline at end of file From 92b213aedc16af749fd9017dab1e1d5f8009d8a1 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Wed, 15 Jun 2022 17:22:41 +0700 Subject: [PATCH 11/27] Just some fix --- handlers/checkStatus.js | 19 ++++++++++++++++++- handlers/postStatus.js | 28 +++++++++++++--------------- index.js | 30 +++++++++++++++++------------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index f0bd5b4..d8763bb 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -5,6 +5,23 @@ const postStatus = require('./postStatus') module.exports = async function checkStatus(client) { + if (client.config.channel.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Channel ID')) + process.exit() + } else if (client.config.panel.url.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Panel URL')) + process.exit() + } else if (client.config.panel.key.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Apikey')) + process.exit() + } else if (!client.config.panel.url.startsWith('http')) { + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Panel URL')) + console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the panel url is starts with "https://" or "http://"')) + process.exit() + } + + if (client.config.panel.url.endsWith('/')) client.config.panel.url = client.config.panel.url.slice(0, -1) + const nodes = [] const panel = { @@ -47,7 +64,7 @@ module.exports = async function checkStatus(client) { console.log(chalk.cyan('[PteroStats]') + chalk.red(' 2. Make sure the apikey has read permission on all options')) console.log(chalk.cyan('[PteroStats]') + chalk.red(' 3. Make sure the apikey is exist')) } else if (err.response.status === 404) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid URL Panel')) + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Panel URL')) console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the panel url is like "https://panel.example.com"')) } else console.log(chalk.cyan('[PteroStats] ') + err) } else console.log(chalk.cyan('[PteroStats] ') + err) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 38a977f..5e46fa3 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -36,9 +36,7 @@ module.exports = async function postStatus(client, panel, nodes) { if (nodes.length !== 0) { nodes.forEach((data, i) => { const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) - let description = '```' + '\n' + - 'Status : ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n' - + let description = '```' switch (client.config.resource.unit) { case 'gb': description = description + @@ -57,7 +55,7 @@ module.exports = async function postStatus(client, panel, nodes) { } if (client.config.resource.location) description = description + 'Location: ' + data.location + '\n' - if (client.config.resource.allocations) description = description + 'Servers : ' + data.allocations.toLocaleString() + '\n' + if (client.config.resource.allocations) description = description + 'Allocations : ' + data.allocations.toLocaleString() + '\n' if (client.config.resource.servers) description = description + 'Servers : ' + data.total_servers.toLocaleString() + '\n' description = description + '```' @@ -76,9 +74,9 @@ module.exports = async function postStatus(client, panel, nodes) { resolve() } else { text = messages.embeds[0].description.replaceAll(client.config.status.online, client.config.status.offline) - if (!panel.status && String(String(messages.embeds[0].fields[1].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[2]).length - 1] !== '`') { - panel.total_users = String(String(messages.embeds[0].fields[1].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[2]).length - 1] - panel.total_servers = String(String(messages.embeds[0].fields[1].value).split('\n')[3]).split('')[String(String(messages.embeds[0].fields[1].value).split('\n')[3]).length - 1] + if (!panel.status && String(String(messages.embeds[0].fields[0].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[2]).length - 1] !== '`') { + panel.total_users = String(String(messages.embeds[0].fields[0].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[2]).length - 1] + panel.total_servers = String(String(messages.embeds[0].fields[0].value).split('\n')[3]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[3]).length - 1] } resolve() } @@ -107,9 +105,9 @@ module.exports = async function postStatus(client, panel, nodes) { let row = [] if (client.config.button.enable) { - row = new MessageActionRow + const button = new MessageActionRow if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.url.length !== 0) { - row.addComponents( + button.addComponents( new MessageButton() .setLabel(client.config.button.btn1.label) .setStyle('LINK') @@ -117,7 +115,7 @@ module.exports = async function postStatus(client, panel, nodes) { ) } if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.url.length !== 0) { - row.addComponents( + button.addComponents( new MessageButton() .setLabel(client.config.button.btn2.label) .setStyle('LINK') @@ -125,7 +123,7 @@ module.exports = async function postStatus(client, panel, nodes) { ) } if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.url.length !== 0) { - row.addComponents( + button.addComponents( new MessageButton() .setLabel(client.config.button.btn3.label) .setStyle('LINK') @@ -133,7 +131,7 @@ module.exports = async function postStatus(client, panel, nodes) { ) } if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.url.length !== 0) { - row.addComponents( + button.addComponents( new MessageButton() .setLabel(client.config.button.btn4.label) .setStyle('LINK') @@ -141,7 +139,7 @@ module.exports = async function postStatus(client, panel, nodes) { ) } if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.url.length !== 0) { - row.addComponents( + button.addComponents( new MessageButton() .setLabel(client.config.button.btn5.label) .setStyle('LINK') @@ -149,10 +147,10 @@ module.exports = async function postStatus(client, panel, nodes) { ) } - row = [row] + row.push(button) } - if (!messages) channel.send({ embeds: [embed] }) + if (!messages) channel.send({ embeds: [embed], components: row }) else messages.edit({ embeds: [embed], components: row }) console.log(chalk.cyan('[PteroStats]') + chalk.green(' Stats posted!')) }) diff --git a/index.js b/index.js index 599a3dc..499866b 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ const fs = require('fs'); -const child = require("child_process") +const child = require('child_process'); if (Number(process.version.split('.')[0]) < 16) { console.log('Invalid NodeJS Version!, Please use NodeJS 16.x or upper') @@ -12,16 +12,20 @@ if (fs.existsSync('./node_modules')) { process.exit() } } else { - console.log('You are not installing package first, please wait until Auto Installer complete.') - child.execSync('npm i').catch((err) => { - console.log('An error detected: ', err) - console.log('Need Support? https://discord.gg/zv6maQRah3') - process.exit() - }) - console.log("Auto Installer complete! Please re run this bot!") - process.exit() + console.log('You didn\'t install the required node packages first!') + console.log('Please wait... starting to install all required node packages using child process') + try { + child.execSync('npm i') + console.log('Install complete!, please run "node index" command again!') + process.exit() + } catch (err) { + console.log('Err! ', err) + console.log('Support Server: https://discord.gg/zv6maQRah3') + process.exit() + } } +const chalk = require('chalk'); const yaml = require('js-yaml'); const { Client, Intents } = require('discord.js'); const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); @@ -43,9 +47,9 @@ for (const file of eventFiles) { } // Login to bot -try { - client.login(config.token); -} catch (Err) { - console.log('Invalid discord bot token') +if (client.config.token.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Discord Bot Token')) process.exit() } + +client.login(config.token); \ No newline at end of file From 6d9e1a05e074654a1791195335915f093c8aa289 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Thu, 16 Jun 2022 20:25:43 +0700 Subject: [PATCH 12/27] Fix bot status --- events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/ready.js b/events/ready.js index ea01800..c42a823 100644 --- a/events/ready.js +++ b/events/ready.js @@ -14,7 +14,7 @@ module.exports = { if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type)) { console.log('Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"') } else { - client.user.setActivity(client.config.status.text, { type: client.config.status.type }) + client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type }) } } From e2db2bb4034e81fee53a7160c83e57c13cd866ec Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Thu, 16 Jun 2022 21:04:29 +0700 Subject: [PATCH 13/27] Gonna do another update later --- handlers/checkStatus.js | 1 - handlers/postStatus.js | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index d8763bb..bc30909 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -25,7 +25,6 @@ module.exports = async function checkStatus(client) { const nodes = [] const panel = { - id: 1, status: false, total_servers: -1, total_users: -1, diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 5e46fa3..02a1b2d 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -40,25 +40,25 @@ module.exports = async function postStatus(client, panel, nodes) { switch (client.config.resource.unit) { case 'gb': description = description + - 'Memory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' Gb /' + Math.floor(data.memory_max / 1000).toLocaleString() + ' Gb\n' + - 'Disk : ' + Math.floor(data.disk_min / 1000).toLocaleString() + 'Gb /' + Math.floor(data.disk_max / 1000).toLocaleString() + ' Gb\n' + '\nMemory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1000).toLocaleString() + ' GB' + + '\nDisk : ' + Math.floor(data.disk_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.disk_max / 1000).toLocaleString() + ' GB' break; case 'percent': description = description + - 'Memory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %\n' + - 'Disk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %\n' + '\nMemory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %' + + '\nDisk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %' break; default: description = description + - 'Memory : ' + data.memory_min.toLocaleString() + ' Mb /' + data.memory_max.toLocaleString() + ' Mb\n' + - 'Disk : ' + data.disk_min.toLocaleString() + 'Mb /' + data.disk_max.toLocaleString() + ' Mb\n' + '\nMemory : ' + data.memory_min.toLocaleString() + ' MB / ' + data.memory_max.toLocaleString() + ' MB' + + '\nDisk : ' + data.disk_min.toLocaleString() + ' MB / ' + data.disk_max.toLocaleString() + ' MB' } - if (client.config.resource.location) description = description + 'Location: ' + data.location + '\n' - if (client.config.resource.allocations) description = description + 'Allocations : ' + data.allocations.toLocaleString() + '\n' - if (client.config.resource.servers) description = description + 'Servers : ' + data.total_servers.toLocaleString() + '\n' + if (client.config.resource.servers) description = description + '\nServers : ' + data.total_servers.toLocaleString() + if (client.config.resource.location) description = description + '\nLocation : ' + data.location + if (client.config.resource.allocations) description = description + '\nAllocations : ' + data.allocations.toLocaleString() - description = description + '```' + description = description + '\n```' if (client.config.resource.enable) { text = text + '\n**' + title.replace(':', ':**') + '\n' + description @@ -102,7 +102,7 @@ module.exports = async function postStatus(client, panel, nodes) { embed.setTimestamp() - let row = [] + const row = [] if (client.config.button.enable) { const button = new MessageActionRow From 0f1e81190482adeac00a5cab8320bc785481fac3 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Fri, 17 Jun 2022 21:49:21 +0700 Subject: [PATCH 14/27] Blacklist Nodes and other fix --- config.yml | 3 +- events/ready.js | 2 +- handlers/postStatus.js | 70 ++++++++++++++++++++++++------------------ 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/config.yml b/config.yml index e543a4a..ccc2ab4 100644 --- a/config.yml +++ b/config.yml @@ -57,8 +57,9 @@ status: offline: ':red_circle: Offline' # Node Resource -resource: +nodes_resource: enable: false + blacklist: [] # You can add node id to remove the node from status embed (Example: "blacklist: [1]") servers: true location: true allocations: true diff --git a/events/ready.js b/events/ready.js index c42a823..9f07849 100644 --- a/events/ready.js +++ b/events/ready.js @@ -8,7 +8,7 @@ module.exports = { console.log(chalk.cyan('[PteroStats]') + chalk.green(' Bot is up!')) console.log(chalk.cyan('[PteroStats]') + chalk.green(' If you need support you can join our discord server https://discord.gg/zv6maQRah3')) - if (client.guilds.cache.size === 0) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' There is bot is not in servers, please invite the bot first!')) + if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' There is bot is not in servers, please invite the bot first!')) if (client.config.bot_status.enable) { if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type)) { diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 02a1b2d..9853729 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -3,7 +3,11 @@ const chalk = require('chalk') module.exports = async function postStatus(client, panel, nodes) { - if (client.guilds.cache.size === 0) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' This bot is not on any discord servers')) + if (!client.config.nodes_resource) client.config.nodes_resource = client.config.resource + if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] + if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] + + if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' This bot is not on any discord servers')) const channel = await client.channels.cache.get(client.config.channel) @@ -11,7 +15,7 @@ module.exports = async function postStatus(client, panel, nodes) { let messages = await channel.messages.fetch({ limit: 10 }) messages = messages.filter(m => m.author.id === client.user.id).last(); - if (messages && messages.embeds.length === 0) { + if (messages && messages.embeds.length < 1) { messages.delete() messages = null } @@ -21,6 +25,7 @@ module.exports = async function postStatus(client, panel, nodes) { let text = '' let desc = '' + let blacklist = 0 if (client.config.embed.title) embed.setTitle(client.config.embed.title) if (client.config.embed.description) desc = client.config.embed.description.replaceAll('{{time}}', format) + '\n' @@ -35,42 +40,47 @@ module.exports = async function postStatus(client, panel, nodes) { const stats = new Promise((resolve, reject) => { if (nodes.length !== 0) { nodes.forEach((data, i) => { - const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) - let description = '```' - switch (client.config.resource.unit) { - case 'gb': - description = description + - '\nMemory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1000).toLocaleString() + ' GB' + - '\nDisk : ' + Math.floor(data.disk_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.disk_max / 1000).toLocaleString() + ' GB' - break; - case 'percent': - description = description + - '\nMemory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %' + - '\nDisk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %' - break; - default: - description = description + - '\nMemory : ' + data.memory_min.toLocaleString() + ' MB / ' + data.memory_max.toLocaleString() + ' MB' + - '\nDisk : ' + data.disk_min.toLocaleString() + ' MB / ' + data.disk_max.toLocaleString() + ' MB' - } + if (!client.config.nodes_resource.blacklist.includes(data.id)) { + blacklist = blacklist + 1 + const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + let description = '```' + switch (client.config.nodes_resource.unit) { + case 'gb': + description = description + + '\nMemory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1000).toLocaleString() + ' GB' + + '\nDisk : ' + Math.floor(data.disk_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.disk_max / 1000).toLocaleString() + ' GB' + break; + case 'percent': + description = description + + '\nMemory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %' + + '\nDisk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %' + break; + default: + description = description + + '\nMemory : ' + data.memory_min.toLocaleString() + ' MB / ' + data.memory_max.toLocaleString() + ' MB' + + '\nDisk : ' + data.disk_min.toLocaleString() + ' MB / ' + data.disk_max.toLocaleString() + ' MB' + } - if (client.config.resource.servers) description = description + '\nServers : ' + data.total_servers.toLocaleString() - if (client.config.resource.location) description = description + '\nLocation : ' + data.location - if (client.config.resource.allocations) description = description + '\nAllocations : ' + data.allocations.toLocaleString() + if (client.config.nodes_resource.servers) description = description + '\nServers : ' + data.total_servers.toLocaleString() + if (client.config.nodes_resource.location) description = description + '\nLocation : ' + data.location + if (client.config.nodes_resource.allocations) description = description + '\nAllocations : ' + data.allocations.toLocaleString() - description = description + '\n```' + description = description + '\n```' - if (client.config.resource.enable) { - text = text + '\n**' + title.replace(':', ':**') + '\n' + description + if (client.config.nodes_resource.enable) { + text = text + '\n**' + title.replace(':', ':**') + '\n' + description + } else { + text = text + '\n**' + title.replace(':', ':**') + } } else { - text = text + '\n**' + title.replace(':', ':**') + if (nodes.length - client.config.nodes_resource.blacklist < 1) text = '\nThere is no nodes to display' } if (i + 1 === nodes.length) resolve() }) - } else if (nodes.length === 0) { + } else if (nodes.length < 1) { if (!messages) { - text = 'There is no nodes to display' + text = '\nThere is no nodes to display' resolve() } else { text = messages.embeds[0].description.replaceAll(client.config.status.online, client.config.status.offline) @@ -85,7 +95,7 @@ module.exports = async function postStatus(client, panel, nodes) { stats.then(async () => { - embed.setDescription(desc + '\n**Nodes Stats [' + nodes.length + ']**' + text) + embed.setDescription(desc + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) if (client.config.panel_resource.enable) { let stats = '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' From 69314d34aa984a13257cec1abf7c616c77697a6a Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sat, 18 Jun 2022 19:51:16 +0700 Subject: [PATCH 15/27] Update readme, info about blacklist node --- Indo.md | 17 +++++++++++++++++ README.md | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Indo.md b/Indo.md index c51f8a5..0575ddc 100644 --- a/Indo.md +++ b/Indo.md @@ -66,6 +66,23 @@ Jika kamu mendapat masalah bisa dm `Hirzi#8701` didiscord atau join [server supp ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) +### Blaclist Nodes +1. Pilih node yang ada di node list admin page + + ![Nodes List](https://usercontent.catto.pictures/hirzi/5699fdbd-7c3c-4fa5-ae2c-d0ccb39cb69e.png) + +2. Cek urlnya dan copy id nodenya + + ![Node Id](https://usercontent.catto.pictures/hirzi/45f855fc-6d96-4b23-a96e-892071189d01.png) + +3. Masukan ke blacklist di config + + ![Blacklist Config](https://usercontent.catto.pictures/hirzi/9c40da3d-fa01-447e-aa86-7871da9da282.png) + +Kamu bisa masukin lebih dari 1 node untuk di blacklist + +![Blacklist Config](https://usercontent.catto.pictures/hirzi/f2a34ca9-accf-4d31-a246-f9dcc6a2fd75.png) + ## Permission apikey Pilih Aktifkan `read` di semua opsi permission, jika tetap error pilih `read & write` di semua opsi permission diff --git a/README.md b/README.md index 0ef2e7c..305164c 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,23 @@ if you need help contact me on discord `Hirzi#8701` or join [our discord support ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) +### Blaclist Nodes +1. Select node from node list on admin page + + ![Nodes List](https://usercontent.catto.pictures/hirzi/5699fdbd-7c3c-4fa5-ae2c-d0ccb39cb69e.png) + +2. Check the url and copy the node id + + ![Node Id](https://usercontent.catto.pictures/hirzi/45f855fc-6d96-4b23-a96e-892071189d01.png) + +3. Add the id to the blacklist on config + + ![Blacklist Config](https://usercontent.catto.pictures/hirzi/9c40da3d-fa01-447e-aa86-7871da9da282.png) + +You can add more than one node in the blaclist + +![Blacklist Config](https://usercontent.catto.pictures/hirzi/f2a34ca9-accf-4d31-a246-f9dcc6a2fd75.png) + ## Admin Apikey Permission enable `read` on all options, if still didn't work enable `read & write` on all options From 5fd4085604aa5601f137aa882ee0e7f840570b48 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sat, 18 Jun 2022 19:52:52 +0700 Subject: [PATCH 16/27] Change License --- LICENSE | 214 +++++--------------------------------------------------- 1 file changed, 17 insertions(+), 197 deletions(-) diff --git a/LICENSE b/LICENSE index 261eeb9..df40dd6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +MIT License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Copyright (c) 2022 HirziDevs - 1. Definitions. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From da94f2f56d5662a3b74b3a0c6395a100f690d736 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sat, 18 Jun 2022 19:59:34 +0700 Subject: [PATCH 17/27] Update package.json --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 397c07f..59559dd 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "pterostats", "version": "v2.0.0", - "description": "PteroStats is a bot designed to check Panel, Nodes, and Databases status and post it to your discord server", - "license": "Apache-2.0", + "description": "PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server", + "license": "MIT", "repository": "HirziDevs/PteroStats", "homepage": "https://pterostats.hirzidevs.net", "bugs": { @@ -15,10 +15,10 @@ "dependencies": { "axios": "^0.26.1", "chalk": "4.1.1", - "discord.js": "^13.7.0", + "discord.js": "^13.8.0", "js-yaml": "^4.1.0" }, "engines": { "node": "16.x" } -} +} \ No newline at end of file From 6cb3cf1f44fb365fd15f757d38c80bc7b0ad0a79 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sat, 18 Jun 2022 20:33:08 +0700 Subject: [PATCH 18/27] Fix typo --- Indo.md | 6 +++--- README.md | 4 ++-- config.yml | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Indo.md b/Indo.md index 0575ddc..4d8911b 100644 --- a/Indo.md +++ b/Indo.md @@ -66,7 +66,7 @@ Jika kamu mendapat masalah bisa dm `Hirzi#8701` didiscord atau join [server supp ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) -### Blaclist Nodes +### Blacklist Nodes 1. Pilih node yang ada di node list admin page ![Nodes List](https://usercontent.catto.pictures/hirzi/5699fdbd-7c3c-4fa5-ae2c-d0ccb39cb69e.png) @@ -79,11 +79,11 @@ Jika kamu mendapat masalah bisa dm `Hirzi#8701` didiscord atau join [server supp ![Blacklist Config](https://usercontent.catto.pictures/hirzi/9c40da3d-fa01-447e-aa86-7871da9da282.png) -Kamu bisa masukin lebih dari 1 node untuk di blacklist +Kamu bisa memasukan lebih dari 1 node untuk di blacklist ![Blacklist Config](https://usercontent.catto.pictures/hirzi/f2a34ca9-accf-4d31-a246-f9dcc6a2fd75.png) -## Permission apikey +## Permission apikey Pilih Aktifkan `read` di semua opsi permission, jika tetap error pilih `read & write` di semua opsi permission diff --git a/README.md b/README.md index 305164c..fd6b42c 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ if you need help contact me on discord `Hirzi#8701` or join [our discord support ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) -### Blaclist Nodes +### Blacklist Nodes 1. Select node from node list on admin page ![Nodes List](https://usercontent.catto.pictures/hirzi/5699fdbd-7c3c-4fa5-ae2c-d0ccb39cb69e.png) @@ -79,7 +79,7 @@ if you need help contact me on discord `Hirzi#8701` or join [our discord support ![Blacklist Config](https://usercontent.catto.pictures/hirzi/9c40da3d-fa01-447e-aa86-7871da9da282.png) -You can add more than one node in the blaclist +You can add more than one node in the blacklist ![Blacklist Config](https://usercontent.catto.pictures/hirzi/f2a34ca9-accf-4d31-a246-f9dcc6a2fd75.png) diff --git a/config.yml b/config.yml index ccc2ab4..e97b2d7 100644 --- a/config.yml +++ b/config.yml @@ -2,24 +2,24 @@ # If you need help, join our discord server here: https://discord.gg/zv6maQRah3 # Bot Configuration -token: 'Put bot token here' +token: 'Put bot token here' bot_status: enable: false - text: 'Hosting Panel' + text: 'Hosting Panel' type: 'WATCHING' # can be 'WATCHING', 'PLAYING', 'LISTENING', or 'COMPETING'. for 'STREAMING' is not working for now # Discord Channel and Refresh Time Configuration -channel: 'Put channel id here' +channel: 'Put channel id here' refresh: 60 # Panel Configuration panel: - url: 'Put panel url here' + url: 'Put panel url here' key: 'Put panel apikey here' # Embed Configuration # set to false if you want to disable embed option -embed: +embed: title: 'PteroStats' color: '5865F2' description: 'Next update {{time}}' # You can use {{time}} to make "in X seconds" time format @@ -35,7 +35,7 @@ embed: # Message Button Configuration button: enable: true - btn1: + btn1: label: 'PteroStats' url: 'https://github.com/HirziDevs/PteroStats' btn2: @@ -50,18 +50,18 @@ button: btn5: label: '' url: '' - + # Status Message Configuration status: online: ':green_circle: Online' offline: ':red_circle: Offline' -# Node Resource +# Nodes Resource nodes_resource: enable: false blacklist: [] # You can add node id to remove the node from status embed (Example: "blacklist: [1]") servers: true - location: true + location: true allocations: true unit: 'gb' # You can use "gb", "mb", or "percent" From 277251c15e3aa55dcbacfb6392ffdb91d2f30d92 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sun, 19 Jun 2022 14:37:27 +0700 Subject: [PATCH 19/27] Some changes --- Indo.md | 15 +++++++++++---- README.md | 15 +++++++++++---- config.yml | 2 +- events/ready.js | 4 ++-- handlers/checkStatus.js | 22 +++++++++++----------- handlers/postStatus.js | 6 +++--- index.js | 7 ++----- 7 files changed, 41 insertions(+), 30 deletions(-) diff --git a/Indo.md b/Indo.md index 4d8911b..dc60b8f 100644 --- a/Indo.md +++ b/Indo.md @@ -11,23 +11,30 @@ PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl dan dikirim ke server discord ## Instalasi + - [Mendapatkan apikey dari pterodactyl](#mendapatkan-apikey-dari-pterodactyl) + - [Membuat Discord Bot](#membuat-discord-bot) + - [Menginvite Discord Bot](#menginvite-discord-bot) + - [Mendapatkan Channel ID](#mendapatkan-channel-id) + - [Memulai Bot](#memulai-bot) + - [Mengunakan custom emoji](#mengunakan-custom-emoji) + - [Blacklist Nodes](#blacklist-nodes) ### Mendapatkan apikey dari pterodactyl - Pergi ke `panel admin pterodactyl` dan pergi ke `Application API` - ![Admin Panel](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) + ![Admin Panel](https://usercontent.catto.pictures/hirzi/aabafe57-cbfe-4d7f-9d6d-4a63a7f23d4c.png) - Klik tombol `Create New` - ![Application API Page](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) + ![Application API Page](https://usercontent.catto.pictures/hirzi/f916f0c6-0968-4125-8226-ba4daa1de902.png) - Set semua permission ke `read` dan untuk description kamu bisa mengisi apa saja - ![Create Application API](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) + ![Create Application API](https://usercontent.catto.pictures/hirzi/3e4575cb-4f52-4bd9-9091-36fda20bedad.png) - Copy apikey-nya. - ![Application API List](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) + ![Application API List](https://usercontent.catto.pictures/hirzi/9142b0b3-0556-4741-840c-6976c3fe3ad4.png) ### Membuat Discord Bot Kalian bisa cek [website ini](https://discordjs.guide/preparations/setting-up-a-bot-application.html) diff --git a/README.md b/README.md index fd6b42c..88d5880 100644 --- a/README.md +++ b/README.md @@ -11,23 +11,30 @@ PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server ## Installation +- [Getting apikey from pterodactyl](#getting-apikey-from-pterodactyl) +- [Creating Discord Bot](#creating-discord-bot) +- [Inviting Discord Bot](#inviting-discord-bot) +- [Getting Channel ID](#getting-channel-id) +- [Starting bot](#starting-bot) +- [Using Custom Emoji](#using-custom-emoji) +- [Blacklist Nodes](#blacklist-nodes) ### Getting apikey from pterodactyl - Go to your `pterodactyl admin page` and go to `Application API`. - ![Admin Panel](https://usercontent.catto.pictures/hirzi/d5225df9-7395-491b-a214-dcd110b12308.png) + ![Admin Panel](https://usercontent.catto.pictures/hirzi/aabafe57-cbfe-4d7f-9d6d-4a63a7f23d4c.png) - Click on the `Create New` button - ![Application API Page](https://usercontent.catto.pictures/hirzi/5ac33e25-ac37-416a-99a6-46d860a51645.png) + ![Application API Page](https://usercontent.catto.pictures/hirzi/f916f0c6-0968-4125-8226-ba4daa1de902.png) - Set all options permission to `read` and for description you can put whatever you want - ![Create Application API](https://usercontent.catto.pictures/hirzi/a0c4a721-e1eb-483f-9a36-0c2aaa213186.png) + ![Create Application API](https://usercontent.catto.pictures/hirzi/3e4575cb-4f52-4bd9-9091-36fda20bedad.png) - Copy the apikey. - ![Application API List](https://usercontent.catto.pictures/hirzi/086111e0-0ffa-48ee-8839-801e0c3678cc.png) + ![Application API List](https://usercontent.catto.pictures/hirzi/9142b0b3-0556-4741-840c-6976c3fe3ad4.png) ### Creating Discord Bot Please refer to [this website](https://discordjs.guide/preparations/setting-up-a-bot-application.html) diff --git a/config.yml b/config.yml index e97b2d7..a049ef8 100644 --- a/config.yml +++ b/config.yml @@ -58,8 +58,8 @@ status: # Nodes Resource nodes_resource: - enable: false blacklist: [] # You can add node id to remove the node from status embed (Example: "blacklist: [1]") + enable: false servers: true location: true allocations: true diff --git a/events/ready.js b/events/ready.js index 9f07849..234338e 100644 --- a/events/ready.js +++ b/events/ready.js @@ -4,7 +4,7 @@ const checkStatus = require('../handlers/checkStatus') module.exports = { name: 'ready', once: true, - async execute(client) { + execute(client) { console.log(chalk.cyan('[PteroStats]') + chalk.green(' Bot is up!')) console.log(chalk.cyan('[PteroStats]') + chalk.green(' If you need support you can join our discord server https://discord.gg/zv6maQRah3')) @@ -22,7 +22,7 @@ module.exports = { checkStatus(client) - setInterval(async () => { + setInterval(() => { checkStatus(client) }, client.config.refresh * 1000) } diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index bc30909..2f2f53e 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -3,7 +3,7 @@ const chalk = require('chalk') const postStatus = require('./postStatus') -module.exports = async function checkStatus(client) { +module.exports = function checkStatus(client) { if (client.config.channel.startsWith('Put')) { console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Channel ID')) @@ -40,7 +40,7 @@ module.exports = async function checkStatus(client) { 'Content-Type': 'application/json', Authorization: 'Bearer ' + client.config.panel.key } - }).then(usr => { + }).then((usr) => { axios(client.config.panel.url + '/api/application/servers', { method: 'GET', headers: { @@ -48,14 +48,14 @@ module.exports = async function checkStatus(client) { 'Content-Type': 'application/json', Authorization: 'Bearer ' + client.config.panel.key } - }).then(async (ser) => { + }).then((ser) => { panel.total_users = usr.data.meta.pagination.total panel.total_servers = ser.data.meta.pagination.total panel.status = true resolve() }) - }).catch(async (err) => { + }).catch((err) => { if (err.response) { if (err.response.status === 403) { console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid apikey')) @@ -79,8 +79,8 @@ module.exports = async function checkStatus(client) { 'Content-Type': 'application/json', Authorization: 'Bearer ' + client.config.panel.key } - }).then(async (res) => { - res.data.data.forEach(async (node, i) => { + }).then((res) => { + res.data.data.forEach((node) => { axios(client.config.panel.url + '/api/application/nodes/' + node.attributes.id + '/configuration', { method: 'GET', headers: { @@ -88,7 +88,7 @@ module.exports = async function checkStatus(client) { 'Content-Type': 'application/json', Authorization: 'Bearer ' + client.config.panel.key } - }).then(async (data) => { + }).then((data) => { const body = { id: node.attributes.id, name: node.attributes.name, @@ -111,9 +111,9 @@ module.exports = async function checkStatus(client) { 'Content-Type': 'application/json', Authorization: 'Bearer ' + data.data.token } - }).then(async (status) => { + }).then((status) => { statsResolve() - }).catch(async (err) => { + }).catch((err) => { body.status = false statsResolve() }) @@ -122,11 +122,11 @@ module.exports = async function checkStatus(client) { nodes.push(body) resolve() }) - }).catch(async (err) => { + }).catch((err) => { resolve() }) }) - }).catch(async (err) => { + }).catch((err) => { resolve() }) }) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 9853729..c738889 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -41,7 +41,6 @@ module.exports = async function postStatus(client, panel, nodes) { if (nodes.length !== 0) { nodes.forEach((data, i) => { if (!client.config.nodes_resource.blacklist.includes(data.id)) { - blacklist = blacklist + 1 const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) let description = '```' switch (client.config.nodes_resource.unit) { @@ -73,7 +72,8 @@ module.exports = async function postStatus(client, panel, nodes) { text = text + '\n**' + title.replace(':', ':**') } } else { - if (nodes.length - client.config.nodes_resource.blacklist < 1) text = '\nThere is no nodes to display' + blacklist = blacklist + 1 + if (nodes.length - client.config.nodes_resource.blacklist.length < 1) text = '\nThere is no nodes to display' } if (i + 1 === nodes.length) resolve() @@ -93,7 +93,7 @@ module.exports = async function postStatus(client, panel, nodes) { } }) - stats.then(async () => { + stats.then(() => { embed.setDescription(desc + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) diff --git a/index.js b/index.js index 499866b..5df5536 100644 --- a/index.js +++ b/index.js @@ -30,23 +30,20 @@ const yaml = require('js-yaml'); const { Client, Intents } = require('discord.js'); const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); -// Load Config const config = yaml.load(fs.readFileSync('./config.yml', 'utf8')); client.config = config -// Read Events Files const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); for (const file of eventFiles) { const event = require(`./events/${file}`); if (event.once) { - client.once(event.name, (client) => event.execute(client)); + client.once(event.name, (...args) => event.execute(...args)); } else { - client.on(event.name, (client) => event.execute(client)); + client.on(event.name, (...args) => event.execute(...args)); } } -// Login to bot if (client.config.token.startsWith('Put')) { console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Discord Bot Token')) process.exit() From 1d0c7c503e5ff3fe39004592beed7ef5d8486263 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sun, 19 Jun 2022 22:16:34 +0700 Subject: [PATCH 20/27] Update readme and some another changes --- Indo.md | 80 ++++++++++++++++++++++++--------------- README.md | 84 +++++++++++++++++++++++++---------------- events/ready.js | 8 ++-- handlers/checkStatus.js | 28 +++++++------- handlers/postStatus.js | 6 +-- 5 files changed, 121 insertions(+), 85 deletions(-) diff --git a/Indo.md b/Indo.md index dc60b8f..c9e0003 100644 --- a/Indo.md +++ b/Indo.md @@ -1,6 +1,6 @@
-![PteroStats Banner](https://cdn.discordapp.com/attachments/626755594526916629/978478722489393153/20220524_090325.png) +PteroStats Banner ## Bahasa / Language [[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.md) | [[Inggris]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) @@ -10,91 +10,109 @@ ## Pengenalan PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl dan dikirim ke server discord +## Contoh +Example + ## Instalasi - - [Mendapatkan apikey dari pterodactyl](#mendapatkan-apikey-dari-pterodactyl) - - [Membuat Discord Bot](#membuat-discord-bot) - - [Menginvite Discord Bot](#menginvite-discord-bot) - - [Mendapatkan Channel ID](#mendapatkan-channel-id) - - [Memulai Bot](#memulai-bot) + 1. [Mendapatkan apikey dari pterodactyl](#mendapatkan-apikey-dari-pterodactyl) + 2. [Membuat Discord Bot](#membuat-discord-bot) + 3. [Menginvite Discord Bot](#menginvite-discord-bot) + 4. [Mendapatkan Channel ID](#mendapatkan-channel-id) + 5. [Memulai Bot](#memulai-bot) + - [Mengunakan custom emoji](#mengunakan-custom-emoji) - [Blacklist Nodes](#blacklist-nodes) ### Mendapatkan apikey dari pterodactyl -- Pergi ke `panel admin pterodactyl` dan pergi ke `Application API` +1. Pergi ke `panel admin pterodactyl` dan pergi ke `Application API` - ![Admin Panel](https://usercontent.catto.pictures/hirzi/aabafe57-cbfe-4d7f-9d6d-4a63a7f23d4c.png) + Admin Panel -- Klik tombol `Create New` +2. Klik tombol `Create New` - ![Application API Page](https://usercontent.catto.pictures/hirzi/f916f0c6-0968-4125-8226-ba4daa1de902.png) + Application API Page -- Set semua permission ke `read` dan untuk description kamu bisa mengisi apa saja +3. Set semua permission ke `read` dan untuk description kamu bisa mengisi apa saja - ![Create Application API](https://usercontent.catto.pictures/hirzi/3e4575cb-4f52-4bd9-9091-36fda20bedad.png) + Create Application API -- Copy apikey-nya. +4. Copy apikey-nya. - ![Application API List](https://usercontent.catto.pictures/hirzi/9142b0b3-0556-4741-840c-6976c3fe3ad4.png) + Application API List + +5. Paste panel apikeynya dan panel urlnya di config + + Panel Config ### Membuat Discord Bot Kalian bisa cek [website ini](https://discordjs.guide/preparations/setting-up-a-bot-application.html) +Paste bot tokennya di config + +Bot Config + ### Menginvite Discord Bot Kalian bisa cek [website ini](https://discordjs.guide/preparations/adding-your-bot-to-servers.html) ### Mendapatkan Channel ID 1. Aktifkan `Developer Mode` di settings discord kamu - ![Discord User Settings](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) + Discord User Settings 2. Klik kanan teks channel dan pilih `Copy ID` - ![Klik Kanan Channel](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) + Right Click Channel + +3. Paste id channelnya di config + + Channel Config ### Memulai Bot -- Masukan `token` bot discord di `line token` yang terdapat di file `config.yml` -- Copy `id channel` diserver discord kamu dan masukan ke line `channel` di file `config.yml` -- Masukan `apikey` dan `url` pterodactyl di `line panel` di file `config.yml` -- Jalankan command `npm install` di folder yang berisi file bot -- Jalankan command `node index` dan kamu selesai! +1. Pastikan kamu telah melakukan semua yang ada diatas +2. Jalankan command `npm install` di folder yang berisi file bot +3. Jalankan command `node index` dan kamu selesai! Jika kamu mendapat masalah bisa dm `Hirzi#8701` didiscord atau join [server support kami](https://discord.gg/zv6maQRah3) ### Mengunakan custom emoji 1. ketik `\` di server yang ada custom emojinya - ![Type \ on the chat](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) + Type \ on the chat 2. Pilih custom emoji yang kamu mau - ![Select Custom Emoji](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) + Select Custom Emoji 3. Copy textnya! - ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) + Copy Emoji ID + +4. Paste id emojinya di config + + Status Config ### Blacklist Nodes 1. Pilih node yang ada di node list admin page - - ![Nodes List](https://usercontent.catto.pictures/hirzi/5699fdbd-7c3c-4fa5-ae2c-d0ccb39cb69e.png) + + Nodes List 2. Cek urlnya dan copy id nodenya - ![Node Id](https://usercontent.catto.pictures/hirzi/45f855fc-6d96-4b23-a96e-892071189d01.png) + Node Id 3. Masukan ke blacklist di config - ![Blacklist Config](https://usercontent.catto.pictures/hirzi/9c40da3d-fa01-447e-aa86-7871da9da282.png) + Blacklist Config Kamu bisa memasukan lebih dari 1 node untuk di blacklist -![Blacklist Config](https://usercontent.catto.pictures/hirzi/f2a34ca9-accf-4d31-a246-f9dcc6a2fd75.png) +Blacklist Config ## Permission apikey -Pilih Aktifkan `read` di semua opsi permission, jika tetap error pilih `read & write` di semua opsi permission +Jika kamu mengalami error 403 coba aktifkan `read & write` di semua opsi permission -![Application API Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) +Application API Permission ## Links diff --git a/README.md b/README.md index 88d5880..2a46ba9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-![PteroStats Banner](https://cdn.discordapp.com/attachments/626755594526916629/978478722489393153/20220524_090325.png) +PteroStats Banner ## Language / Bahasa [[English]](https://github.com/HirziDevs/PteroStats/blob/dev/README.md) | [[Indonesia]](https://github.com/HirziDevs/PteroStats/blob/dev/Indo.md) @@ -10,91 +10,109 @@ ## Introduction PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server +## Example +Example + ## Installation -- [Getting apikey from pterodactyl](#getting-apikey-from-pterodactyl) -- [Creating Discord Bot](#creating-discord-bot) -- [Inviting Discord Bot](#inviting-discord-bot) -- [Getting Channel ID](#getting-channel-id) -- [Starting bot](#starting-bot) +1. [Getting apikey from pterodactyl](#getting-apikey-from-pterodactyl) +2. [Creating Discord Bot](#creating-discord-bot) +3. [Inviting Discord Bot](#inviting-discord-bot) +4. [Getting Channel ID](#getting-channel-id) +5. [Starting bot](#starting-bot) + - [Using Custom Emoji](#using-custom-emoji) - [Blacklist Nodes](#blacklist-nodes) ### Getting apikey from pterodactyl -- Go to your `pterodactyl admin page` and go to `Application API`. +1. Go to your `pterodactyl admin page` and go to `Application API`. - ![Admin Panel](https://usercontent.catto.pictures/hirzi/aabafe57-cbfe-4d7f-9d6d-4a63a7f23d4c.png) + Admin Panel -- Click on the `Create New` button +2. Click on the `Create New` button - ![Application API Page](https://usercontent.catto.pictures/hirzi/f916f0c6-0968-4125-8226-ba4daa1de902.png) + Application API Page -- Set all options permission to `read` and for description you can put whatever you want +3. Set all options permission to `read` and for description you can put whatever you want - ![Create Application API](https://usercontent.catto.pictures/hirzi/3e4575cb-4f52-4bd9-9091-36fda20bedad.png) + Create Application API -- Copy the apikey. +4. Copy the apikey. - ![Application API List](https://usercontent.catto.pictures/hirzi/9142b0b3-0556-4741-840c-6976c3fe3ad4.png) + Application API List + +5. Paste the panel apikey and panel url at the config + + Panel Config ### Creating Discord Bot Please refer to [this website](https://discordjs.guide/preparations/setting-up-a-bot-application.html) +Paste the bot token at the config + +Bot Config + ### Inviting Discord Bot Please refer to [this website](https://discordjs.guide/preparations/adding-your-bot-to-servers.html) ### Getting Channel ID 1. Enable Developer Feature at your discord settings - ![Discord User Settings](https://usercontent.catto.pictures/hirzi/c5e825d1-c323-4b19-a11b-e2f004d4906e.png) + Discord User Settings 2. Right Click text channel and select `Copy ID` - ![Right Click Channel](https://usercontent.catto.pictures/hirzi/e5fa4f62-b28f-45fd-a544-429f23899edb.png) + Right Click Channel + +3. Paste the channel id at the config + + Channel Config ### Starting bot -- Put discord bot token in `config.yml` at `token line`. -- Put your pterodactyl `apikey` and `url` in `config.yml` at `panel line`. -- Copy `channel id` from your discord server and put it in `config.yml` file at `channel line`. -- Run `npm install` in the root directory of the bot files. -- Run `node index` and you are done. +1. Make sure you have done the things above +2. Run `npm install` in the root directory of the bot files. +3. Run `node index` and you are done. if you need help contact me on discord `Hirzi#8701` or join [our discord support server](https://discord.gg/zv6maQRah3) ### Using Custom Emoji 1. type `\` in guild that has custom emoji you want - ![Type \ on the chat](https://usercontent.catto.pictures/hirzi/1f59b255-7c5d-48f2-ab93-5358429cec83.png) + Type \ on the chat 2. Select custom emoji you want - ![Select Custom Emoji](https://usercontent.catto.pictures/hirzi/38098261-7257-4e4d-8945-4ac5c252c952.png) + Select Custom Emoji 3. Copy the text! - ![Copy Emoji ID](https://usercontent.catto.pictures/hirzi/33800ccf-9ed5-4d54-9747-2983b23e1755.png) + Copy Emoji ID + +4. Paste the emoji id at the config + + Status Config ### Blacklist Nodes 1. Select node from node list on admin page - - ![Nodes List](https://usercontent.catto.pictures/hirzi/5699fdbd-7c3c-4fa5-ae2c-d0ccb39cb69e.png) + + Nodes List 2. Check the url and copy the node id - ![Node Id](https://usercontent.catto.pictures/hirzi/45f855fc-6d96-4b23-a96e-892071189d01.png) + Node Id -3. Add the id to the blacklist on config +3. Paste the id to the blacklist on config - ![Blacklist Config](https://usercontent.catto.pictures/hirzi/9c40da3d-fa01-447e-aa86-7871da9da282.png) + Blacklist Config You can add more than one node in the blacklist -![Blacklist Config](https://usercontent.catto.pictures/hirzi/f2a34ca9-accf-4d31-a246-f9dcc6a2fd75.png) +Blacklist Config -## Admin Apikey Permission +## Apikey permission -enable `read` on all options, if still didn't work enable `read & write` on all options +If you having issue with 403 error try to enable `read & write` on all options -![Application API Permission](https://media.discordapp.net/attachments/819757140155564062/876320084992331816/Screenshot_2021-08-15-11-20-05-56.jpg) +Application API Permission ## Links diff --git a/events/ready.js b/events/ready.js index 234338e..fd993af 100644 --- a/events/ready.js +++ b/events/ready.js @@ -5,14 +5,14 @@ module.exports = { name: 'ready', once: true, execute(client) { - console.log(chalk.cyan('[PteroStats]') + chalk.green(' Bot is up!')) - console.log(chalk.cyan('[PteroStats]') + chalk.green(' If you need support you can join our discord server https://discord.gg/zv6maQRah3')) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('Bot is up!')) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('If you need support you can join our discord server https://discord.gg/zv6maQRah3')) - if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' There is bot is not in servers, please invite the bot first!')) + if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) if (client.config.bot_status.enable) { if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type)) { - console.log('Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"') + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"')) } else { client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type }) } diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index 2f2f53e..06f5b08 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -6,17 +6,17 @@ const postStatus = require('./postStatus') module.exports = function checkStatus(client) { if (client.config.channel.startsWith('Put')) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Channel ID')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Channel ID')) process.exit() } else if (client.config.panel.url.startsWith('Put')) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Panel URL')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) process.exit() } else if (client.config.panel.key.startsWith('Put')) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Apikey')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Apikey')) process.exit() } else if (!client.config.panel.url.startsWith('http')) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Panel URL')) - console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the panel url is starts with "https://" or "http://"')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the panel url is starts with "https://" or "http://"')) process.exit() } @@ -30,7 +30,7 @@ module.exports = function checkStatus(client) { total_users: -1, } - console.log(chalk.cyan('[PteroStats]') + chalk.green(' Getting nodes stats')) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('Getting nodes stats')) const panelStats = new Promise((resolve, reject) => { axios(client.config.panel.url + '/api/application/users', { @@ -58,15 +58,15 @@ module.exports = function checkStatus(client) { }).catch((err) => { if (err.response) { if (err.response.status === 403) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid apikey')) - console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the apikey is from admin page not account page')) - console.log(chalk.cyan('[PteroStats]') + chalk.red(' 2. Make sure the apikey has read permission on all options')) - console.log(chalk.cyan('[PteroStats]') + chalk.red(' 3. Make sure the apikey is exist')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid apikey')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the apikey is from admin page not account page')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('2. Make sure the apikey has read permission on all options')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('3. Make sure the apikey is exist')) } else if (err.response.status === 404) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Panel URL')) - console.log(chalk.cyan('[PteroStats]') + chalk.red(' 1. Make sure the panel url is like "https://panel.example.com"')) - } else console.log(chalk.cyan('[PteroStats] ') + err) - } else console.log(chalk.cyan('[PteroStats] ') + err) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the panel url is like "https://panel.example.com"')) + } else console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! ' + err)) + } else console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! ' + err)) resolve() }) }) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index c738889..8483e95 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -7,11 +7,11 @@ module.exports = async function postStatus(client, panel, nodes) { if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] - if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' This bot is not on any discord servers')) + if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) const channel = await client.channels.cache.get(client.config.channel) - if (!channel) return console.log(chalk.cyan('[PteroStats]') + chalk.red(' Invalid Channel ID')) + if (!channel) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Channel ID')) let messages = await channel.messages.fetch({ limit: 10 }) messages = messages.filter(m => m.author.id === client.user.id).last(); @@ -162,6 +162,6 @@ module.exports = async function postStatus(client, panel, nodes) { if (!messages) channel.send({ embeds: [embed], components: row }) else messages.edit({ embeds: [embed], components: row }) - console.log(chalk.cyan('[PteroStats]') + chalk.green(' Stats posted!')) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('Stats posted!')) }) } \ No newline at end of file From 9b962d0edde0760753e9ab11798e26675f4d0165 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Wed, 29 Jun 2022 07:20:40 +0700 Subject: [PATCH 21/27] FIx bot only show 1 nodes --- handlers/checkStatus.js | 4 ++-- handlers/postStatus.js | 1 + package.json | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index 06f5b08..03b15c0 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -80,7 +80,7 @@ module.exports = function checkStatus(client) { Authorization: 'Bearer ' + client.config.panel.key } }).then((res) => { - res.data.data.forEach((node) => { + res.data.data.forEach((node, i) => { axios(client.config.panel.url + '/api/application/nodes/' + node.attributes.id + '/configuration', { method: 'GET', headers: { @@ -120,7 +120,7 @@ module.exports = function checkStatus(client) { }) stats.then(() => { nodes.push(body) - resolve() + if (i + 1 === res.data.data.length) resolve() }) }).catch((err) => { resolve() diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 8483e95..f804519 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -6,6 +6,7 @@ module.exports = async function postStatus(client, panel, nodes) { if (!client.config.nodes_resource) client.config.nodes_resource = client.config.resource if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] + if (!['mb', 'gb', 'percent'].includes(client.config.nodes_resource.unit)) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Unit at nodes_resource')) if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) diff --git a/package.json b/package.json index 59559dd..5f0b5ac 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,12 @@ "start": "node index.js" }, "dependencies": { - "axios": "^0.26.1", + "axios": "^0.27.2", "chalk": "4.1.1", - "discord.js": "^13.8.0", + "discord.js": "^13.8.1", "js-yaml": "^4.1.0" }, "engines": { - "node": "16.x" + "node": "^16.x" } } \ No newline at end of file From 6f4c3f59fa37b5bfcbecc3bd98cbb7a29a9e4179 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Wed, 29 Jun 2022 09:08:43 +0700 Subject: [PATCH 22/27] Now you can add message content and image --- config.yml | 8 ++++++-- events/ready.js | 6 +++--- handlers/postStatus.js | 32 ++++++++++++++++---------------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/config.yml b/config.yml index a049ef8..0382d39 100644 --- a/config.yml +++ b/config.yml @@ -17,8 +17,12 @@ panel: url: 'Put panel url here' key: 'Put panel apikey here' -# Embed Configuration -# set to false if you want to disable embed option +# Message Configuration +# set to false if you want to disable option +message: + content: false + image: false # If you enable image on message it upload the image first before sending or editing message and it will delay stats + embed: title: 'PteroStats' color: '5865F2' diff --git a/events/ready.js b/events/ready.js index fd993af..c486380 100644 --- a/events/ready.js +++ b/events/ready.js @@ -11,14 +11,14 @@ module.exports = { if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) if (client.config.bot_status.enable) { - if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type)) { + if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type.toUpperCase())) { console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"')) } else { - client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type }) + client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type.toUpperCase() }) } } - if (client.config.refresh < 10) console.log('Refresh below 10 seconds is not recommended!') + if (client.config.refresh < 10) console.log('Refresh lower than 10 seconds is not recommended!') checkStatus(client) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index f804519..79fd8bc 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -1,4 +1,4 @@ -const { MessageEmbed, Formatters, MessageActionRow, MessageButton } = require('discord.js') +const { MessageEmbed, Formatters, MessageActionRow, MessageButton, MessageAttachment } = require('discord.js') const chalk = require('chalk') module.exports = async function postStatus(client, panel, nodes) { @@ -6,7 +6,7 @@ module.exports = async function postStatus(client, panel, nodes) { if (!client.config.nodes_resource) client.config.nodes_resource = client.config.resource if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] - if (!['mb', 'gb', 'percent'].includes(client.config.nodes_resource.unit)) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Unit at nodes_resource')) + if (!['mb', 'gb', 'percent'].includes(client.config.nodes_resource.unit.toLowerCase())) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Unit at nodes config')) if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) @@ -21,7 +21,6 @@ module.exports = async function postStatus(client, panel, nodes) { messages = null } - const format = await Formatters.time(new Date(Date.now() + client.config.refresh * 1000), 'R') const embed = new MessageEmbed() let text = '' @@ -29,7 +28,7 @@ module.exports = async function postStatus(client, panel, nodes) { let blacklist = 0 if (client.config.embed.title) embed.setTitle(client.config.embed.title) - if (client.config.embed.description) desc = client.config.embed.description.replaceAll('{{time}}', format) + '\n' + if (client.config.embed.description) desc = client.config.embed.description + '\n' if (client.config.embed.color) embed.setColor(client.config.embed.color) if (client.config.embed.footer) embed.setFooter({ text: client.config.embed.footer }) if (client.config.embed.thumbnail) embed.setThumbnail(client.config.embed.thumbnail) @@ -44,7 +43,7 @@ module.exports = async function postStatus(client, panel, nodes) { if (!client.config.nodes_resource.blacklist.includes(data.id)) { const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) let description = '```' - switch (client.config.nodes_resource.unit) { + switch (client.config.nodes_resource.unit.toLowerCase()) { case 'gb': description = description + '\nMemory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1000).toLocaleString() + ' GB' + @@ -94,9 +93,9 @@ module.exports = async function postStatus(client, panel, nodes) { } }) - stats.then(() => { - - embed.setDescription(desc + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) + stats.then(async () => { + const format = await Formatters.time(new Date(Date.now() + client.config.refresh * 1000), 'R') + embed.setDescription(desc.replaceAll('{{time}}', format) + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) if (client.config.panel_resource.enable) { let stats = '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' @@ -107,11 +106,8 @@ module.exports = async function postStatus(client, panel, nodes) { embed.addField('Panel Stats', stats) } - if (client.config.embed.field.enable) { - embed.addField(client.config.embed.field.title, client.config.embed.field.description.replaceAll('{{time}}', format)) - } - - embed.setTimestamp() + if (client.config.embed.field.enable) embed.addField(client.config.embed.field.title, client.config.embed.field.description.replaceAll('{{time}}', format)) + if (client.config.embed.timestamp) embed.setTimestamp() const row = [] @@ -157,12 +153,16 @@ module.exports = async function postStatus(client, panel, nodes) { .setURL(client.config.button.btn5.url) ) } - row.push(button) } + let content = null + const files = [] - if (!messages) channel.send({ embeds: [embed], components: row }) - else messages.edit({ embeds: [embed], components: row }) + if (client.config.message.content) content = client.config.message.content + if (client.config.message.image) files.push(new MessageAttachment(client.config.message.image)) + + if (!messages) channel.send({ content: content, embeds: [embed], components: row, files: files }) + else messages.edit({ content: content, embeds: [embed], components: row, files: files }) console.log(chalk.cyan('[PteroStats] ') + chalk.green('Stats posted!')) }) } \ No newline at end of file From d919cd370d115e9c2d3ddc9e182bacb8432f3b75 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Wed, 29 Jun 2022 09:12:31 +0700 Subject: [PATCH 23/27] Update readme --- Indo.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Indo.md b/Indo.md index c9e0003..2f22582 100644 --- a/Indo.md +++ b/Indo.md @@ -11,7 +11,7 @@ PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl dan dikirim ke server discord ## Contoh -Example +Example ## Instalasi 1. [Mendapatkan apikey dari pterodactyl](#mendapatkan-apikey-dari-pterodactyl) diff --git a/README.md b/README.md index 2a46ba9..5be47c7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server ## Example -Example +Example ## Installation 1. [Getting apikey from pterodactyl](#getting-apikey-from-pterodactyl) From eff98bb8d221069274968a2bfe924c80ac1d5537 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Thu, 30 Jun 2022 11:25:02 +0700 Subject: [PATCH 24/27] Fix if nodes is down the stats not updated --- handlers/checkStatus.js | 10 +++++++++- handlers/postStatus.js | 11 ++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index 03b15c0..0222e34 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -104,6 +104,7 @@ module.exports = function checkStatus(client) { } const stats = new Promise((statsResolve, statsReject) => { + let done = false axios(node.attributes.scheme + '://' + node.attributes.fqdn + ':' + node.attributes.daemon_listen + '/api/servers', { method: 'GET', headers: { @@ -112,15 +113,21 @@ module.exports = function checkStatus(client) { Authorization: 'Bearer ' + data.data.token } }).then((status) => { + done = true statsResolve() }).catch((err) => { body.status = false + done = true statsResolve() }) + setTimeout(() => { + if (!done) body.status = false + statsResolve() + }, 1000) }) stats.then(() => { nodes.push(body) - if (i + 1 === res.data.data.length) resolve() + if (nodes.length === res.data.data.length) resolve() }) }).catch((err) => { resolve() @@ -133,6 +140,7 @@ module.exports = function checkStatus(client) { panelStats.then(() => { nodeStats.then(() => { + nodes.sort(function (a, b) { return a.id - b.id }) postStatus(client, panel, nodes) }) }) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 79fd8bc..87a8a51 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -27,6 +27,12 @@ module.exports = async function postStatus(client, panel, nodes) { let desc = '' let blacklist = 0 + let content = null + const files = [] + + if (client.config.message.content) content = client.config.message.content + if (client.config.message.image) files.push(new MessageAttachment(client.config.message.image)) + if (client.config.embed.title) embed.setTitle(client.config.embed.title) if (client.config.embed.description) desc = client.config.embed.description + '\n' if (client.config.embed.color) embed.setColor(client.config.embed.color) @@ -155,11 +161,6 @@ module.exports = async function postStatus(client, panel, nodes) { } row.push(button) } - let content = null - const files = [] - - if (client.config.message.content) content = client.config.message.content - if (client.config.message.image) files.push(new MessageAttachment(client.config.message.image)) if (!messages) channel.send({ content: content, embeds: [embed], components: row, files: files }) else messages.edit({ content: content, embeds: [embed], components: row, files: files }) From 3d0512c3323ecf079101104c7ecf3c94d265e298 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Sat, 2 Jul 2022 16:35:26 +0700 Subject: [PATCH 25/27] Add TB Unit and other thing --- config.yml | 4 ++-- events/ready.js | 4 ++-- handlers/checkStatus.js | 11 ++++------- handlers/postStatus.js | 9 +++++++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/config.yml b/config.yml index 0382d39..fe1759b 100644 --- a/config.yml +++ b/config.yml @@ -21,7 +21,7 @@ panel: # set to false if you want to disable option message: content: false - image: false # If you enable image on message it upload the image first before sending or editing message and it will delay stats + attachment: false # If you enable attachment on message it upload the attachment first before sending or editing message and it will delay the stats embed: title: 'PteroStats' @@ -67,7 +67,7 @@ nodes_resource: servers: true location: true allocations: true - unit: 'gb' # You can use "gb", "mb", or "percent" + unit: 'gb' # You can use "gb", "mb", "tb", or "percent" # Panel Users and Servers panel_resource: diff --git a/events/ready.js b/events/ready.js index c486380..5f0f683 100644 --- a/events/ready.js +++ b/events/ready.js @@ -10,8 +10,8 @@ module.exports = { if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) - if (client.config.bot_status.enable) { - if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type.toUpperCase())) { + if (client.config.bot_status.enable && client.config.bot_status.text.length > 0) { + if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type.toUpperCase() || client.config.bot_status.type.length < 1 )) { console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"')) } else { client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type.toUpperCase() }) diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index 0222e34..48e2ded 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -104,7 +104,6 @@ module.exports = function checkStatus(client) { } const stats = new Promise((statsResolve, statsReject) => { - let done = false axios(node.attributes.scheme + '://' + node.attributes.fqdn + ':' + node.attributes.daemon_listen + '/api/servers', { method: 'GET', headers: { @@ -113,16 +112,14 @@ module.exports = function checkStatus(client) { Authorization: 'Bearer ' + data.data.token } }).then((status) => { - done = true - statsResolve() + return statsResolve() }).catch((err) => { body.status = false - done = true - statsResolve() + return statsResolve() }) setTimeout(() => { - if (!done) body.status = false - statsResolve() + body.status = false + return statsResolve() }, 1000) }) stats.then(() => { diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 87a8a51..1cbe00a 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -6,7 +6,7 @@ module.exports = async function postStatus(client, panel, nodes) { if (!client.config.nodes_resource) client.config.nodes_resource = client.config.resource if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] - if (!['mb', 'gb', 'percent'].includes(client.config.nodes_resource.unit.toLowerCase())) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Unit at nodes config')) + if (!client.config.message.attachment) client.config.message.attachment = client.config.message.image if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) @@ -31,7 +31,7 @@ module.exports = async function postStatus(client, panel, nodes) { const files = [] if (client.config.message.content) content = client.config.message.content - if (client.config.message.image) files.push(new MessageAttachment(client.config.message.image)) + if (client.config.message.attachment) files.push(new MessageAttachment(client.config.message.attachment)) if (client.config.embed.title) embed.setTitle(client.config.embed.title) if (client.config.embed.description) desc = client.config.embed.description + '\n' @@ -50,6 +50,11 @@ module.exports = async function postStatus(client, panel, nodes) { const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) let description = '```' switch (client.config.nodes_resource.unit.toLowerCase()) { + case 'tb': + description = description + + '\nMemory : ' + Math.floor(data.memory_min / 1000000).toLocaleString() + ' TB / ' + Math.floor(data.memory_max / 1000000).toLocaleString() + ' TB' + + '\nDisk : ' + Math.floor(data.disk_min / 1000000).toLocaleString() + ' TB / ' + Math.floor(data.disk_max / 1000000).toLocaleString() + ' TB' + break; case 'gb': description = description + '\nMemory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1000).toLocaleString() + ' GB' + From 623d0a611cdbcfaa118fe2d0856fafc1e31773fe Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Wed, 2 Nov 2022 12:21:12 +0000 Subject: [PATCH 26/27] Update to discordjs 14 --- Indo.md | 8 +++++++- README.md | 8 +++++++- handlers/postStatus.js | 38 ++++++++++++++++++++------------------ index.js | 28 ++++++++++++++++------------ package.json | 18 +++++++++--------- 5 files changed, 59 insertions(+), 41 deletions(-) diff --git a/Indo.md b/Indo.md index 2f22582..4e3306b 100644 --- a/Indo.md +++ b/Indo.md @@ -11,7 +11,13 @@ PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl dan dikirim ke server discord ## Contoh -Example +- Test Panel + + Example + +- [Calvs Cloud](https://discord.gg/ssCQjhrBJN) + + Calvs Cloud ## Instalasi 1. [Mendapatkan apikey dari pterodactyl](#mendapatkan-apikey-dari-pterodactyl) diff --git a/README.md b/README.md index 5be47c7..6b496aa 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,13 @@ PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server ## Example -Example +- Test Panel + + Example + +- [Calvs Cloud](https://discord.gg/ssCQjhrBJN) + + Calvs Cloud ## Installation 1. [Getting apikey from pterodactyl](#getting-apikey-from-pterodactyl) diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 1cbe00a..369f466 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -1,4 +1,4 @@ -const { MessageEmbed, Formatters, MessageActionRow, MessageButton, MessageAttachment } = require('discord.js') +const { EmbedBuilder, time, ActionRowBuilder, ButtonBuilder, AttachmentBuilder, ButtonStyle } = require('discord.js') const chalk = require('chalk') module.exports = async function postStatus(client, panel, nodes) { @@ -21,7 +21,7 @@ module.exports = async function postStatus(client, panel, nodes) { messages = null } - const embed = new MessageEmbed() + const embed = new EmbedBuilder() let text = '' let desc = '' @@ -31,7 +31,7 @@ module.exports = async function postStatus(client, panel, nodes) { const files = [] if (client.config.message.content) content = client.config.message.content - if (client.config.message.attachment) files.push(new MessageAttachment(client.config.message.attachment)) + if (client.config.message.attachment) files.push(new AttachmentBuilder(client.config.message.attachment)) if (client.config.embed.title) embed.setTitle(client.config.embed.title) if (client.config.embed.description) desc = client.config.embed.description + '\n' @@ -105,8 +105,9 @@ module.exports = async function postStatus(client, panel, nodes) { }) stats.then(async () => { - const format = await Formatters.time(new Date(Date.now() + client.config.refresh * 1000), 'R') + const format = await time(new Date(Date.now() + client.config.refresh * 1000), 'R') embed.setDescription(desc.replaceAll('{{time}}', format) + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) + const EmbedFields = [] if (client.config.panel_resource.enable) { let stats = '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' @@ -114,53 +115,54 @@ module.exports = async function postStatus(client, panel, nodes) { if (client.config.panel_resource.users) stats = stats + 'Users: ' + String(panel.total_users).replace('-1', '`Unknown`') + '\n' if (client.config.panel_resource.servers) stats = stats + 'Servers: ' + String(panel.total_servers).replace('-1', '`Unknown`') - embed.addField('Panel Stats', stats) + EmbedFields.push({ name: 'Panel Stats', value: stats }) } - if (client.config.embed.field.enable) embed.addField(client.config.embed.field.title, client.config.embed.field.description.replaceAll('{{time}}', format)) + if (client.config.embed.field.enable) EmbedFields.push({ name: client.config.embed.field.title, value: client.config.embed.field.description.replaceAll('{{time}}', format) }) if (client.config.embed.timestamp) embed.setTimestamp() - + if (EmbedFields.length > 0) embed.addFields(EmbedFields) + const row = [] if (client.config.button.enable) { - const button = new MessageActionRow + const button = new ActionRowBuilder if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.url.length !== 0) { button.addComponents( - new MessageButton() + new ButtonBuilder() .setLabel(client.config.button.btn1.label) - .setStyle('LINK') + .setStyle(ButtonStyle.Link) .setURL(client.config.button.btn1.url) ) } if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.url.length !== 0) { button.addComponents( - new MessageButton() + new ButtonBuilder() .setLabel(client.config.button.btn2.label) - .setStyle('LINK') + .setStyle(ButtonStyle.Link) .setURL(client.config.button.btn2.url) ) } if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.url.length !== 0) { button.addComponents( - new MessageButton() + new ButtonBuilder() .setLabel(client.config.button.btn3.label) - .setStyle('LINK') + .setStyle(ButtonStyle.Link) .setURL(client.config.button.btn3.url) ) } if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.url.length !== 0) { button.addComponents( - new MessageButton() + new ButtonBuilder() .setLabel(client.config.button.btn4.label) - .setStyle('LINK') + .setStyle(ButtonStyle.Link) .setURL(client.config.button.btn4.url) ) } if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.url.length !== 0) { button.addComponents( - new MessageButton() + new ButtonBuilder() .setLabel(client.config.button.btn5.label) - .setStyle('LINK') + .setStyle(ButtonStyle.Link) .setURL(client.config.button.btn5.url) ) } diff --git a/index.js b/index.js index 5df5536..b1694be 100644 --- a/index.js +++ b/index.js @@ -7,8 +7,8 @@ if (Number(process.version.split('.')[0]) < 16) { } if (fs.existsSync('./node_modules')) { const check = require('./node_modules/discord.js/package.json') - if (Number(check.version.split('.')[0]) !== 13) { - console.log('Invalid Discord.JS Version!, Please use Discord.JS 13.x') + if (Number(check.version.split('.')[0]) !== 14) { + console.log('Invalid Discord.JS Version!, Please use Discord.JS 14.x') process.exit() } } else { @@ -25,26 +25,30 @@ if (fs.existsSync('./node_modules')) { } } +const path = require('node:path'); const chalk = require('chalk'); const yaml = require('js-yaml'); -const { Client, Intents } = require('discord.js'); -const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); +const { Client, GatewayIntentBits } = require('discord.js'); const config = yaml.load(fs.readFileSync('./config.yml', 'utf8')); client.config = config -const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); + +const eventsPath = path.join(__dirname, 'events'); +const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js')); for (const file of eventFiles) { - const event = require(`./events/${file}`); - if (event.once) { - client.once(event.name, (...args) => event.execute(...args)); - } else { - client.on(event.name, (...args) => event.execute(...args)); - } + const filePath = path.join(eventsPath, file); + const event = require(filePath); + if (event.once) { + client.once(event.name, (...args) => event.execute(...args)); + } else { + client.on(event.name, (...args) => event.execute(...args)); + } } -if (client.config.token.startsWith('Put')) { +if (client.config.token.startsWith('Put') || client.config.token.length < 1) { console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Discord Bot Token')) process.exit() } diff --git a/package.json b/package.json index 5f0b5ac..90846dd 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,24 @@ { "name": "pterostats", - "version": "v2.0.0", + "version": "v3.0.0", "description": "PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server", "license": "MIT", "repository": "HirziDevs/PteroStats", "homepage": "https://pterostats.hirzidevs.net", "bugs": { - "email": "hirzidevs@gmail.com", - "url": "https://github.com/HirziDevs/PteroStats" + "email": "hirzidevs@gmail.com", + "url": "https://github.com/HirziDevs/PteroStats" }, "scripts": { - "start": "node index.js" + "start": "node index.js" }, "dependencies": { - "axios": "^0.27.2", - "chalk": "4.1.1", - "discord.js": "^13.8.1", - "js-yaml": "^4.1.0" + "axios": "^0.27.2", + "chalk": "4.1.1", + "discord.js": "^14.6.0", + "js-yaml": "^4.1.0" }, "engines": { - "node": "^16.x" + "node": "^16.x" } } \ No newline at end of file From f3e192720acb053827aac3863c228fcb5dc54db1 Mon Sep 17 00:00:00 2001 From: Hirzi <64255651+HirziDevs@users.noreply.github.com> Date: Thu, 3 Nov 2022 04:44:11 +0000 Subject: [PATCH 27/27] Some changes --- Indo.md | 2 +- README.md | 2 +- events/ready.js | 38 ++--- handlers/checkStatus.js | 254 +++++++++++++++++----------------- handlers/postStatus.js | 298 ++++++++++++++++++++-------------------- index.js | 60 ++++---- package.json | 44 +++--- 7 files changed, 347 insertions(+), 351 deletions(-) diff --git a/Indo.md b/Indo.md index 4e3306b..3436700 100644 --- a/Indo.md +++ b/Indo.md @@ -17,7 +17,7 @@ PteroStats adalah bot yang dirancang untuk memeriksa status panel pterodactyl da - [Calvs Cloud](https://discord.gg/ssCQjhrBJN) - Calvs Cloud + Calvs Cloud ## Instalasi 1. [Mendapatkan apikey dari pterodactyl](#mendapatkan-apikey-dari-pterodactyl) diff --git a/README.md b/README.md index 6b496aa..e8a4391 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and pos - [Calvs Cloud](https://discord.gg/ssCQjhrBJN) - Calvs Cloud + Calvs Cloud ## Installation 1. [Getting apikey from pterodactyl](#getting-apikey-from-pterodactyl) diff --git a/events/ready.js b/events/ready.js index 5f0f683..0927b0e 100644 --- a/events/ready.js +++ b/events/ready.js @@ -2,28 +2,28 @@ const chalk = require('chalk') const checkStatus = require('../handlers/checkStatus') module.exports = { - name: 'ready', - once: true, - execute(client) { - console.log(chalk.cyan('[PteroStats] ') + chalk.green('Bot is up!')) - console.log(chalk.cyan('[PteroStats] ') + chalk.green('If you need support you can join our discord server https://discord.gg/zv6maQRah3')) + name: 'ready', + once: true, + execute(client) { + console.log(chalk.cyan('[PteroStats] ') + chalk.green('Bot is up!')) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('If you need support you can join our discord server https://discord.gg/zv6maQRah3')) - if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) + if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) - if (client.config.bot_status.enable && client.config.bot_status.text.length > 0) { - if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type.toUpperCase() || client.config.bot_status.type.length < 1 )) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"')) - } else { - client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type.toUpperCase() }) - } - } + if (client.config.bot_status.enable && client.config.bot_status.text.length > 0) { + if (!['PLAYING', 'WATCHING', 'LISTENING', 'COMPETING'].includes(client.config.bot_status.type.toUpperCase() || client.config.bot_status.type.length < 1)) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Status Type!, Can be "WATCHING", "PLAYING", "LISTENING", or "COMPETING"')) + } else { + client.user.setActivity(client.config.bot_status.text, { type: client.config.bot_status.type.toUpperCase() }) + } + } - if (client.config.refresh < 10) console.log('Refresh lower than 10 seconds is not recommended!') + if (client.config.refresh < 10) console.log('Refresh lower than 10 seconds is not recommended!') - checkStatus(client) + checkStatus(client) - setInterval(() => { - checkStatus(client) - }, client.config.refresh * 1000) - } + setInterval(() => { + checkStatus(client) + }, client.config.refresh * 1000) + } } \ No newline at end of file diff --git a/handlers/checkStatus.js b/handlers/checkStatus.js index 48e2ded..2bab4e7 100644 --- a/handlers/checkStatus.js +++ b/handlers/checkStatus.js @@ -5,140 +5,140 @@ const postStatus = require('./postStatus') module.exports = function checkStatus(client) { - if (client.config.channel.startsWith('Put')) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Channel ID')) - process.exit() - } else if (client.config.panel.url.startsWith('Put')) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) - process.exit() - } else if (client.config.panel.key.startsWith('Put')) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Apikey')) - process.exit() - } else if (!client.config.panel.url.startsWith('http')) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) - console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the panel url is starts with "https://" or "http://"')) - process.exit() - } + if (client.config.channel.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Channel ID')) + process.exit() + } else if (client.config.panel.url.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) + process.exit() + } else if (client.config.panel.key.startsWith('Put')) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Apikey')) + process.exit() + } else if (!client.config.panel.url.startsWith('http')) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the panel url is starts with "https://" or "http://"')) + process.exit() + } - if (client.config.panel.url.endsWith('/')) client.config.panel.url = client.config.panel.url.slice(0, -1) + if (client.config.panel.url.endsWith('/')) client.config.panel.url = client.config.panel.url.slice(0, -1) - const nodes = [] + const nodes = [] - const panel = { - status: false, - total_servers: -1, - total_users: -1, - } + const panel = { + status: false, + total_servers: -1, + total_users: -1, + } - console.log(chalk.cyan('[PteroStats] ') + chalk.green('Getting nodes stats')) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('Getting nodes stats')) - const panelStats = new Promise((resolve, reject) => { - axios(client.config.panel.url + '/api/application/users', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + client.config.panel.key - } - }).then((usr) => { - axios(client.config.panel.url + '/api/application/servers', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + client.config.panel.key - } - }).then((ser) => { - panel.total_users = usr.data.meta.pagination.total - panel.total_servers = ser.data.meta.pagination.total - panel.status = true + const panelStats = new Promise((resolve, reject) => { + axios(client.config.panel.url + '/api/application/users', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then((usr) => { + axios(client.config.panel.url + '/api/application/servers', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then((ser) => { + panel.total_users = usr.data.meta.pagination.total + panel.total_servers = ser.data.meta.pagination.total + panel.status = true - resolve() - }) - }).catch((err) => { - if (err.response) { - if (err.response.status === 403) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid apikey')) - console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the apikey is from admin page not account page')) - console.log(chalk.cyan('[PteroStats] ') + chalk.red('2. Make sure the apikey has read permission on all options')) - console.log(chalk.cyan('[PteroStats] ') + chalk.red('3. Make sure the apikey is exist')) - } else if (err.response.status === 404) { - console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) - console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the panel url is like "https://panel.example.com"')) - } else console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! ' + err)) - } else console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! ' + err)) - resolve() - }) - }) + resolve() + }) + }).catch((err) => { + if (err.response) { + if (err.response.status === 403) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid apikey')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the apikey is from admin page not account page')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('2. Make sure the apikey has read permission on all options')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('3. Make sure the apikey is exist')) + } else if (err.response.status === 404) { + console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Panel URL')) + console.log(chalk.cyan('[PteroStats] ') + chalk.red('1. Make sure the panel url is like "https://panel.example.com"')) + } else console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! ' + err)) + } else console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! ' + err)) + resolve() + }) + }) - const nodeStats = new Promise((resolve, reject) => { - axios(client.config.panel.url + '/api/application/nodes?include=servers,location,allocations', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + client.config.panel.key - } - }).then((res) => { - res.data.data.forEach((node, i) => { - axios(client.config.panel.url + '/api/application/nodes/' + node.attributes.id + '/configuration', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + client.config.panel.key - } - }).then((data) => { - const body = { - id: node.attributes.id, - name: node.attributes.name, - location: node.attributes.relationships.location.attributes.short, - allocations: node.attributes.relationships.allocations.data.length, - status: true, - maintenance: node.attributes.maintenance_mode, - total_servers: node.attributes.relationships.servers.data.length, - memory_min: node.attributes.allocated_resources.memory, - memory_max: node.attributes.memory, - disk_min: node.attributes.allocated_resources.disk, - disk_max: node.attributes.disk, - } + const nodeStats = new Promise((resolve, reject) => { + axios(client.config.panel.url + '/api/application/nodes?include=servers,location,allocations', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then((res) => { + res.data.data.forEach((node, i) => { + axios(client.config.panel.url + '/api/application/nodes/' + node.attributes.id + '/configuration', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + client.config.panel.key + } + }).then((data) => { + const body = { + id: node.attributes.id, + name: node.attributes.name, + location: node.attributes.relationships.location.attributes.short, + allocations: node.attributes.relationships.allocations.data.length, + status: true, + maintenance: node.attributes.maintenance_mode, + total_servers: node.attributes.relationships.servers.data.length, + memory_min: node.attributes.allocated_resources.memory, + memory_max: node.attributes.memory, + disk_min: node.attributes.allocated_resources.disk, + disk_max: node.attributes.disk, + } - const stats = new Promise((statsResolve, statsReject) => { - axios(node.attributes.scheme + '://' + node.attributes.fqdn + ':' + node.attributes.daemon_listen + '/api/servers', { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + data.data.token - } - }).then((status) => { - return statsResolve() - }).catch((err) => { - body.status = false - return statsResolve() - }) - setTimeout(() => { - body.status = false - return statsResolve() - }, 1000) - }) - stats.then(() => { - nodes.push(body) - if (nodes.length === res.data.data.length) resolve() - }) - }).catch((err) => { - resolve() - }) - }) - }).catch((err) => { - resolve() - }) - }) + const stats = new Promise((statsResolve, statsReject) => { + axios(node.attributes.scheme + '://' + node.attributes.fqdn + ':' + node.attributes.daemon_listen + '/api/servers', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + data.data.token + } + }).then((status) => { + return statsResolve() + }).catch((err) => { + body.status = false + return statsResolve() + }) + setTimeout(() => { + body.status = false + return statsResolve() + }, 1000) + }) + stats.then(() => { + nodes.push(body) + if (nodes.length === res.data.data.length) resolve() + }) + }).catch((err) => { + resolve() + }) + }) + }).catch((err) => { + resolve() + }) + }) - panelStats.then(() => { - nodeStats.then(() => { - nodes.sort(function (a, b) { return a.id - b.id }) - postStatus(client, panel, nodes) - }) - }) + panelStats.then(() => { + nodeStats.then(() => { + nodes.sort(function (a, b) { return a.id - b.id }) + postStatus(client, panel, nodes) + }) + }) } \ No newline at end of file diff --git a/handlers/postStatus.js b/handlers/postStatus.js index 369f466..7c57495 100644 --- a/handlers/postStatus.js +++ b/handlers/postStatus.js @@ -1,176 +1,176 @@ -const { EmbedBuilder, time, ActionRowBuilder, ButtonBuilder, AttachmentBuilder, ButtonStyle } = require('discord.js') +const { EmbedBuilder, time, ActionRowBuilder, ButtonBuilder, ButtonStyle, AttachmentBuilder } = require('discord.js') const chalk = require('chalk') module.exports = async function postStatus(client, panel, nodes) { - if (!client.config.nodes_resource) client.config.nodes_resource = client.config.resource - if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] - if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] - if (!client.config.message.attachment) client.config.message.attachment = client.config.message.image + if (!client.config.nodes_resource) client.config.nodes_resource = client.config.resource + if (!client.config.nodes_resource.blacklist) client.config.nodes_resource.blacklist = [] + if (!Array.isArray(client.config.nodes_resource.blacklist) && Number.isInteger(client.config.nodes_resource.blacklist)) client.config.nodes_resource.blacklist = [client.config.nodes_resource.blacklist] + if (!client.config.message.attachment) client.config.message.attachment = client.config.message.image - if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) + if (client.guilds.cache.size < 1) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! This bot is not on any discord servers')) - const channel = await client.channels.cache.get(client.config.channel) + const channel = await client.channels.cache.get(client.config.channel) - if (!channel) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Channel ID')) + if (!channel) return console.log(chalk.cyan('[PteroStats] ') + chalk.red('Err! Invalid Channel ID')) - let messages = await channel.messages.fetch({ limit: 10 }) - messages = messages.filter(m => m.author.id === client.user.id).last(); - if (messages && messages.embeds.length < 1) { - messages.delete() - messages = null - } + let messages = await channel.messages.fetch({ limit: 10 }) + messages = messages.filter(m => m.author.id === client.user.id).last(); + if (messages && messages.embeds.length < 1) { + messages.delete() + messages = null + } - const embed = new EmbedBuilder() + const embed = new EmbedBuilder() - let text = '' - let desc = '' - let blacklist = 0 + let text = '' + let desc = '' + let blacklist = 0 - let content = null - const files = [] + let content = null + const files = [] - if (client.config.message.content) content = client.config.message.content - if (client.config.message.attachment) files.push(new AttachmentBuilder(client.config.message.attachment)) + if (client.config.message.content) content = client.config.message.content + if (client.config.message.attachment) files.push(new AttachmentBuilder(client.config.message.attachment)) - if (client.config.embed.title) embed.setTitle(client.config.embed.title) - if (client.config.embed.description) desc = client.config.embed.description + '\n' - if (client.config.embed.color) embed.setColor(client.config.embed.color) - if (client.config.embed.footer) embed.setFooter({ text: client.config.embed.footer }) - if (client.config.embed.thumbnail) embed.setThumbnail(client.config.embed.thumbnail) - if (client.config.embed.image) embed.setImage(client.config.embed.image) + if (client.config.embed.title) embed.setTitle(client.config.embed.title) + if (client.config.embed.description) desc = client.config.embed.description + '\n' + if (client.config.embed.color) embed.setColor(client.config.embed.color) + if (client.config.embed.footer) embed.setFooter({ text: client.config.embed.footer }) + if (client.config.embed.thumbnail) embed.setThumbnail(client.config.embed.thumbnail) + if (client.config.embed.image) embed.setImage(client.config.embed.image) - panel.total_users = panel.total_users.toLocaleString() - panel.total_servers = panel.total_servers.toLocaleString() + panel.total_users = panel.total_users.toLocaleString() + panel.total_servers = panel.total_servers.toLocaleString() - const stats = new Promise((resolve, reject) => { - if (nodes.length !== 0) { - nodes.forEach((data, i) => { - if (!client.config.nodes_resource.blacklist.includes(data.id)) { - const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) - let description = '```' - switch (client.config.nodes_resource.unit.toLowerCase()) { - case 'tb': - description = description + - '\nMemory : ' + Math.floor(data.memory_min / 1000000).toLocaleString() + ' TB / ' + Math.floor(data.memory_max / 1000000).toLocaleString() + ' TB' + - '\nDisk : ' + Math.floor(data.disk_min / 1000000).toLocaleString() + ' TB / ' + Math.floor(data.disk_max / 1000000).toLocaleString() + ' TB' - break; - case 'gb': - description = description + - '\nMemory : ' + Math.floor(data.memory_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1000).toLocaleString() + ' GB' + - '\nDisk : ' + Math.floor(data.disk_min / 1000).toLocaleString() + ' GB / ' + Math.floor(data.disk_max / 1000).toLocaleString() + ' GB' - break; - case 'percent': - description = description + - '\nMemory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %' + - '\nDisk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %' - break; - default: - description = description + - '\nMemory : ' + data.memory_min.toLocaleString() + ' MB / ' + data.memory_max.toLocaleString() + ' MB' + - '\nDisk : ' + data.disk_min.toLocaleString() + ' MB / ' + data.disk_max.toLocaleString() + ' MB' - } + const stats = new Promise((resolve, reject) => { + if (nodes.length !== 0) { + nodes.forEach((data, i) => { + if (!client.config.nodes_resource.blacklist.includes(data.id)) { + const title = data.name + ': ' + String(data.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + let description = '```' + switch (client.config.nodes_resource.unit.toLowerCase()) { + case 'tb': + description = description + + '\nMemory : ' + Math.floor(data.memory_min / (1024 * 1000)).toLocaleString() + ' TB / ' + Math.floor(data.memory_max / (1024 * 1000)).toLocaleString() + ' TB' + + '\nDisk : ' + Math.floor(data.disk_min / (1024 * 1000)).toLocaleString() + ' TB / ' + Math.floor(data.disk_max / (1024 * 1000)).toLocaleString() + ' TB' + break; + case 'gb': + description = description + + '\nMemory : ' + Math.floor(data.memory_min / 1024).toLocaleString() + ' GB / ' + Math.floor(data.memory_max / 1024).toLocaleString() + ' GB' + + '\nDisk : ' + Math.floor(data.disk_min / 1024).toLocaleString() + ' GB / ' + Math.floor(data.disk_max / 1024).toLocaleString() + ' GB' + break; + case 'percent': + description = description + + '\nMemory : ' + Math.floor(data.memory_min / data.memory_max * 100) + ' %' + + '\nDisk : ' + Math.floor(data.disk_min / data.disk_max * 100) + ' %' + break; + default: + description = description + + '\nMemory : ' + data.memory_min.toLocaleString() + ' MB / ' + data.memory_max.toLocaleString() + ' MB' + + '\nDisk : ' + data.disk_min.toLocaleString() + ' MB / ' + data.disk_max.toLocaleString() + ' MB' + } - if (client.config.nodes_resource.servers) description = description + '\nServers : ' + data.total_servers.toLocaleString() - if (client.config.nodes_resource.location) description = description + '\nLocation : ' + data.location - if (client.config.nodes_resource.allocations) description = description + '\nAllocations : ' + data.allocations.toLocaleString() + if (client.config.nodes_resource.servers) description = description + '\nServers : ' + data.total_servers.toLocaleString() + if (client.config.nodes_resource.location) description = description + '\nLocation : ' + data.location + if (client.config.nodes_resource.allocations) description = description + '\nAllocations : ' + data.allocations.toLocaleString() - description = description + '\n```' + description = description + '\n```' - if (client.config.nodes_resource.enable) { - text = text + '\n**' + title.replace(':', ':**') + '\n' + description - } else { - text = text + '\n**' + title.replace(':', ':**') - } - } else { - blacklist = blacklist + 1 - if (nodes.length - client.config.nodes_resource.blacklist.length < 1) text = '\nThere is no nodes to display' - } + if (client.config.nodes_resource.enable) { + text = text + '\n**' + title.replace(':', ':**') + '\n' + description + } else { + text = text + '\n**' + title.replace(':', ':**') + } + } else { + blacklist = blacklist + 1 + if (nodes.length - client.config.nodes_resource.blacklist.length < 1) text = '\nThere is no nodes to display' + } - if (i + 1 === nodes.length) resolve() - }) - } else if (nodes.length < 1) { - if (!messages) { - text = '\nThere is no nodes to display' - resolve() - } else { - text = messages.embeds[0].description.replaceAll(client.config.status.online, client.config.status.offline) - if (!panel.status && String(String(messages.embeds[0].fields[0].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[2]).length - 1] !== '`') { - panel.total_users = String(String(messages.embeds[0].fields[0].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[2]).length - 1] - panel.total_servers = String(String(messages.embeds[0].fields[0].value).split('\n')[3]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[3]).length - 1] - } - resolve() - } - } - }) + if (i + 1 === nodes.length) resolve() + }) + } else if (nodes.length < 1) { + if (!messages) { + text = '\nThere is no nodes to display' + resolve() + } else { + text = messages.embeds[0].description.replaceAll(client.config.status.online, client.config.status.offline) + if (!panel.status && String(String(messages.embeds[0].fields[0].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[2]).length - 1] !== '`') { + panel.total_users = String(String(messages.embeds[0].fields[0].value).split('\n')[2]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[2]).length - 1] + panel.total_servers = String(String(messages.embeds[0].fields[0].value).split('\n')[3]).split('')[String(String(messages.embeds[0].fields[0].value).split('\n')[3]).length - 1] + } + resolve() + } + } + }) - stats.then(async () => { - const format = await time(new Date(Date.now() + client.config.refresh * 1000), 'R') - embed.setDescription(desc.replaceAll('{{time}}', format) + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) - const EmbedFields = [] + stats.then(async () => { + const format = await time(new Date(Date.now() + client.config.refresh * 1000), 'R') + embed.setDescription(desc.replaceAll('{{time}}', format) + '\n**Nodes Stats [' + Math.floor(nodes.length - blacklist) + ']**' + text) + const EmbedFields = [] - if (client.config.panel_resource.enable) { - let stats = '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' + if (client.config.panel_resource.enable) { + let stats = '**Status:** ' + String(panel.status).replace('true', client.config.status.online).replace('false', client.config.status.offline) + '\n\n' - if (client.config.panel_resource.users) stats = stats + 'Users: ' + String(panel.total_users).replace('-1', '`Unknown`') + '\n' - if (client.config.panel_resource.servers) stats = stats + 'Servers: ' + String(panel.total_servers).replace('-1', '`Unknown`') + if (client.config.panel_resource.users) stats = stats + 'Users: ' + String(panel.total_users).replace('-1', '`Unknown`') + '\n' + if (client.config.panel_resource.servers) stats = stats + 'Servers: ' + String(panel.total_servers).replace('-1', '`Unknown`') - EmbedFields.push({ name: 'Panel Stats', value: stats }) - } + EmbedFields.push({ name: 'Panel Stats', value: stats }) + } - if (client.config.embed.field.enable) EmbedFields.push({ name: client.config.embed.field.title, value: client.config.embed.field.description.replaceAll('{{time}}', format) }) - if (client.config.embed.timestamp) embed.setTimestamp() - if (EmbedFields.length > 0) embed.addFields(EmbedFields) - - const row = [] + if (client.config.embed.field.enable) EmbedFields.push({ name: client.config.embed.field.title, value: client.config.embed.field.description.replaceAll('{{time}}', format) }) + if (client.config.embed.timestamp) embed.setTimestamp() + if (EmbedFields.length > 0) embed.addFields(EmbedFields) - if (client.config.button.enable) { - const button = new ActionRowBuilder - if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.url.length !== 0) { - button.addComponents( - new ButtonBuilder() - .setLabel(client.config.button.btn1.label) - .setStyle(ButtonStyle.Link) - .setURL(client.config.button.btn1.url) - ) - } - if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.url.length !== 0) { - button.addComponents( - new ButtonBuilder() - .setLabel(client.config.button.btn2.label) - .setStyle(ButtonStyle.Link) - .setURL(client.config.button.btn2.url) - ) - } - if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.url.length !== 0) { - button.addComponents( - new ButtonBuilder() - .setLabel(client.config.button.btn3.label) - .setStyle(ButtonStyle.Link) - .setURL(client.config.button.btn3.url) - ) - } - if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.url.length !== 0) { - button.addComponents( - new ButtonBuilder() - .setLabel(client.config.button.btn4.label) - .setStyle(ButtonStyle.Link) - .setURL(client.config.button.btn4.url) - ) - } - if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.url.length !== 0) { - button.addComponents( - new ButtonBuilder() - .setLabel(client.config.button.btn5.label) - .setStyle(ButtonStyle.Link) - .setURL(client.config.button.btn5.url) - ) - } - row.push(button) - } + const row = [] - if (!messages) channel.send({ content: content, embeds: [embed], components: row, files: files }) - else messages.edit({ content: content, embeds: [embed], components: row, files: files }) - console.log(chalk.cyan('[PteroStats] ') + chalk.green('Stats posted!')) - }) + if (client.config.button.enable) { + const button = new ActionRowBuilder + if (client.config.button.btn1.label.length !== 0 && client.config.button.btn1.url.length !== 0) { + button.addComponents( + new ButtonBuilder() + .setLabel(client.config.button.btn1.label) + .setStyle(ButtonStyle.Link) + .setURL(client.config.button.btn1.url) + ) + } + if (client.config.button.btn2.label.length !== 0 && client.config.button.btn2.url.length !== 0) { + button.addComponents( + new ButtonBuilder() + .setLabel(client.config.button.btn2.label) + .setStyle(ButtonStyle.Link) + .setURL(client.config.button.btn2.url) + ) + } + if (client.config.button.btn3.label.length !== 0 && client.config.button.btn3.url.length !== 0) { + button.addComponents( + new ButtonBuilder() + .setLabel(client.config.button.btn3.label) + .setStyle(ButtonStyle.Link) + .setURL(client.config.button.btn3.url) + ) + } + if (client.config.button.btn4.label.length !== 0 && client.config.button.btn4.url.length !== 0) { + button.addComponents( + new ButtonBuilder() + .setLabel(client.config.button.btn4.label) + .setStyle(ButtonStyle.Link) + .setURL(client.config.button.btn4.url) + ) + } + if (client.config.button.btn5.label.length !== 0 && client.config.button.btn5.url.length !== 0) { + button.addComponents( + new ButtonBuilder() + .setLabel(client.config.button.btn5.label) + .setStyle(ButtonStyle.Link) + .setURL(client.config.button.btn5.url) + ) + } + row.push(button) + } + + if (!messages) channel.send({ content: content, embeds: [embed], components: row, files: files }) + else messages.edit({ content: content, embeds: [embed], components: row, files: files }) + console.log(chalk.cyan('[PteroStats] ') + chalk.green('Stats posted!')) + }) } \ No newline at end of file diff --git a/index.js b/index.js index b1694be..9098250 100644 --- a/index.js +++ b/index.js @@ -2,55 +2,51 @@ const fs = require('fs'); const child = require('child_process'); if (Number(process.version.split('.')[0]) < 16) { - console.log('Invalid NodeJS Version!, Please use NodeJS 16.x or upper') - process.exit() + console.log('Invalid NodeJS Version!, Please use NodeJS 16.x or upper') + process.exit() } if (fs.existsSync('./node_modules')) { - const check = require('./node_modules/discord.js/package.json') - if (Number(check.version.split('.')[0]) !== 14) { - console.log('Invalid Discord.JS Version!, Please use Discord.JS 14.x') - process.exit() - } + const check = require('./node_modules/discord.js/package.json') + if (Number(check.version.split('.')[0]) !== 14) { + console.log('Invalid Discord.JS Version!, Please use Discord.JS 14.x') + process.exit() + } } else { - console.log('You didn\'t install the required node packages first!') - console.log('Please wait... starting to install all required node packages using child process') - try { - child.execSync('npm i') - console.log('Install complete!, please run "node index" command again!') - process.exit() - } catch (err) { - console.log('Err! ', err) - console.log('Support Server: https://discord.gg/zv6maQRah3') - process.exit() - } + console.log('You didn\'t install the required node packages first!') + console.log('Please wait... starting to install all required node packages using child process') + try { + child.execSync('npm i') + console.log('Install complete!, please run "node index" command again!') + process.exit() + } catch (err) { + console.log('Err! ', err) + console.log('Support Server: https://discord.gg/zv6maQRah3') + process.exit() + } } -const path = require('node:path'); const chalk = require('chalk'); const yaml = require('js-yaml'); const { Client, GatewayIntentBits } = require('discord.js'); +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); const config = yaml.load(fs.readFileSync('./config.yml', 'utf8')); client.config = config -const client = new Client({ intents: [GatewayIntentBits.Guilds] }); - -const eventsPath = path.join(__dirname, 'events'); -const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js')); +const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); for (const file of eventFiles) { - const filePath = path.join(eventsPath, file); - const event = require(filePath); - if (event.once) { - client.once(event.name, (...args) => event.execute(...args)); - } else { - client.on(event.name, (...args) => event.execute(...args)); - } + const event = require(`./events/${file}`); + if (event.once) { + client.once(event.name, (...args) => event.execute(...args)); + } else { + client.on(event.name, (...args) => event.execute(...args)); + } } if (client.config.token.startsWith('Put') || client.config.token.length < 1) { - console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Discord Bot Token')) - process.exit() + console.log(chalk.cyan('[PteroStats]') + chalk.red(' Err! Invalid Discord Bot Token')) + process.exit() } client.login(config.token); \ No newline at end of file diff --git a/package.json b/package.json index 90846dd..36fbe00 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,24 @@ { - "name": "pterostats", - "version": "v3.0.0", - "description": "PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server", - "license": "MIT", - "repository": "HirziDevs/PteroStats", - "homepage": "https://pterostats.hirzidevs.net", - "bugs": { - "email": "hirzidevs@gmail.com", - "url": "https://github.com/HirziDevs/PteroStats" - }, - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "axios": "^0.27.2", - "chalk": "4.1.1", - "discord.js": "^14.6.0", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": "^16.x" - } + "name": "pterostats", + "version": "v3.0.0", + "description": "PteroStats is a bot designed to check Pterodactyl Panel and Nodes status and post it to your discord server", + "license": "MIT", + "repository": "HirziDevs/PteroStats", + "homepage": "https://pterostats.hirzidevs.net", + "bugs": { + "email": "hirzidevs@gmail.com", + "url": "https://github.com/HirziDevs/PteroStats" + }, + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "axios": "^1.1.3", + "chalk": "4.1.1", + "discord.js": "^14.6.0", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": "^16.x" + } } \ No newline at end of file