TS3AudioBot Panel
This product need a certain level of technical expertise. If you don't know what you are doing, you might break the System and cause bad things to happen.
First of all, Thank you so much for purchasing this template and for
being my loyal customer.
You are awesome!
You are entitled to get free lifetime updates to this product +
exceptional support from the author directly.
This documentation is to help you regarding each step of customization. Please go through the documentation carefully to understand how this product is working and how you can work with it.
You will need the following sofwares to install and use this product:
Let's get started installing the Interface on your Server. For demonstration purposes, imagine I use a Debian 9.8 Server during this installation process.
In theory the process is pretty simple:
Your download key can be found in the CIS under the "Products"-tab (https://bennetgallein.de/cis/products)
root@server:/var/www/html# wget --prefer-family=IPv4 https://bennetgallein.de/api/download-key/...
Once downloaded, rename the file:
root@server:/var/www/html# mv <file> cp.zip
And unpack it:
root@server:/var/www/html# unzip cp.zip
As said, I assume that you already have a MySQL Database installed on your System (prefferable a MariaDB 10.1.37 Server).
Let's enter the Database over the command line tool.
root@server:/# mysql -u root
If you have a password for the root user, use this command:
root@server:/# mysql -u root -p
After you logged in to the Database, you should see something like this:
MariaDB [(none)]>
You see it? Great! Let's create the Database:
MariaDB [(none)]> CREATE DATABASE TS3ABCP; Query OK, 1 row affected (0.01 sec) MariaDB [(none)]>
Now you want to exit the Database. Use exit;
to do that.
Now we want to import the Database. The easiest thing is to use the command line or
a tool like phpmyadmin if that is installed:
root@server:/# mysql -u root -p TS3ABCP < /var/www/html/database.sql
Now, we are basically finished. We just need to install the Dependencies, create an Account and give it Admin rights.
root@server:/var/www/html/# chmod +x ./bin/install.sh && sudo ./bin/install.sh
This will install all the dependencies the Interface needs, if errors accour during the installation, try fixing them by googleing.
Continue by downloading all permission and language files required.
root@server:/var/www/html/# chmod +x ./bin/download_* && sudo ./bin/download_*
Now onto the important point on this list to make everythink work just the way you expect it to. If you do not have an config.json by this point (should be created by the script above)
root@server:/var/www/html# cp config.json.example config.json && nano config.json
Key | Example | Value |
---|---|---|
APP_URL |
"/" |
This is the URL of your application. If you want it to run on yourdomain.com/
enter / , otherwise the path like /TS3ABCP/
|
DB_HOST |
"localhost" |
The Host of your Database. Should be localhost , 127.0.0.1
or your IP. |
DB_USER |
"root" |
The User with which to access the Database. |
DB_PASSWORD |
"root" |
The passwort of the Database user specified in DB_USER .
Enter "" if you dont want to enter a password |
DB_NAME |
"TS3ABCP" |
The name of the Database which you'll have create with the steps above.
If you followed the tutorial, enter TS3ABCP |
MB_HOST |
"localhost" |
The host of the server where the Bot is running. If it is running,
localhost should be fine. Remember to expose the IP in the
config file of the Bot! |
MB_PORT |
"8180" |
The port from the API of the Bot. Default is 8180 |
MB_TOKEN |
"j+W41OpXcHv8In9vt/Q2x+UmUPs=:ts3ab:GVFdH..." |
This is the response from !bot api token which you will
need to authenticate as an admin, so the Interface can control the Bots |
MB_LIMIT |
"3" |
This is the default limit of Bots a normal User can create. If you
don't want to set a limit, set it to -1 to enable infinite
Bots per user |
REGISTER_ACTIVE |
true |
With this you are able to disable registrations for new users. Set to
false to disable registrations. |
TERMS_AND_CONDITIONS |
"http://example/tos.html" |
A link to your Terms and Conditions. This will be linked on the registration site. |
CUSTOM_BOX_TITLE |
"Website" |
This is the box on the dashboard where you can enter a custom thing. |
CUSTOM_BOX_TEXT |
"bennetgallein.de" |
This is the content of the box on the dashboard. |
QUICKPLAY |
{
"ILoveRadion": "http://stream01.iloveradio.de/iloveradio1.mp3",
"ReyFM": "https://stream01.reyfm.de/original_192kbps.mp3"
} |
This is a JSON Array for custom quicklplay links. On the left side (key) is the Name (can be anything) while on the right site you need to paste the direct play link to the stream! |
THEME |
"default" |
This is the theme folder, inside the _views folder. If you
didn't know what to write here, just enter the example value |
ANALYTICS_ENABLED |
true |
If you want to have analytics reports enabled |
ANALYTICS_KEY |
6254e81ade14be8908cd0d9f05da90f6 |
your personal analytics key. If you dont have one, you can register your site here: bennetgallein.de/cis |
MODULES |
"MODULES": { "TicketModule": false, "AntiRobotModule": true } |
This is an array of your activated modules. If you want to have the module enabled, set true otherwise false .You need to purchase and install the Module in order to use it! |
optional: API_ENABLED |
false |
Wether you want to have the API enabled. This feature is only in the commercial edition! |
optional: API_AUTH |
super-secure-token |
This is the Authentication Token you need to communicate with the REST-API.This feature is only in the commercial edition! |
Save everything once you are done with editing and exit.
Starting with the 2.1.0
release, the Panel features a detailed permission system, which allows you to create roles for different groups of users and allow and disallow certain actions.
The permission files are all stored in the _permissions
folder, the default.json
is from the core of the Panel, all other files there are from Modules.
If you don't have any permission files in the folder, run the following command from the folder of the CP to download the default permission: 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" ] }
What you can see here is pretty similliar to the content in _permissions/default.json
. "0"
,"50"
,"100"
are the permissions that you need to set in the Database in order to assign a user to a group.
value | explanation |
---|---|
admin.users |
Permission to see the list of users |
admin.user |
Pemrission to see individual user |
admin.user.delete |
Permission to delete a user |
admin.user.changelimit |
Permission to change the individual botlimit for a user |
admin.user.makeadmin |
Pemrission to make a user an admin |
admin.user.addbalance |
Permission to add balance to the users account |
admin.user.removebalance |
Permission to remove balance from the users account |
admin.bots |
Permission to see the list of bots |
admin.bot |
Permission to take full control over bots the user doesn't own, usefull for support-purposes |
admin.internal.apiunresponsive |
Permission to click the "API crashed" button in the Admin view |
admin.internal.startallbots |
Permission to click the "Start all Bots" button in the Admin view |
admin.internal.stopallbots |
Permission to click the "Stop all Bots" button in the Admin view |
admin.internal.update |
Permission to update the Software |
admin.internal.migrate |
Permission to visit the migrate to url, only if your version is older than 1.1.8 |
admin.ignoredeactivatedregister |
Permission to register even if the REGISTER_ACTIVE is false. |
admin.setpermission |
Permission to update the permission level of a user |
For Module Permissions, view the Modules Section and teir respective Documentation.
Now, you are finished. Open your Browser and browse to your IP. Create a new User,
enter the Database and set the permission
to your Admin Permission level. Now you
can login and enjoy your product!
All Modules need a config-entry in order to get loaded:
"MODULES": { "TicketModule": true, "AntiRobotModule": true }
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.
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 |
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"
))
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.
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.
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
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.
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.
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!
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.
_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.
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); } }); });
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); } }); });
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 |
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, }) } }); }
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 |
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?
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"); } }); });
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 });
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 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. |
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 }) } }) }
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.