TS3AudioBot Control Panel Dokumentation

TS3AudioBot Panel


Einführung

Dieses Produkt erfordert ein gewisses Level an Expertise. Bei Fragen sind wir über Ticket oder E-Mail erreichbar.


Danke für den Kauf dieses Produkts. Du bist super!
Du hast eine Lebenslange Lizenz des Produkts erhalten und direkt Support der Entwickler

Diese Dokumentation soll dir helfen, das Produkt zu installieren und passend für dich einzurichten

Voraussetzungen

Du brauchst die folgenden Sachen um das Produkt zu installieren:

  1. Web Browser for testing (eg: Google Chrome or Mozilla Firefox)
  2. Einen Server:
    1. Basis-Server: (s.h. Anleitung hier)

Installation #nach oben

Lass uns Anfangen das CP zu installieren. In dieser Anleitung nutzen wir einen Server mit Debian 10, es sollte aber mit möglicherweise kleinen Änderungen auch auf anderen Betriebssystemen funktionieren.

Wir werden die folgenden Schritte ausführen:

  1. Runterladen und entpacken
  2. Datenbank importieren
  3. Config bearbeiten
  4. Abhängigkeiten installieren

Runterladen und entpacken

Wir gehen in den /var/www/html-Order (nutze cd). Deinen Download-code findest du im CIS unter dem Reiter "Produkte" (https://bennetgallein.de/cis/products)

                                    root@server:/var/www/html# wget --prefer-family=IPv4 https://bennetgallein.de/api/download-key/...
                                

Nach dem runterladen, bennene die Datei um:

                                    root@server:/var/www/html# mv <file> cp.zip
                                

Und entpacke sie:

                                    root@server:/var/www/html# unzip cp.zip
                                

Datenbank importieren

Durch die Basiseinrichtung haben wir bereits einen Nutzer für das CP erstellt.

Wir gehen jetzt wieder über das Terminal in die mysql shell.

                                    root@server:/# mysql -u root
                                

Wenn du in der Basiseinrichtung ein Passwort für den root-Nutzer gesetzt hast, nutze diesen Befehl und gib das Passwort ein wenn gefordert:

                                    root@server:/# mysql -u root -p
                                

Du solltest jetzt soetwas sehen:

                                    MariaDB [(none)]>
                                

Jetzt können wir die Datenbank erstellen:

                                    MariaDB [(none)]> CREATE DATABASE TS3ABCP;
                                    Query OK, 1 row affected (0.01 sec)

                                    MariaDB [(none)]>
                                

Das war's auch schon. Nutze exit; um die Datenbank wieder zu verlassen.
Als nächstes importieren wir die Datenbank mit dem folgenden Befehl

                                    root@server:/# mysql -u root -p TS3ABCP < /var/www/html/database.sql
                                

Abhängigkeitn installieren

Jetzt installieren wir die Abhängigkeiten, indem wir das mitgelieferte Installations-script ausführen

                                    root@server:/var/www/html/# chmod +x ./bin/install.sh && sudo ./bin/install.sh
                                

Dies wird alle Abhängigkeiten installieren, die das CP benötigt. Wenn nach einem Nutzernamen gefragt wird, stelle sicher, dass die IP-Adresse des Servers in der Lizenz im CIS steht.

Jetzt musst du alle permission- (Rechtesystem) und language- (Sprachsystem) Datein runterladen. Auch hierfür gibt es wieder scripte.

                                    root@server:/var/www/html/# chmod +x ./bin/download_permission_files.sh && sudo ./bin/download_permission_files.sh
                                    root@server:/var/www/html/# chmod +x ./bin/download_language_files.sh && sudo ./bin/download_language_files.sh
                                

Config bearbeiten

Als nächtes wollen wir die config bearbeiten. Du hast im Stamm-order jetzt eine Datei config.json. Diese kannst du mit nano config.json öffnen und bearbeiten. Zum speichern verlasse nano mit ctrl + x und bestätige Änderungen mit Y.

Die folgende Tabelle erklärt die einzelnen Einstellungen und deren Werte.

Schlüssel Beispiel Wert
APP_URL "/" Dies ist die Basis-URL der App. Wenn du es auf yourdomain.com/ laufen haben möchtest, gib / ein, andernfalls einen Pfad wie z.B. /TS3ABCP/. Das würde heißen, dass das CP in dem Ordner /var/www/html/TS3ABCP/ liegt.
DB_HOST "localhost" Der Datenbank Server. localhost oder 127.0.0.1 wenn du das Tutorial befolgt hast.
DB_USER "root" Der Datenbank Nutzer.
DB_PASSWORD "root" Das Passwort zu dem Datenbanknutzer in DB_USER. "" wenn kein Passwort bei der Installation gesetzt wurde
DB_NAME "TS3ABCP" Der Datenbank Name. Wenn du das Tutorial befolgt hast, gib TS3ABCP an
MB_HOST "localhost" Der Host auf dem der Bot läft. Wenn du den Bot auf dem gleichen Server laufen hast wie das CP ist es localhost
MB_PORT "58913" Der Port von dem Webserver des Bots. Standard ist 58913
MB_TOKEN "j+W41OpXcHv8In9vt/Q2x+UmUPs=:ts3ab:GVFdH..." Der Token von dem Musikbot. !bot api token an den Bot gibt dir einen Token welcher benötigt wird um die Bots zu steuern
MB_LIMIT "3" Dies ist das Standard-limit für einen Nutzer. Er kann dann nicht mehr als die Anzahl Bots erstellen Wenn du kein Limit eingestellt haben möchtest, gib -1 an
REGISTER_ACTIVE true Hiermit kannst du kontrollieren ob sich neue Nutzer registrieren dürfen oder nicht. false um Registrierungen zu deaktivieren.
TERMS_AND_CONDITIONS "http://example/tos.html" Ein Link zu den Nutzungsbedingungen. Diese werden auf der Registrationsseite angezeigt
CUSTOM_BOX_TITLE "Website" Dies ist der Titel für die Box auf dem Dashboard wo du deinen eigenen Text eingeben kannst
CUSTOM_BOX_TEXT "bennetgallein.de" Der Inhalt für die eigene Box auf dem Dashboard.
QUICKPLAY { "ILoveRadion": "http://stream01.iloveradio.de/iloveradio1.mp3", "ReyFM": "https://stream01.reyfm.de/original_192kbps.mp3" } Liste von Quickplay Links. Auf der Linken Seite der Anzeigename im CP, auf der rechten dann der Streamlink
THEME "default" Die zu nutzende Theme aus dem _views Ordner. Wenn du keine zusäzliche Theme besitzt, nutze den Standardwert.
ANALYTICS_ENABLED true Ob Statistiken aktiviert sein sollen oder nicht
ANALYTICS_KEY 6254e81ade14be8908cd0d9f05da90f6 Der Analytics-token. Wenn du keinen hast, kannst du deine Seite hier registrieren und dadurch deinen Token erhalten: bennetgallein.de/cis
MODULES "MODULES": { "TicketModule": false, "AntiRobotModule": true } Eine Liste von Modulen. Wenn das Modul aktiviert sein soll, setze es auf true sonst auf false.Du musst du Module kaufen und installieren um sie zu benutzten!

Vergiss nicht deine Änderungen zu speichern!

Rechtesystem

Ab dem 2.1.0 release hat das CP ein feines Rechtesystem, welches dir das erstellen von Gruppen und zuteilen von Rechten für die Gruppe erlaubt.

Alle Rechtedatei liegen in dem _permissions Ordner, die default.json gehöhrt zum Kern des CP, alle anderen Datein kommen von Modulen.

Wenn du keine Datein in diesem Ordner hast, führe den folgenden Befehl aus um alle runterzuladen: chmod +x bin -R && sudo ./bin/download_permission_files.sh

                                    {
                                        "0": [

                                        ],
                                        "50":[
                                            "admin.users",
                                            "admin.user",
                                            "admin.user.changelimit",
                                            "admin.bots",
                                            "admin.bot"
                                        ],
                                        "100": [
                                            "admin.users",
                                            "admin.user",
                                            "admin.user.delete",
                                            "admin.user.changelimit",
                                            "admin.user.makeadmin",
                                            "admin.user.addbalance",
                                            "admin.user.removebalance",
                                            "admin.bots",
                                            "admin.bot",
                                            "admin.internal.apiunresponsive",
                                            "admin.internal.startallbots",
                                            "admin.internal.stopallbots",
                                            "admin.internal.update",
                                            "admin.internal.migrate",
                                            "admin.ignoredeactivatedregister"
                                        ]
                                    }
                                

Was oben zu sehen ist, ist der Standardinhalt der _permissions/default.json. "0","50","100" sind die permissions die du einem Nutzer zuweisen musst, damit er die Gruppe bekommt.

Wert Erklärung
admin.users Recht um die Liste aller Nutzer zu sehen
admin.user Recht um einen einzelnen Nutzer zu sehen
admin.user.delete Recht um einen Nutzer zu löschen
admin.user.changelimit Recht um das Limit für einen Nutzer zu ändern
admin.user.makeadmin Recht um einen Nutzer Admin zu machen
admin.user.addbalance Recht um einem Nutzer Guthaben hinzuzufügen
admin.user.removebalance Recht um einem Nutzer Guthaben zu entfernen.
admin.bots Recht um die Liste von Bots zu sehen
admin.bot Recht um die Kontrolle über einen Bot zu übernehmen. Sinnvoll bei Support-Gruppen.
admin.internal.apiunresponsive Recht um den "API crashed" Button in der Adminliste zu nutzen
admin.internal.startallbots Recht um alle Bots zu starten
admin.internal.stopallbots Recht um alle Bots zu stoppen
admin.internal.update Recht um ein Update zu installieren
admin.setpermission Recht um die Gruppe eines Nutzer zu ändern

Für die Rechte von Modulen, schau bei den Modulen selber.


Jetzt kannst du deine IP + APP_URL in einem Browser öffnen. Registriere einen neuen Nutzer, gehe in die Datenbank und setzte die permissions auf 100. Jetzt kannst du dich einloggen!

Alle Module brauchen einen Config-Eintrag um geladen zu werden:

                                    "MODULES": {
                                        "TicketModule": true,
                                        "AntiRobotModule": true
                                    }
                                

Themes #back to top

Um Themes zu installieren müssen diese erstmal auf den Server geladen werden. Auch für Themes gibt es einen Download-Key welcher sich im CIS finden lässt.

Wir laden die Theme runter und entpacken sie mit den folgenden Befehlen:

                                    root@server:/var/www/html# wget --prefer-family=IPv4 -O theme.zip https://bennetgallein.de/api/download-key/...
                                    root@server:/var/www/html# unzip theme.zip 
                                

Jetzt liegt ein Ordner dort mit dem Namen der Theme. Bewege diesen Ordner jetzt in den _views Order mit mv <theme>.zip _views/.

Als letztes muss die Theme jetzt noch in der config.json aktiviert werden. Setzte dafür den Wert von THEME auf den Namen deiner Theme.

Ticket Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder TicketModule inside the _Modules folder. Reload the Page and if no errors accour, browse to <ip>/module/ticket/install in your Browser to install the required Database folders and the additional pages to the _views folder.

If you get any errors and the logs say something about Class Not Found, run composer dump-autoload -o in the directory of the Panel to load the new classes.

Permissions

value explanation
ticket.tickets Permission to see the list of users
ticket.admin.setup Permission to visit the setup page
ticket.admin.tickets Permission to see all tickets
ticket.admin.ticket Permission to see a ticket that doesn't belong to the logged in user
ticket.admin.answer Permission to answer a ticket that doesn't belong to the logged in user
ticket.admin.close Permission to close a ticket that doesn't belong to the logged in user
ticket.createnew Permission to create a new ticket

AntiRobot Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder AntiRobotModule inside the _Modules folder.

There are also some new config entries you need to make. CAPTCHA_PUBLIC (your public google recaptcha code), CAPTCHA_PRIVATE (your private recaptcha code) and CAPTCHA_LIMIT(a number between 0 and 1, the level of trust google at least needs to have in the user (example value: "0.7"))


MultiHost Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder MultiHostModule inside the _Modules folder.

Once done with the unzipping, make sure you have the latest permission files by running the script: chmod +x ./bin/download_permission_files.sh && sudo ./bin/download_permission_files.sh. After that, visit /module/multihost/install and confirm that there are no errors. The module will take the Bot which is currently in the config.json as the first node. After that, you should be good to go setting up your new nodes and bots.

Commercial Module #back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder CommercialModule inside the _Modules folder.

A few new config-entries are needed. See the below table with example values.

value example explanation
PP_MODE "sandbox" The mode in which paypal should operate (sandbox to test, production for production)
PP_MODE_BACKEND "sandbox" The mode in which paypal should operate (sandbox to test, live for production)
PP_CLIENT "AYWW_JrxYWv0jE0NIvaf7Cxhavwg0Eq7Ad7pzIPiJf5F6hdelFZsN4iBmJKT" PayPal client ID (https://www.paypalobjects.com/webstatic/de_DE/downloads/PayPal_Nutzung_der_REST_API.pdf)
PP_SECRET "EBKkZiWY7m51XYb4k67P309xDnTrqUUed-h8Fs5NF4i5hDT8PKtP9Z1b7xtuQRk" PayPal client secret (https://www.paypalobjects.com/webstatic/de_DE/downloads/PayPal_Nutzung_der_REST_API.pdf)
BOT_PRICE "1.50" The price for each Bot the user has to pay
PP_RETURNURL "https://bennetgallein.de/balance" The full URL of the balance page
PP_CANCELURL "https://bennetgallein.de/balance" The full URL of the balance page (same as PP_CANCELURL)

Subscription Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder SubscriptionModule inside the _Modules folder.

After that, go to your browser and visit this url: <ip>/module/subscription/install to import the database changes.

There is also a new config entry that you need to make. PAYMENT_INTERVAL is the number of days between each payment. So if you set this to 30 days, the module will try to subtract the BOT_PRICE from the users account and if it fails, will stop the bot and delete it.

It is also recommended to setup a cronjob to execute the job on a daily basis, you can decide how often you want to check if a payment is required. Use this tool to get an valid crontab format and then enter the following in your crontab file (can be accessed by executing crontab -e in the console): * * * * * curl "http(s)://your-ip.de/module/subscription/execute" >/dev/null 2>&1 which will execute the script every minute.

StatusPage Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder StatusPageModule inside the _Modules folder.

After that, go to your browser and visit this url: <ip>/module/statuspage/install to import the database changes.

Now you are ready to collect metrics from your nodes. To do that, type crontab -e into your terminal and paste the following snippet at the end of the file: * * * * * curl "http(s)://your-ip.de/status/check" >/dev/null 2>&1. This will save the status every minute. Please notice that you have to change the IP of your server in that snippet!

After some short time, you should be able to the collected data in the graph on <ip>/status

.

Playlist Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder PlaylistsModule inside the _Modules folder.

After that, go to your browser and visit this url: <ip>/module/playlists/install to import the database changes and move the files.

Sharing Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder SharingModule inside the _Modules folder.

After that, go to your browser and visit this url: <ip>/module/sharing/install to import the database changes.

Newsletter Module#back to top

Installing a Module is straight forward. Download the files over the download-link you received via E-Mail. Them unzip the folder NewsletterModule inside the _Modules folder.

After that, go to your browser and visit this url: <ip>/module/newsletter/install to import the database changes.

This module will use the native PHP mail() function to send mails, so make sure you have PHP configured for Mail sending!

Developers#back to top

If you want to develop your own modules read this page: https://docs.bennetgallein.de/ts3abcp/modules.html

If you want to develop your own themes for the Dashboard, that's cool. In this part of the guide, I'll give my best to explain how everything works and how you can get started creating custom themes and how to install them.

Of course there are conditions to this option: You have to leave a copyright to my Website in the footer and to all other Authors you used. If you want to remove the copyright, email me: me@bennetgallein.de and against a small fee this should be no problem. Just don't do it without my permission, my ToS permit it and I realy don't want to revoke your license!

With that out of the way, let's get started: Basically you have to create a folder inside the _views/ folder with the name of your template (I use test in this tutorial) and change the THEME property in the config to the name of the folder (in my example test).

In order for the Panel to continue working as expected, you need to follow the file structure I provide below. Also note that I use a Templating Engine, which allows you to include files easily (I use it to include styles, scripts, sidebars, etc.). A full List of the Syntax can be found in this file.

File Structure

                                    _views/
                                        test/
                                            admin_bots.html
                                            admin_list.html
                                            admin_user.html
                                            bot.html
                                            error.html
                                            index.html
                                            new_bot.html
                                            settings.html
                                            sign-in.html
                                            sign-up.html
                                            _includes/
                                                optional files
                                

This is the file structure. You need to have the same file names at the same locations, otherwise the Software won't find them.

sign-in.html

This file is responsible to display the login form. there is only one parameter register which you can use, which shows if the REGISTER_ACTIVE option in the config is enabled or disabled. You can check this by using the following Syntax in your code:

                                    { if :register }
                                        // register is active, display link to register form
                                    { endif }
                                

You also need to add a little bit of JavaScript to make the login work, because it's interactive and the Document wont get reloaded until the user is being redirected to the Dashboard.

                                    $("#login").on("click", (e) => {
                                        e.preventDefault();

                                        let emailInput = $("#email").val();
                                        let passwordInput = $("#password").val();

                                        $.post("{ :app_url }login",
                                        {
                                            email: emailInput,
                                            password: passwordInput
                                        }, (data) => {
                                            if (data.error === true) {
                                                // there is a error. The Error message is in data.error_msg
                                            } else {
                                                setTimeout(() => {
                                                    window.location = "{ :app_url }dashboard";
                                                }, 2000);
                                            }
                                        });
                                    });
                                

sign-up.html

This file is responsible to display the sign up form. This wont render if REGISTER_ACTIVE is set to false in the config. The only parameter here is tac, which will be populated with the content of the TERMS_AND_CONDITIONS variable.

Again, we need some JavaScript to make this work:

                                        $("#register-btn").on('click', function (e) {
                                            e.preventDefault();

                                            var name = $("#name").val();
                                            var email = $("#email").val();
                                            var password = $("#password").val();
                                            var confirmpassword = $("#cpassword").val();

                                            if (password !== confirmpassword || password === "") {
                                                // checks are also made in the backend
                                                // but it saves some time to do so of them here
                                            }
                                            $.post("{ :app_url }register",
                                                {
                                                    name: name,
                                                    email: email,
                                                    password: password
                                                }, function (data) {
                                                    if (data.error === true) {
                                                        // error, see data.error_msg for more information.
                                                    } else {
                                                        // no error. Redirect to login
                                                        setTimeout(function() {
                                                            window.location = "{ :app_url }login";
                                                        }, 2000);
                                                    }
                                                });
                                        });
                                

settings.html

This page is to render the settings for the user account. Here we'll also introduct our first object, which is the user. You can access it's properties by using the { :user.property } Syntax.

User object:

property explanation
id The ID of the user in the database.
name The name the user registed under
email The email address of the user
permission The permission level the user has
limit the limit of Bots a user can have

For example, if you want to display the user's email on the settings page, just enter { :user.email } and it will render the email of the current logged in user.

To change the passwort, use this as a template for further development:

                                        function changePass() {
                                            $.post("{ :app_url }api/changepass", {
                                                old: $("#old").val(),
                                                new: $("#new").val()
                                            }, function(data) {
                                               if (data.error) {
                                                   Swal({
                                                       type: 'error',
                                                       title: 'Failed',
                                                       text: data.error_msg,
                                                   })
                                               } else {
                                                   Swal({
                                                       type: 'success',
                                                       title: 'Done',
                                                       text: data.error_msg,
                                                   })
                                               }
                                            });
                                        }
                                

index.html

Okay, this is for the main Dashboard a user lands on, once he logged in successfully. This table will give you an overview which parameters are here and how to use them.

property explanation
name The name of the logged in user
email The email of the logged in user
num_bots The amount of Bots the user currently has
last_login A Timestamp of the last login
bots An Array of all Bots and their information.
total_bots The Amount of total Bots created by all users.
custom_box_title The custom box title value from the config
custom_box_text The content of the box, according to the config
filter If the User has a filter active
showfilter a boolean to show the filter.

Displaying the Bots on the Dashoard looks something like this:

                                        { foreach :bot in :bots }
                                        <tr>
                                            <td>{ :bot.id }</td>
                                            <td>
                                                <a class="text-dark" href="{ :app_url }bot/{ :bot.id }">{ :bot.nickname }</a>
                                            </td>
                                            <td class="d-none d-md-table-cell">{ :bot.created }</td>
                                            <td>
                                                <?php if ($bot['status'] == "Online"): ?>
                                                <span class="badge badge-success">{ :bot.status }</span>
                                                { else }
                                                <span class="badge badge-danger">{ :bot.status }</span>
                                                { endif }
                                            </td>
                                        </tr>
                                        { endforeach }
                                

Basically you are looping over the Array to display the values, pretty simpel huh?

new-bot.html

This page displays the dialog to create a new Bot. There are no parameters, but I'll drop you a hint on howto create a new Bot.

                                        $("#submit-create").on("click", function(e) {
                                            e.preventDefault();
                                            let nickname = $("#nickname").val();
                                            let ip = $("#ip").val();

                                            $.post("{ :app_url }bot/new", {
                                                nickname: nickname,
                                                ip: ip
                                            }, function(data) {
                                                console.log(data);
                                                if (data.error) {
                                                    Swal("Done", "" + data.error_msg, "error");
                                                } else {
                                                    Swal("Done", "" + data.error_msg, "success");
                                                }
                                            });
                                        });
                                

bot.html

This is the page which display the specific Bot and it's properties. Parameters are id which is the Bot ID, bot which is the Bot Object and quickplay which will be false if there are no quicklplay links and a key-value array if there are some.

Bot object:

property explanation
id Bot ID in Database, same as id which comes by default
nickname the nickname set for the Bot
connected the IP where the Bot is connected to
userid The ID of the User who created this Bot
last_id The last ID the Bot received from the TS3AudioBot API
active If the Bot is deleted (0 if it is deleted)
created A timestamp when the Bot was created
status Status of the Bot (Online or Offline)
commander Wether the Bot is a channel-commander or not.

To update settings, volume and get current songs, look at the examples below:

                                        var slider = document.getElementById("volume");
                                        var output = document.getElementById("volume_display");
                                        output.innerHTML = slider.value; // Display the default slider value

                                        // Update the current slider value (each time you drag the slider handle)
                                        slider.oninput = function() {
                                            output.innerHTML = this.value;
                                        }

                                        function disconnect(id) {
                                            $.get("{ :app_url }api/bot/disconnect/" + id, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }

                                                setTimeout(function () {
                                                    location.reload();
                                                }, 2000)
                                            });
                                        }

                                        function start(id) {
                                            $.get("{ :app_url }api/bot/start/" + id, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                                setTimeout(function () {
                                                    location.reload();
                                                }, 2000);
                                            });
                                        }

                                        function deleteBot(id) {
                                            $.get("{ :app_url }api/delete/" + id, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                                setTimeout(function () {
                                                    location.href = "{ :app_url }";
                                                }, 2000);
                                            });
                                        }

                                        function updateConnection(id) {
                                            $.post("{ :app_url }api/bot/update/" + id, {
                                                nickname: $("#nickname").val(),
                                                ip: $("#ip").val(),
                                                commander: document.getElementById("checkbox-commander").checked,
                                                volume: slider.value,
                                                default: $("#default").val(),
                                                default_password: $("#channel_password").val(),
                                                server_password: $("#server_pw").val()
                                            }, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                            });
                                        }

                                        function updateIdentity(id) {
                                            $.post("{ :app_url }api/bot/identity/" + id, {
                                                identity: $("#identity_key").val()
                                            }, function(data) {

                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                            });
                                        }

                                        function playSong(id) {
                                            $.post("{ :app_url }api/bot/play/" + id, {
                                                song: $("#song_input").val()
                                            }, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                            });
                                        }

                                        function playQuick(url, id) {
                                            $.post("{ :app_url }api/bot/play/" + id, {
                                                song: url
                                            }, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                            });
                                        }

                                        function stopSong(id) {
                                            $.get("{ :app_url }api/bot/stop/" + id,
                                                function (data) {
                                                    if (data.error === true) {
                                                        Swal({
                                                            type: 'error',
                                                            title: 'Failed',
                                                            text: data.error_msg,
                                                        })
                                                    } else {
                                                        Swal({
                                                            type: 'success',
                                                            title: 'Done',
                                                            text: data.error_msg
                                                        })
                                                    }
                                                });
                                        }
                                        function getCurrent(id) {
                                            $.get("{ :app_url }api/bot/current/" + id,
                                                function(data) {
                                                    if (data.error === true) {
                                                        Swal({
                                                            type: "error",
                                                            title: "Failed",
                                                            text: data.error_msg
                                                        });
                                                    } else {
                                                        current = JSON.parse(data.current);
                                                        if (typeof current.ErrorCode !== "undefined") {
                                                            $("#current_song").text("Nothing playing");
                                                        } else {
                                                            $("#current_song").html("" + current.Value + "");
                                                        }
                                                        $("#volume_display").text(data.volume);
                                                        $("#volume").val(data.volume);
                                                        $("#default").val(data.default_channel);
                                                        $("#channel_password").val(data.default_password);
                                                        $("#server_pw").val(data.server_password);
                                                        $("#identity_key").val(data.identity);
                                                    }
                                            });
                                        }
                                        getCurrent({ :bot.id });
                                

admin_list.html

This renders a list of Users to the Admin. Only parameter is users

property explanation
id ID of the user
username Username of the user
email email of the user
password Hashed password of the user
register registration timestamp
last_login Timestamp of the last login
permission Permission level of the user
mb_limit the bot limit of the user.

admin_user.html

This page displays information about one specific user. Parameters are id, user and bots

All parameters are explained already above.

To change the limit, delete a Bot or delete the User, look at the following examples:

                                        function deleteUser(id) {
                                            $.get("{ :app_url }api/users/delete/" + id, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                            });
                                        }

                                        function deleteBot(id) {
                                            $.get("{ :app_url }api/delete/" + id, function (data) {
                                                if (data.error === true) {
                                                    Swal({
                                                        type: 'error',
                                                        title: 'Failed',
                                                        text: data.error_msg,
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'success',
                                                        title: 'Done',
                                                        text: data.error_msg
                                                    })
                                                }
                                                setTimeout(function() {
                                                   location.reload();
                                                }, 2000);
                                            });
                                        }

                                        function changeLimit(id) {
                                            Swal.fire({
                                                title: "Change Bot Limit",
                                                input: 'text',
                                                showCancelButton: true,
                                                confirmButtonText: 'Update',
                                                showLoaderOnConfirm: true,
                                                preConfirm: (limit) => {
                                                    return fetch(`{ :app_url }api/botlimit/${id}/${limit}`, { credentials: "same-origin" })
                                                        .then(response => {
                                                            if (!response.ok) {
                                                                throw new Error(response.statusText)
                                                            }
                                                            return response.json()
                                                        })
                                                        .catch(error => {
                                                            Swal.showValidationMessage(
                                                                `Request failed: ${error}`
                                                            )
                                                        })
                                                },
                                                allowOutsideClick: () => !Swal.isLoading()
                                            }).then((result) => {
                                                console.log(result);
                                                if (result.value.error === false) {
                                                    Swal({
                                                        type: 'success',
                                                        title: "Update complete",
                                                        text: result.value.error_msg
                                                    })
                                                } else {
                                                    Swal({
                                                        type: 'error',
                                                        title: "Update complete",
                                                        text: result.value.error_msg
                                                    })
                                                }
                                            })
                                        }
                                

admin_bots.html

This display all Bots created. The only parameter is bots, which is explained above already, but with an additional username attribute to get the username of the Bots owner.