Squashed commit of the following:
commit e946bf124602f224ce0e371ba1374f0355b537eb
Merge: d6a4e64
4505909
Author: Rosemary Witchaven <32779090+in1tiate@users.noreply.github.com>
Date: Fri Jan 28 19:43:36 2022 -0600
Merge pull request #225 from Salanto/Dynamic-Area-Musiclist-Take2
Allow users to add custom songs to the music list on a per-area basis
commit 45059092d2888b60912f721e43a380910d10ccd8
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 24 22:05:27 2022 +0100
TIL what a typedef is
commit 02584db9640fff0a1969a7f516c4bccfae9b5388
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 24 21:39:17 2022 +0100
Not all OR are equal. Explain weird command splitting
Remove hardcoded URLs
commit d00ebd5692296cd0c29dd377113b53fe0e7b99c0
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 24 21:28:08 2022 +0100
Salanto PR Language Update by in1tiate
As usual, my English is absolutely unreadable.
Co-authored-by: Rosemary Witchaven <32779090+in1tiate@users.noreply.github.com>
commit d3842106e06350dc02d8864bb28232fdc5643f00
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 24 20:35:32 2022 +0100
Add missing config file + document commands for help
commit ac64360e1c1741023b01052977de77a7d5ea4f8c
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 24 19:52:13 2022 +0100
Minor improvements to command usage and addition of clear command
commit c614578e78ce9afa0c8e22aa36bdf46a70a97169
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 23 22:19:54 2022 +0100
Purge last traces of old songInformation system
commit 07618761f044a13d75587b28a9c994342a5980e2
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 23 22:10:54 2022 +0100
Working version, needs some refinement and debugging in AOClient
commit 33c0358c98c0fd2de805356a9aa3ac7bbed204e1
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 23 21:48:05 2022 +0100
Almost functional implementation
Now only need to determine why I can't play the customs yet
commit b0acbace78b3f16f2fe4f3c6f65a422e3343f992
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 23 15:26:42 2022 +0100
Fix build error, expand validation test slightly
commit a48c4f503998ce8e42f0bb409c5a3c7dc5e40329
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 23 01:03:27 2022 +0100
Add commands
commit 88ab0b473953873166e291e5009b97df31547b3f
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sat Jan 22 15:10:26 2022 +0100
Float sucks, int has to be good enough
+ add retrival of song information
commit e924e1340be1a0909eba84072f1646fe9770bd02
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Thu Jan 20 22:28:35 2022 +0100
Fix removing moving
Add necessary tests
commit 3df088f8d07ce7e0d8fe08b6a97608a623e6ef97
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Wed Jan 19 19:34:16 2022 +0100
Start work on adding this shit into commands
commit c293ecfa99d1b2bd1e0b34cb8752d69b2eca057c
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Tue Jan 18 19:07:11 2022 +0100
Fix typo and add singal for incremental upgrades
commit 10a42322e1e23af5795278a40b2ac59f3ab952ef
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Tue Jan 18 06:17:51 2022 +0100
Hookup packet sending to music manager
This might sound like a bad idea on first glance, but otherwise it breaks the AreaData tests and I am NOT gonna try to fix those without even understanding why they break.
commit 319836296374162b0b847432e8a626778317b869
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Tue Jan 18 06:17:51 2022 +0100
Enraged comments, make area send FM packet
Revert "Enraged comments, make area send FM packet"
This reverts commit ec7a1a25646b2c2acc8a3a748b853851cc47d205.
commit 224a0d7efe989a5f336167c3f716061813f93ee3
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Tue Jan 18 05:10:18 2022 +0100
Change packet communication from area to client
First steps to hookup the custom musiclist.
commit 65aa8f7855a36f2c668b1399a5ed22fefeaf186d
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 17 00:48:38 2022 +0100
Add test for custom list sanitisation.
+ Fix intentionally broken tests
commit 7c00ab437a6ff12033742d029ce49037f5bb1ebe
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Mon Jan 17 00:29:51 2022 +0100
Sanitise the custom list opposed to deleting it
This will fail tests intentionally to test the CI.
commit 80ad401267068e75707b2517a0bf836763141f8b
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 16 17:17:12 2022 +0100
Add custom category capabilities
commit 08d8f5f8f683816ceba532f9c47cd0d5ab34389a
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sun Jan 16 03:58:18 2022 +0100
Fix music addition and move relevant tests
commit 6ebf0d03b5da61a9c287115009d28038710ba7af
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sat Jan 15 08:08:20 2022 +0100
Hookup music_manager into server, change default musiclist source for new clients
+ More tests 🆒
commit bd50c62376f131e2508ecdd3e272209894ecaec1
Author: Salanto <62221668+Salanto@users.noreply.github.com>
Date: Sat Jan 15 03:13:42 2022 +0100
Add central song validator for other classes
Also added applicable test cases to ensure proper operation.
This commit is contained in:
parent
d6a4e64070
commit
83c41c05f7
1
bin/config_sample/text/cdns.txt
Normal file
1
bin/config_sample/text/cdns.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
cdn.discord.com
|
@ -646,7 +646,32 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name":"areamessage",
|
"name":"areamessage",
|
||||||
"usage":"/areamessage",
|
"usage":"/areamessage 'Message'",
|
||||||
"text":"Returns the area message in OOC. If text is entered it updates the current area message."
|
"text":"Returns the area message in OOC. If text is entered it updates the current area message."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"addsong",
|
||||||
|
"usage":"/addsong <Songname>,'TrueName','Duration'",
|
||||||
|
"text":"Adds a song to the custom musiclist. Optionally can be an aliased name to hide a streamlink. Set the duration for the jukebox."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"addcategory",
|
||||||
|
"usage":"/addsong <Category>",
|
||||||
|
"text":"Adds a category to the custom musiclist."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"removeentry",
|
||||||
|
"usage":"/removeentry 'Name'",
|
||||||
|
"text":"Removes an entry from the custom musiclist."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"toggleglobal",
|
||||||
|
"usage":"/toggleglobal",
|
||||||
|
"text":"Changes the behaviour of prepending the server root musiclist to the custom lists of the area."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"clearcustom",
|
||||||
|
"usage":"/clearcustom",
|
||||||
|
"text":"Removes all custom songs from the area."
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -47,7 +47,8 @@ SOURCES += \
|
|||||||
src/advertiser.cpp \
|
src/advertiser.cpp \
|
||||||
src/logger/u_logger.cpp \
|
src/logger/u_logger.cpp \
|
||||||
src/logger/writer_modcall.cpp \
|
src/logger/writer_modcall.cpp \
|
||||||
src/logger/writer_full.cpp
|
src/logger/writer_full.cpp \
|
||||||
|
src/music_manager.cpp
|
||||||
|
|
||||||
HEADERS += include/aoclient.h \
|
HEADERS += include/aoclient.h \
|
||||||
include/aopacket.h \
|
include/aopacket.h \
|
||||||
@ -62,4 +63,5 @@ HEADERS += include/aoclient.h \
|
|||||||
include/advertiser.h \
|
include/advertiser.h \
|
||||||
include/logger/u_logger.h \
|
include/logger/u_logger.h \
|
||||||
include/logger/writer_modcall.h \
|
include/logger/writer_modcall.h \
|
||||||
include/logger/writer_full.h
|
include/logger/writer_full.h \
|
||||||
|
include/music_manager.h
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "include/server.h"
|
#include "include/server.h"
|
||||||
#include "include/area_data.h"
|
#include "include/area_data.h"
|
||||||
#include "include/db_manager.h"
|
#include "include/db_manager.h"
|
||||||
|
#include "include/music_manager.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -50,14 +51,7 @@ class AOClient : public QObject {
|
|||||||
* @param user_id The user ID of the client.
|
* @param user_id The user ID of the client.
|
||||||
* @param parent Qt-based parent, passed along to inherited constructor from QObject.
|
* @param parent Qt-based parent, passed along to inherited constructor from QObject.
|
||||||
*/
|
*/
|
||||||
AOClient(Server* p_server, QTcpSocket* p_socket, QObject* parent = nullptr, int user_id = 0)
|
AOClient(Server* p_server, QTcpSocket* p_socket, QObject* parent = nullptr, int user_id = 0, MusicManager* p_manager = nullptr);;
|
||||||
: QObject(parent), m_id(user_id), m_remote_ip(p_socket->peerAddress()), m_password(""),
|
|
||||||
m_joined(false), m_current_area(0), m_current_char(""), m_socket(p_socket), server(p_server),
|
|
||||||
is_partial(false), m_last_wtce_time(0) {
|
|
||||||
m_afk_timer = new QTimer;
|
|
||||||
m_afk_timer->setSingleShot(true);
|
|
||||||
connect(m_afk_timer, SIGNAL(timeout()), this, SLOT(onAfkTimeout()));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destructor for the AOClient instance.
|
* @brief Destructor for the AOClient instance.
|
||||||
@ -1868,6 +1862,31 @@ class AOClient : public QObject {
|
|||||||
*/
|
*/
|
||||||
void cmdToggleJukebox(int argc, QStringList argv);
|
void cmdToggleJukebox(int argc, QStringList argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a song to the custom list.
|
||||||
|
*/
|
||||||
|
void cmdAddSong(int argc, QStringList argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a category to the areas custom music list.
|
||||||
|
*/
|
||||||
|
void cmdAddCategory(int argc, QStringList argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes any matching song or category from the custom area.
|
||||||
|
*/
|
||||||
|
void cmdRemoveCategorySong(int argc, QStringList argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Toggles the prepending behaviour of the servers root musiclist.
|
||||||
|
*/
|
||||||
|
void cmdToggleRootlist(int argc, QStringList argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the entire custom list of this area.
|
||||||
|
*/
|
||||||
|
void cmdClearCustom(int argc, QStringList argv);
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2185,7 +2204,12 @@ class AOClient : public QObject {
|
|||||||
{"clearcm", {ACLFlags.value("KICK"), 0, &AOClient::cmdClearCM}},
|
{"clearcm", {ACLFlags.value("KICK"), 0, &AOClient::cmdClearCM}},
|
||||||
{"togglemessage", {ACLFlags.value("CM"), 0, &AOClient::cmdToggleAreaMessageOnJoin}},
|
{"togglemessage", {ACLFlags.value("CM"), 0, &AOClient::cmdToggleAreaMessageOnJoin}},
|
||||||
{"clearmessage", {ACLFlags.value("CM"), 0, &AOClient::cmdClearAreaMessage}},
|
{"clearmessage", {ACLFlags.value("CM"), 0, &AOClient::cmdClearAreaMessage}},
|
||||||
{"areamessage", {ACLFlags.value("CM"), 0, &AOClient::cmdAreaMessage}}
|
{"areamessage", {ACLFlags.value("CM"), 0, &AOClient::cmdAreaMessage}},
|
||||||
|
{"addsong", {ACLFlags.value("CM"), 1, &AOClient::cmdAddSong}},
|
||||||
|
{"addcategory", {ACLFlags.value("CM"), 1, &AOClient::cmdAddCategory}},
|
||||||
|
{"removeentry", {ACLFlags.value("CM"), 1, &AOClient::cmdRemoveCategorySong}},
|
||||||
|
{"toggleroot", {ACLFlags.value("CM"), 0, &AOClient::cmdToggleRootlist}},
|
||||||
|
{"clearcustom", {ACLFlags.value("CM"), 0, &AOClient::cmdClearCustom}}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2234,6 +2258,11 @@ class AOClient : public QObject {
|
|||||||
*/
|
*/
|
||||||
QString m_last_message;
|
QString m_last_message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pointer to the servers music manager instance.
|
||||||
|
*/
|
||||||
|
MusicManager* m_music_manager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A helper function to add recorded packets to an area's judgelog.
|
* @brief A helper function to add recorded packets to an area's judgelog.
|
||||||
*
|
*
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "aopacket.h"
|
#include "aopacket.h"
|
||||||
#include "config_manager.h"
|
#include "config_manager.h"
|
||||||
|
#include "music_manager.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -44,7 +45,7 @@ class AreaData : public QObject {
|
|||||||
* and `YYYYYY` is the actual name of the area.
|
* and `YYYYYY` is the actual name of the area.
|
||||||
* @param p_index The index of the area in the area list.
|
* @param p_index The index of the area in the area list.
|
||||||
*/
|
*/
|
||||||
AreaData(QString p_name, int p_index);
|
AreaData(QString p_name, int p_index, MusicManager* p_music_manager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The data for evidence in the area.
|
* @brief The data for evidence in the area.
|
||||||
@ -865,9 +866,11 @@ public slots:
|
|||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Changes the song in the current area when the jukebox timer expires.
|
* @brief Sends a packet to every client inside the area.
|
||||||
*/
|
*/
|
||||||
void playJukeboxSong(AOPacket f_packet, int f_area_index);
|
void sendAreaPacket(AOPacket f_packet, int f_area_index);
|
||||||
|
|
||||||
|
void userJoinedArea(int f_area_index, int f_user_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -885,6 +888,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
int m_index;
|
int m_index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pointer to the global music manager.
|
||||||
|
*/
|
||||||
|
MusicManager* m_music_manager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A list of the character IDs of all characters taken.
|
* @brief A list of the character IDs of all characters taken.
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
typedef QMap<QString,QPair<QString,int>> MusicList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The config file handler class.
|
* @brief The config file handler class.
|
||||||
*/
|
*/
|
||||||
@ -76,7 +78,14 @@ class ConfigManager {
|
|||||||
*
|
*
|
||||||
* @return See short description.
|
* @return See short description.
|
||||||
*/
|
*/
|
||||||
static QStringList musiclist();
|
static MusicList musiclist();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns an ordered QList of all basesongs of this server.
|
||||||
|
*
|
||||||
|
* @return See short description.
|
||||||
|
*/
|
||||||
|
static QStringList ordered_songs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Loads help information into m_help_information.
|
* @brief Loads help information into m_help_information.
|
||||||
@ -85,13 +94,6 @@ class ConfigManager {
|
|||||||
*/
|
*/
|
||||||
static void loadCommandHelp();
|
static void loadCommandHelp();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the duration of a song in the songlist.
|
|
||||||
* @param The name of the song where duration is requested
|
|
||||||
* @return The duration of the song
|
|
||||||
*/
|
|
||||||
static QPair<QString, float> songInformation(const QString& f_songName);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the content of
|
* @brief Returns the content of
|
||||||
*
|
*
|
||||||
@ -412,6 +414,13 @@ class ConfigManager {
|
|||||||
*/
|
*/
|
||||||
static QStringList gimpList();
|
static QStringList gimpList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the server approved domain list.
|
||||||
|
*
|
||||||
|
* @return See short description.
|
||||||
|
*/
|
||||||
|
static QStringList cdnList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns if the advertiser is enabled to advertise on ms3.
|
* @brief Returns if the advertiser is enabled to advertise on ms3.
|
||||||
*/
|
*/
|
||||||
@ -473,6 +482,7 @@ class ConfigManager {
|
|||||||
*/
|
*/
|
||||||
static void reloadSettings();
|
static void reloadSettings();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Checks if a file exists and is valid.
|
* @brief Checks if a file exists and is valid.
|
||||||
@ -500,6 +510,7 @@ private:
|
|||||||
QStringList praises; //!< Contains command praises, found in config/text/praises.txt
|
QStringList praises; //!< Contains command praises, found in config/text/praises.txt
|
||||||
QStringList reprimands; //!< Contains command reprimands, found in config/text/reprimands.txt
|
QStringList reprimands; //!< Contains command reprimands, found in config/text/reprimands.txt
|
||||||
QStringList gimps; //!< Contains phrases for /gimp, found in config/text/gimp.txt
|
QStringList gimps; //!< Contains phrases for /gimp, found in config/text/gimp.txt
|
||||||
|
QStringList cdns; // !< Contains domains for custom song validation, found in config/text/cdns.txt
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -535,7 +546,12 @@ private:
|
|||||||
/**
|
/**
|
||||||
* @brief Contains the musiclist with time durations.
|
* @brief Contains the musiclist with time durations.
|
||||||
*/
|
*/
|
||||||
static QHash<QString,QPair<QString,float>>* m_musicList;
|
static MusicList* m_musicList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contains an ordered list for the musiclist.
|
||||||
|
*/
|
||||||
|
static QStringList* m_ordered_list;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief QHash containing the help information for all commands registered to the server.
|
* @brief QHash containing the help information for all commands registered to the server.
|
||||||
|
214
core/include/music_manager.h
Normal file
214
core/include/music_manager.h
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// akashi - a server for Attorney Online 2 //
|
||||||
|
// Copyright (C) 2020 scatterflower //
|
||||||
|
// //
|
||||||
|
// This program is free software: you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU Affero General Public License as //
|
||||||
|
// published by the Free Software Foundation, either version 3 of the //
|
||||||
|
// License, or (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU Affero General Public License for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU Affero General Public License //
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifndef MUSIC_MANAGER_H
|
||||||
|
#define MUSIC_MANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
|
#include <include/config_manager.h>
|
||||||
|
#include <include/aopacket.h>
|
||||||
|
|
||||||
|
class MusicManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor for the server-wide musiclist manager.
|
||||||
|
*
|
||||||
|
* @param Copy of the server musiclist generated by ConfigManager::musiclist();
|
||||||
|
*/
|
||||||
|
MusicManager(QObject* parent = nullptr, QStringList f_root_ordered = {}, QStringList f_cdns = {"cdn.discord.com"},
|
||||||
|
QMap<QString, QPair<QString, int> > f_root_list = ConfigManager::musiclist());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor for the server-wide musiclist manager.
|
||||||
|
*/
|
||||||
|
virtual ~MusicManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a musiclist with aliased names.
|
||||||
|
*
|
||||||
|
* @return See short description.
|
||||||
|
*/
|
||||||
|
QStringList musiclist(int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns only the root musiclist with aliased names.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
QStringList rootMusiclist();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new area to the music_manager.
|
||||||
|
*
|
||||||
|
* @param f_area_id ID of the new area being added.
|
||||||
|
*
|
||||||
|
* @return Returns false if registering the area fails.
|
||||||
|
*/
|
||||||
|
bool registerArea(int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates the song candidate to be played. If validation fails, false is returned.
|
||||||
|
*
|
||||||
|
* @param f_song_name The song to be played. Can be an http/https stream or a local file.
|
||||||
|
*
|
||||||
|
* @param f_approved_cdns A list of approved remote content sources.
|
||||||
|
*
|
||||||
|
* @return Wether or not the song can be played or added.
|
||||||
|
*/
|
||||||
|
bool validateSong(QString f_song_name, QStringList f_approved_cdns);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attempts to add the new song to the custom musiclist.
|
||||||
|
*
|
||||||
|
* @param f_song_name Friendly name shown in the clients musiclist.
|
||||||
|
*
|
||||||
|
* @param f_real_name Real name/url of the file.
|
||||||
|
*
|
||||||
|
* @param f_duration Playtime of the musicfile in seconds.
|
||||||
|
*
|
||||||
|
* @param f_area_id Area id of the clients current area.
|
||||||
|
*
|
||||||
|
* @return Returns true on success, false on fail.
|
||||||
|
*/
|
||||||
|
bool addCustomSong(QString f_song_name, QString f_real_name, int f_duration, int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attempts to add the new category to the custom musiclist.
|
||||||
|
*
|
||||||
|
* @param f_category_name Category name candidate.
|
||||||
|
*
|
||||||
|
* @return Returns true on saccess, false on fail.
|
||||||
|
*/
|
||||||
|
bool addCustomCategory(QString f_category_name, int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes either a song or a category from the custom list.
|
||||||
|
*
|
||||||
|
* @param Name of the category or song to remove
|
||||||
|
*
|
||||||
|
* @return True on success, false on failure.
|
||||||
|
*/
|
||||||
|
bool removeCategorySong(QString f_songcategory_name, int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Toggles wether the root list is included for this area.
|
||||||
|
* This also delets the custom llist if it was enabled prior.
|
||||||
|
*
|
||||||
|
* @return Current state of the music list.
|
||||||
|
*/
|
||||||
|
bool toggleRootEnabled(int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes conflicting songnames from the custom list.
|
||||||
|
*
|
||||||
|
* @param f_area_id Id of the area this is invoked in.
|
||||||
|
*/
|
||||||
|
void sanitiseCustomList(int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes all entries from the custom list.
|
||||||
|
* @param f_area_id Id of the area custom list.
|
||||||
|
*/
|
||||||
|
void clearCustomList(int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns song information necessary for the operation of the jukebox.
|
||||||
|
* @param Alias name of the song.
|
||||||
|
* @param Area of the jukebox checking for information.
|
||||||
|
* @return Returns a QPair with the true name and duration of the invoked song.
|
||||||
|
*/
|
||||||
|
QPair<QString, int> songInformation(QString f_song_name, int f_area_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a song is part of the clients current area custom list.
|
||||||
|
*
|
||||||
|
* @return Returns true if the song exists as a custom song.
|
||||||
|
*/
|
||||||
|
bool isCustom(int f_area_id, QString f_song_name);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the root musiclist and CDN list.
|
||||||
|
*/
|
||||||
|
void reloadRequest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Triggers sending of FM packet to client joining a new area.
|
||||||
|
*/
|
||||||
|
void userJoinedArea(int f_area_index, int f_user_id);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends the FM packet with the musiclist of the area when a client enters.
|
||||||
|
*
|
||||||
|
* @param f_packet FM packet with the full musiclist, when enabled, and custom list.
|
||||||
|
*
|
||||||
|
* @param f_user_id temporary userid of the incoming client.
|
||||||
|
*/
|
||||||
|
void sendFMPacket(AOPacket f_packet, int f_user_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends the FM packet with the musiclist of the area when changes are made.
|
||||||
|
*
|
||||||
|
* @param f_packet FM packet with the full musiclist, when enabled, and eventual custom list.
|
||||||
|
*
|
||||||
|
* @param f_area_index Index of the current area the edit is made in.
|
||||||
|
*/
|
||||||
|
void sendAreaFMPacket(AOPacket f_packet, int f_area_index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contains all custom lists of all areas in the server.
|
||||||
|
*/
|
||||||
|
QHash<int,MusicList>* m_custom_lists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Server musiclist shared among all areas.
|
||||||
|
*/
|
||||||
|
MusicList m_root_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief QList with the ordered musiclist.
|
||||||
|
*/
|
||||||
|
QStringList m_root_ordered;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contains all custom songs ordered in a per-area buffer.
|
||||||
|
*/
|
||||||
|
QMap<int,QStringList> m_customs_ordered;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wether the global musiclist is prepend and validation when adding custom music.
|
||||||
|
*/
|
||||||
|
QHash<int,bool> m_global_enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contains all server approved content sources.
|
||||||
|
*/
|
||||||
|
QStringList m_cdns;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MUSIC_MANAGER_H
|
@ -27,6 +27,7 @@
|
|||||||
#include "include/config_manager.h"
|
#include "include/config_manager.h"
|
||||||
#include "include/advertiser.h"
|
#include "include/advertiser.h"
|
||||||
#include "include/logger/u_logger.h"
|
#include "include/logger/u_logger.h"
|
||||||
|
#include "include/music_manager.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@ -126,6 +127,7 @@ class Server : public QObject {
|
|||||||
* @brief Sends a packet to all clients in a given area.
|
* @brief Sends a packet to all clients in a given area.
|
||||||
*
|
*
|
||||||
* @param packet The packet to send to the clients.
|
* @param packet The packet to send to the clients.
|
||||||
|
*
|
||||||
* @param area_index The index of the area to look for clients in.
|
* @param area_index The index of the area to look for clients in.
|
||||||
*
|
*
|
||||||
* @note Does nothing if an area by the given index does not exist.
|
* @note Does nothing if an area by the given index does not exist.
|
||||||
@ -140,7 +142,7 @@ class Server : public QObject {
|
|||||||
void broadcast(AOPacket packet);
|
void broadcast(AOPacket packet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a packet to clients, sends an altered packet to a specific usergroup.
|
* @brief Sends a packet to a specific usergroup..
|
||||||
*
|
*
|
||||||
* @param The packet to send to the clients.
|
* @param The packet to send to the clients.
|
||||||
*
|
*
|
||||||
@ -159,6 +161,15 @@ class Server : public QObject {
|
|||||||
*/
|
*/
|
||||||
void broadcast(AOPacket packet, AOPacket other_packet, enum TARGET_TYPE target);
|
void broadcast(AOPacket packet, AOPacket other_packet, enum TARGET_TYPE target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends a packet to a single client.
|
||||||
|
*
|
||||||
|
* @param The packet send to the client.
|
||||||
|
*
|
||||||
|
* @param The temporary userID of the client.
|
||||||
|
*/
|
||||||
|
void unicast(AOPacket f_packet, int f_client_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the character's character ID (= their index in the character list).
|
* @brief Returns the character's character ID (= their index in the character list).
|
||||||
*
|
*
|
||||||
@ -385,6 +396,11 @@ class Server : public QObject {
|
|||||||
*/
|
*/
|
||||||
ULogger* logger;
|
ULogger* logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles all musiclists.
|
||||||
|
*/
|
||||||
|
MusicManager* music_manager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The port through which the server will accept TCP connections.
|
* @brief The port through which the server will accept TCP connections.
|
||||||
*/
|
*/
|
||||||
|
@ -347,9 +347,15 @@ bool AOClient::checkAuth(unsigned long long acl_mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString AOClient::getIpid() const { return m_ipid; }
|
QString AOClient::getIpid() const
|
||||||
|
{
|
||||||
|
return m_ipid;
|
||||||
|
}
|
||||||
|
|
||||||
QString AOClient::getHwid() const { return m_hwid; }
|
QString AOClient::getHwid() const
|
||||||
|
{
|
||||||
|
return m_hwid;
|
||||||
|
}
|
||||||
|
|
||||||
Server* AOClient::getServer() { return server; }
|
Server* AOClient::getServer() { return server; }
|
||||||
|
|
||||||
@ -360,6 +366,26 @@ void AOClient::onAfkTimeout()
|
|||||||
m_is_afk = true;
|
m_is_afk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AOClient::AOClient(Server *p_server, QTcpSocket *p_socket, QObject *parent, int user_id, MusicManager *p_manager)
|
||||||
|
: QObject(parent),
|
||||||
|
m_id(user_id),
|
||||||
|
m_remote_ip(p_socket->peerAddress()),
|
||||||
|
m_password(""),
|
||||||
|
m_joined(false),
|
||||||
|
m_current_area(0),
|
||||||
|
m_current_char(""),
|
||||||
|
m_socket(p_socket),
|
||||||
|
server(p_server),
|
||||||
|
is_partial(false),
|
||||||
|
m_last_wtce_time(0),
|
||||||
|
m_music_manager(p_manager)
|
||||||
|
{
|
||||||
|
m_afk_timer = new QTimer;
|
||||||
|
m_afk_timer->setSingleShot(true);
|
||||||
|
connect(m_afk_timer, &QTimer::timeout,
|
||||||
|
this, &AOClient::onAfkTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
AOClient::~AOClient() {
|
AOClient::~AOClient() {
|
||||||
m_socket->deleteLater();
|
m_socket->deleteLater();
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,9 @@
|
|||||||
|
|
||||||
#include "include/area_data.h"
|
#include "include/area_data.h"
|
||||||
|
|
||||||
AreaData::AreaData(QString p_name, int p_index) :
|
AreaData::AreaData(QString p_name, int p_index, MusicManager* p_music_manager = nullptr) :
|
||||||
m_index(p_index),
|
m_index(p_index),
|
||||||
|
m_music_manager(p_music_manager),
|
||||||
m_playerCount(0),
|
m_playerCount(0),
|
||||||
m_status(IDLE),
|
m_status(IDLE),
|
||||||
m_locked(FREE),
|
m_locked(FREE),
|
||||||
@ -93,6 +94,7 @@ void AreaData::clientJoinedArea(int f_charId, int f_userId)
|
|||||||
m_charactersTaken.append(f_charId);
|
m_charactersTaken.append(f_charId);
|
||||||
}
|
}
|
||||||
m_joined_ids.append(f_userId);
|
m_joined_ids.append(f_userId);
|
||||||
|
emit userJoinedArea(m_index, f_userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<int> AreaData::owners() const
|
QList<int> AreaData::owners() const
|
||||||
@ -564,12 +566,12 @@ QString AreaData::addJukeboxSong(QString f_song)
|
|||||||
{
|
{
|
||||||
if(!m_jukebox_queue.contains(f_song)) {
|
if(!m_jukebox_queue.contains(f_song)) {
|
||||||
//Retrieve song information.
|
//Retrieve song information.
|
||||||
QPair<QString,float> l_song = ConfigManager::songInformation(f_song);
|
QPair<QString,float> l_song = m_music_manager->songInformation(f_song, index());
|
||||||
|
|
||||||
if (l_song.second > 0) {
|
if (l_song.second > 0) {
|
||||||
if (m_jukebox_queue.size() == 0) {
|
if (m_jukebox_queue.size() == 0) {
|
||||||
|
|
||||||
emit playJukeboxSong(AOPacket("MC",{l_song.first,QString::number(-1)}), index());
|
emit sendAreaPacket(AOPacket("MC",{l_song.first,QString::number(-1)}), index());
|
||||||
m_jukebox_timer->start(l_song.second * 1000);
|
m_jukebox_timer->start(l_song.second * 1000);
|
||||||
setCurrentMusic(f_song);
|
setCurrentMusic(f_song);
|
||||||
setMusicPlayedBy("Jukebox");
|
setMusicPlayedBy("Jukebox");
|
||||||
@ -594,16 +596,16 @@ void AreaData::switchJukeboxSong()
|
|||||||
QString l_song_name;
|
QString l_song_name;
|
||||||
if(m_jukebox_queue.size() == 1) {
|
if(m_jukebox_queue.size() == 1) {
|
||||||
l_song_name = m_jukebox_queue[0];
|
l_song_name = m_jukebox_queue[0];
|
||||||
QPair<QString,float> l_song = ConfigManager::songInformation(l_song_name);
|
QPair<QString,float> l_song = m_music_manager->songInformation(l_song_name, index());
|
||||||
emit playJukeboxSong(AOPacket("MC",{l_song.first,"-1"}), m_index);
|
emit sendAreaPacket(AOPacket("MC",{l_song.first,"-1"}), m_index);
|
||||||
m_jukebox_timer->start(l_song.second * 1000);
|
m_jukebox_timer->start(l_song.second * 1000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int l_random_index = QRandomGenerator::system()->bounded(m_jukebox_queue.size() -1);
|
int l_random_index = QRandomGenerator::system()->bounded(m_jukebox_queue.size() -1);
|
||||||
l_song_name = m_jukebox_queue[l_random_index];
|
l_song_name = m_jukebox_queue[l_random_index];
|
||||||
|
|
||||||
QPair<QString,float> l_song = ConfigManager::songInformation(l_song_name);
|
QPair<QString,float> l_song = m_music_manager->songInformation(l_song_name, index());
|
||||||
emit playJukeboxSong(AOPacket("MC",{l_song.first,"-1"}), m_index);
|
emit sendAreaPacket(AOPacket("MC",{l_song.first,"-1"}), m_index);
|
||||||
m_jukebox_timer->start(l_song.second * 1000);
|
m_jukebox_timer->start(l_song.second * 1000);
|
||||||
|
|
||||||
m_jukebox_queue.remove(l_random_index);
|
m_jukebox_queue.remove(l_random_index);
|
||||||
|
@ -127,3 +127,79 @@ void AOClient::cmdToggleJukebox(int argc, QStringList argv)
|
|||||||
sendServerMessage("You do not have permission to change the jukebox status.");
|
sendServerMessage("You do not have permission to change the jukebox status.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdAddSong(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
Q_UNUSED(argc);
|
||||||
|
|
||||||
|
//This needs some explanation.
|
||||||
|
//Akashi has no concept of argument count,so any space is interpreted as a new element
|
||||||
|
//in the QStringList. This works fine until someone enters something with a space.
|
||||||
|
//Since we can't preencode those elements, we join all as a string and use a delimiter
|
||||||
|
//that does not exist in file and URL paths. I decided on the ol' reliable ','.
|
||||||
|
QString l_argv_string = argv.join(" ");
|
||||||
|
QStringList l_argv = l_argv_string.split(",");
|
||||||
|
|
||||||
|
bool l_success = false;
|
||||||
|
if (l_argv.size() == 1) {
|
||||||
|
QString l_song_name = l_argv.value(0);
|
||||||
|
l_success = m_music_manager->addCustomSong(l_song_name, l_song_name, 0, m_current_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_argv.size() == 2) {
|
||||||
|
QString l_song_name = l_argv.value(0);
|
||||||
|
QString l_true_name = l_argv.value(1);
|
||||||
|
l_success = m_music_manager->addCustomSong(l_song_name, l_true_name, 0, m_current_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_argv.size() == 3) {
|
||||||
|
QString l_song_name = l_argv.value(0);
|
||||||
|
QString l_true_name = l_argv.value(1);
|
||||||
|
bool ok;
|
||||||
|
int l_song_duration = l_argv.value(2).toInt(&ok);
|
||||||
|
if (!ok)
|
||||||
|
l_song_duration = 0;
|
||||||
|
l_success = m_music_manager->addCustomSong(l_song_name, l_true_name, l_song_duration, m_current_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_argv.size() >= 4) {
|
||||||
|
sendServerMessage("Too many arguments. Addition of song has failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString l_message = l_success ? "succeeded." : "failed.";
|
||||||
|
sendServerMessage("The addition of the song has " + l_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdAddCategory(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
Q_UNUSED(argc);
|
||||||
|
bool l_success = m_music_manager->addCustomCategory(argv.join(" "), m_current_area);
|
||||||
|
QString l_message = l_success ? "succeeded." : "failed.";
|
||||||
|
sendServerMessage("The addition of the category has " + l_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdRemoveCategorySong(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
Q_UNUSED(argc);
|
||||||
|
bool l_success = m_music_manager->removeCategorySong(argv.join(" "), m_current_area);
|
||||||
|
QString l_message = l_success ? "succeeded." : "failed.";
|
||||||
|
sendServerMessage("The removal of the entry has " + l_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdToggleRootlist(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
Q_UNUSED(argc);
|
||||||
|
Q_UNUSED(argv);
|
||||||
|
bool l_status = m_music_manager->toggleRootEnabled(m_current_area);
|
||||||
|
QString l_message = (l_status) ? "enabled." : "disabled.";
|
||||||
|
sendServerMessage("Global musiclist has been " + l_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdClearCustom(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
Q_UNUSED(argc);
|
||||||
|
Q_UNUSED(argv);
|
||||||
|
m_music_manager->clearCustomList(m_current_area);
|
||||||
|
sendServerMessage("Custom songs have been cleared.");
|
||||||
|
}
|
||||||
|
@ -25,8 +25,9 @@ QSettings* ConfigManager::m_areas = new QSettings("config/areas.ini", QSettings:
|
|||||||
QSettings* ConfigManager::m_logtext = new QSettings("config/text/logtext.ini", QSettings::IniFormat);
|
QSettings* ConfigManager::m_logtext = new QSettings("config/text/logtext.ini", QSettings::IniFormat);
|
||||||
ConfigManager::CommandSettings* ConfigManager::m_commands = new CommandSettings();
|
ConfigManager::CommandSettings* ConfigManager::m_commands = new CommandSettings();
|
||||||
QElapsedTimer* ConfigManager::m_uptimeTimer = new QElapsedTimer;
|
QElapsedTimer* ConfigManager::m_uptimeTimer = new QElapsedTimer;
|
||||||
QHash<QString,QPair<QString,float>>* ConfigManager::m_musicList = new QHash<QString,QPair<QString,float>>;
|
MusicList* ConfigManager::m_musicList = new MusicList;
|
||||||
QHash<QString,ConfigManager::help>* ConfigManager::m_commands_help = new QHash<QString,ConfigManager::help>;
|
QHash<QString,ConfigManager::help>* ConfigManager::m_commands_help = new QHash<QString,ConfigManager::help>;
|
||||||
|
QStringList* ConfigManager::m_ordered_list = new QStringList;
|
||||||
|
|
||||||
bool ConfigManager::verifyServerConfig()
|
bool ConfigManager::verifyServerConfig()
|
||||||
{
|
{
|
||||||
@ -42,7 +43,7 @@ bool ConfigManager::verifyServerConfig()
|
|||||||
// Verify config files
|
// Verify config files
|
||||||
QStringList l_config_files{"config/config.ini", "config/areas.ini", "config/backgrounds.txt", "config/characters.txt", "config/music.json",
|
QStringList l_config_files{"config/config.ini", "config/areas.ini", "config/backgrounds.txt", "config/characters.txt", "config/music.json",
|
||||||
"config/discord.ini", "config/text/8ball.txt", "config/text/gimp.txt", "config/text/praise.txt",
|
"config/discord.ini", "config/text/8ball.txt", "config/text/gimp.txt", "config/text/praise.txt",
|
||||||
"config/text/reprimands.txt","config/text/commandhelp.json"};
|
"config/text/reprimands.txt","config/text/commandhelp.json","config/text/cdns.txt"};
|
||||||
for (const QString &l_file : l_config_files) {
|
for (const QString &l_file : l_config_files) {
|
||||||
if (!fileExists(QFileInfo(l_file))) {
|
if (!fileExists(QFileInfo(l_file))) {
|
||||||
qCritical() << l_file + " does not exist!";
|
qCritical() << l_file + " does not exist!";
|
||||||
@ -92,6 +93,7 @@ bool ConfigManager::verifyServerConfig()
|
|||||||
m_commands->praises = (loadConfigFile("praise"));
|
m_commands->praises = (loadConfigFile("praise"));
|
||||||
m_commands->reprimands = (loadConfigFile("reprimands"));
|
m_commands->reprimands = (loadConfigFile("reprimands"));
|
||||||
m_commands->gimps = (loadConfigFile("gimp"));
|
m_commands->gimps = (loadConfigFile("gimp"));
|
||||||
|
m_commands->cdns = (loadConfigFile("cdns"));
|
||||||
|
|
||||||
m_uptimeTimer->start();
|
m_uptimeTimer->start();
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ QStringList ConfigManager::backgrounds()
|
|||||||
return l_backgrounds;
|
return l_backgrounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ConfigManager::musiclist()
|
MusicList ConfigManager::musiclist()
|
||||||
{
|
{
|
||||||
QFile l_music_json("config/music.json");
|
QFile l_music_json("config/music.json");
|
||||||
l_music_json.open(QIODevice::ReadOnly | QIODevice::Text);
|
l_music_json.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||||
@ -138,14 +140,13 @@ QStringList ConfigManager::musiclist()
|
|||||||
QJsonDocument l_music_list_json = QJsonDocument::fromJson(l_music_json.readAll(), &l_error);
|
QJsonDocument l_music_list_json = QJsonDocument::fromJson(l_music_json.readAll(), &l_error);
|
||||||
if (!(l_error.error == QJsonParseError::NoError)) { //Non-Terminating error.
|
if (!(l_error.error == QJsonParseError::NoError)) { //Non-Terminating error.
|
||||||
qWarning() << "Unable to load musiclist. The following error was encounted : " + l_error.errorString();
|
qWarning() << "Unable to load musiclist. The following error was encounted : " + l_error.errorString();
|
||||||
return QStringList {}; //Server can still run without music.
|
return QMap<QString,QPair<QString,int>>{}; //Server can still run without music.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Akashi expects the musiclist to be contained in a JSON array, even if its only a single category.
|
// Akashi expects the musiclist to be contained in a JSON array, even if its only a single category.
|
||||||
QJsonArray l_Json_root_array = l_music_list_json.array();
|
QJsonArray l_Json_root_array = l_music_list_json.array();
|
||||||
QJsonObject l_child_obj;
|
QJsonObject l_child_obj;
|
||||||
QJsonArray l_child_array;
|
QJsonArray l_child_array;
|
||||||
QStringList l_musiclist;
|
|
||||||
for (int i = 0; i <= l_Json_root_array.size() -1; i++){ //Iterate trough entire JSON file to assemble musiclist
|
for (int i = 0; i <= l_Json_root_array.size() -1; i++){ //Iterate trough entire JSON file to assemble musiclist
|
||||||
l_child_obj = l_Json_root_array.at(i).toObject();
|
l_child_obj = l_Json_root_array.at(i).toObject();
|
||||||
|
|
||||||
@ -153,7 +154,7 @@ QStringList ConfigManager::musiclist()
|
|||||||
QString l_category_name = l_child_obj["category"].toString();
|
QString l_category_name = l_child_obj["category"].toString();
|
||||||
if (!l_category_name.isEmpty()) {
|
if (!l_category_name.isEmpty()) {
|
||||||
m_musicList->insert(l_category_name,{l_category_name,0});
|
m_musicList->insert(l_category_name,{l_category_name,0});
|
||||||
l_musiclist.append(l_category_name);
|
m_ordered_list->append(l_category_name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qWarning() << "Category name not set. This may cause the musiclist to be displayed incorrectly.";
|
qWarning() << "Category name not set. This may cause the musiclist to be displayed incorrectly.";
|
||||||
@ -167,17 +168,19 @@ QStringList ConfigManager::musiclist()
|
|||||||
if (l_real_name.isEmpty()) {
|
if (l_real_name.isEmpty()) {
|
||||||
l_real_name = l_song_name;
|
l_real_name = l_song_name;
|
||||||
}
|
}
|
||||||
float l_song_duration = l_song_obj["length"].toVariant().toFloat();
|
int l_song_duration = l_song_obj["length"].toVariant().toInt();
|
||||||
m_musicList->insert(l_song_name,{l_real_name,l_song_duration});
|
m_musicList->insert(l_song_name,{l_real_name,l_song_duration});
|
||||||
l_musiclist.append(l_song_name);
|
m_ordered_list->append(l_song_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l_music_json.close();
|
l_music_json.close();
|
||||||
|
|
||||||
if(!l_musiclist[0].contains("==")) // Add a default category if none exists
|
return *m_musicList;
|
||||||
l_musiclist.insert(0,"==Music==");
|
}
|
||||||
|
|
||||||
return l_musiclist;
|
QStringList ConfigManager::ordered_songs()
|
||||||
|
{
|
||||||
|
return *m_ordered_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigManager::loadCommandHelp()
|
void ConfigManager::loadCommandHelp()
|
||||||
@ -211,11 +214,6 @@ void ConfigManager::loadCommandHelp()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString,float> ConfigManager::songInformation(const QString &f_songName)
|
|
||||||
{
|
|
||||||
return m_musicList->value(f_songName);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSettings* ConfigManager::areaData()
|
QSettings* ConfigManager::areaData()
|
||||||
{
|
{
|
||||||
return m_areas;
|
return m_areas;
|
||||||
@ -566,6 +564,11 @@ QStringList ConfigManager::gimpList()
|
|||||||
return m_commands->gimps;
|
return m_commands->gimps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList ConfigManager::cdnList()
|
||||||
|
{
|
||||||
|
return m_commands->cdns;
|
||||||
|
}
|
||||||
|
|
||||||
bool ConfigManager::advertiseServer()
|
bool ConfigManager::advertiseServer()
|
||||||
{
|
{
|
||||||
return m_settings->value("Advertiser/advertise","true").toBool();
|
return m_settings->value("Advertiser/advertise","true").toBool();
|
||||||
|
237
core/src/music_manager.cpp
Normal file
237
core/src/music_manager.cpp
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
#include "include/music_manager.h"
|
||||||
|
|
||||||
|
MusicManager::MusicManager(QObject *parent, QStringList f_root_ordered, QStringList f_cdns, QMap<QString, QPair<QString, int>> f_root_list) :
|
||||||
|
QObject(parent),
|
||||||
|
m_root_list(f_root_list),
|
||||||
|
m_root_ordered(f_root_ordered)
|
||||||
|
{
|
||||||
|
m_custom_lists = new QHash<int,QMap<QString,QPair<QString,int>>>;
|
||||||
|
if (!f_cdns.isEmpty()) {
|
||||||
|
m_cdns = f_cdns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MusicManager::~MusicManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList MusicManager::musiclist(int f_area_id)
|
||||||
|
{
|
||||||
|
if (m_global_enabled.value(f_area_id)) {
|
||||||
|
QStringList l_combined_list = m_root_ordered;
|
||||||
|
l_combined_list.append(m_customs_ordered.value(f_area_id));
|
||||||
|
return l_combined_list;
|
||||||
|
}
|
||||||
|
return m_custom_lists->value(f_area_id).keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList MusicManager::rootMusiclist()
|
||||||
|
{
|
||||||
|
return m_root_ordered;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::registerArea(int f_area_id)
|
||||||
|
{
|
||||||
|
if(m_custom_lists->contains(f_area_id)) {
|
||||||
|
//This area is already registered. We can't add it.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_custom_lists->insert(f_area_id,{});
|
||||||
|
m_global_enabled.insert(f_area_id,true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::validateSong(QString f_song_name, QStringList f_approved_cdns)
|
||||||
|
{
|
||||||
|
QStringList l_extensions = {".opus", ".ogg", ".mp3", ".wav" };
|
||||||
|
|
||||||
|
bool l_cdn_approved = false;
|
||||||
|
//Check if URL formatted.
|
||||||
|
if (f_song_name.contains("/")) {
|
||||||
|
//Only allow HTTPS/HTTP sources.
|
||||||
|
if (f_song_name.startsWith("https://") || f_song_name.startsWith("http://")) {
|
||||||
|
for (const QString &l_cdn : qAsConst(f_approved_cdns)) {
|
||||||
|
//Iterate trough all available CDNs to find an approved match
|
||||||
|
if (f_song_name.startsWith("https://" + l_cdn + "/", Qt::CaseInsensitive)
|
||||||
|
|| f_song_name.startsWith("http://" + l_cdn + "/", Qt::CaseInsensitive)) {
|
||||||
|
l_cdn_approved = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!l_cdn_approved) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool l_suffix_found = false;;
|
||||||
|
for (const QString &suffix : qAsConst(l_extensions)) {
|
||||||
|
if (f_song_name.endsWith(suffix)){
|
||||||
|
l_suffix_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!l_suffix_found) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::addCustomSong(QString f_song_name, QString f_real_name, int f_duration, int f_area_id)
|
||||||
|
{
|
||||||
|
//Validate if simple name.
|
||||||
|
QString l_song_name = f_song_name;
|
||||||
|
if (f_song_name.split(".").size() == 1) {
|
||||||
|
l_song_name = l_song_name + ".opus";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString l_real_name = f_real_name;
|
||||||
|
if (f_real_name.split(".").size() == 1) {
|
||||||
|
l_real_name = l_real_name + ".opus";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(validateSong(l_song_name, m_cdns) && validateSong(l_real_name, m_cdns))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid conflicts by checking if it exists.
|
||||||
|
if (m_root_list.contains(l_song_name) && m_global_enabled[f_area_id]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_custom_lists->value(f_area_id).contains(f_song_name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_customs_ordered.value(f_area_id).contains(l_song_name)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There should be a way to directly insert into the QMap. Too bad!
|
||||||
|
MusicList l_custom_list = m_custom_lists->value(f_area_id);
|
||||||
|
l_custom_list.insert(l_song_name,{l_real_name,f_duration});
|
||||||
|
m_custom_lists->insert(f_area_id,l_custom_list);
|
||||||
|
m_customs_ordered.insert(f_area_id,(QStringList {m_customs_ordered.value(f_area_id)} << l_song_name));
|
||||||
|
emit sendAreaFMPacket(AOPacket("FM",musiclist(f_area_id)), f_area_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::addCustomCategory(QString f_category_name, int f_area_id)
|
||||||
|
{
|
||||||
|
if (f_category_name.split(".").size() > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString l_category_name = f_category_name;
|
||||||
|
if (!f_category_name.startsWith("==")) {
|
||||||
|
l_category_name = "==" + l_category_name + "==";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid conflicts by checking if it exists.
|
||||||
|
if (m_root_list.contains(l_category_name) && m_global_enabled.value(f_area_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_custom_lists->value(f_area_id).contains(l_category_name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString,QPair<QString,int>> l_custom_list = m_custom_lists->value(f_area_id);
|
||||||
|
l_custom_list.insert(l_category_name,{l_category_name,0});
|
||||||
|
m_custom_lists->insert(f_area_id,l_custom_list);
|
||||||
|
m_customs_ordered.insert(f_area_id,(QStringList {m_customs_ordered.value(f_area_id)} << l_category_name));
|
||||||
|
emit sendAreaFMPacket(AOPacket("FM",musiclist(f_area_id)), f_area_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::removeCategorySong(QString f_songcategory_name, int f_area_id)
|
||||||
|
{
|
||||||
|
if (!m_root_list.contains(f_songcategory_name)){
|
||||||
|
MusicList l_custom_list = m_custom_lists->value(f_area_id);
|
||||||
|
if (l_custom_list.contains(f_songcategory_name)) {
|
||||||
|
l_custom_list.remove(f_songcategory_name);
|
||||||
|
m_custom_lists->insert(f_area_id,l_custom_list);
|
||||||
|
|
||||||
|
//Updating the list alias too.
|
||||||
|
QStringList l_customs_ordered = m_customs_ordered.value(f_area_id);
|
||||||
|
l_customs_ordered.removeAll(f_songcategory_name);
|
||||||
|
m_customs_ordered.insert(f_area_id, l_customs_ordered);
|
||||||
|
|
||||||
|
emit sendAreaFMPacket(AOPacket("FM",musiclist(f_area_id)), f_area_id);
|
||||||
|
return true;
|
||||||
|
} // Fallthrough
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::toggleRootEnabled(int f_area_id)
|
||||||
|
{
|
||||||
|
m_global_enabled.insert(f_area_id, !m_global_enabled.value(f_area_id));
|
||||||
|
if (m_global_enabled.value(f_area_id)) {
|
||||||
|
sanitiseCustomList(f_area_id);
|
||||||
|
}
|
||||||
|
emit sendAreaFMPacket(AOPacket("FM",musiclist(f_area_id)), f_area_id);
|
||||||
|
return m_global_enabled.value(f_area_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicManager::sanitiseCustomList(int f_area_id)
|
||||||
|
{
|
||||||
|
MusicList l_sanitised_list;
|
||||||
|
QStringList l_sanitised_ordered = m_customs_ordered.value(f_area_id);
|
||||||
|
for (auto iterator = m_custom_lists->value(f_area_id).keyBegin(),
|
||||||
|
end = m_custom_lists->value(f_area_id).keyEnd(); iterator != end; ++iterator)
|
||||||
|
{
|
||||||
|
QString l_key = iterator.operator*();
|
||||||
|
if (!m_root_list.contains(l_key)) {
|
||||||
|
l_sanitised_list.insert(l_key, m_custom_lists->value(f_area_id).value(l_key));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
l_sanitised_ordered.removeAll(l_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
m_custom_lists->insert(f_area_id, l_sanitised_list);
|
||||||
|
m_customs_ordered.insert(f_area_id, l_sanitised_ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicManager::clearCustomList(int f_area_id)
|
||||||
|
{
|
||||||
|
m_custom_lists->remove(f_area_id);
|
||||||
|
m_custom_lists->insert(f_area_id,{});
|
||||||
|
m_customs_ordered.remove(f_area_id);
|
||||||
|
m_customs_ordered.insert(f_area_id, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QString, int> MusicManager::songInformation(QString f_song_name, int f_area_id)
|
||||||
|
{
|
||||||
|
if (m_root_list.contains(f_song_name)) {
|
||||||
|
return m_root_list.value(f_song_name);
|
||||||
|
}
|
||||||
|
return m_custom_lists->value(f_area_id).value(f_song_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicManager::isCustom(int f_area_id, QString f_song_name)
|
||||||
|
{
|
||||||
|
if (m_customs_ordered.value(f_area_id).contains(f_song_name, Qt::CaseInsensitive)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicManager::reloadRequest()
|
||||||
|
{
|
||||||
|
m_root_list = ConfigManager::musiclist();
|
||||||
|
m_root_ordered = ConfigManager::ordered_songs();
|
||||||
|
m_cdns = ConfigManager::cdnList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicManager::userJoinedArea(int f_area_index, int f_user_id)
|
||||||
|
{
|
||||||
|
emit sendFMPacket(AOPacket("FM", musiclist(f_area_index)), f_user_id);
|
||||||
|
}
|
@ -299,7 +299,7 @@ void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
// argument is a valid song
|
// argument is a valid song
|
||||||
QString l_argument = argv[0];
|
QString l_argument = argv[0];
|
||||||
|
|
||||||
if (server->m_music_list.contains(l_argument) || l_argument == "~stop.mp3") { // ~stop.mp3 is a dummy track used by 2.9+
|
if (server->m_music_list.contains(l_argument) || m_music_manager->isCustom(m_current_area, l_argument) || l_argument == "~stop.mp3") { // ~stop.mp3 is a dummy track used by 2.9+
|
||||||
// We have a song here
|
// We have a song here
|
||||||
if (m_is_dj_blocked) {
|
if (m_is_dj_blocked) {
|
||||||
sendServerMessage("You are blocked from changing the music.");
|
sendServerMessage("You are blocked from changing the music.");
|
||||||
@ -327,9 +327,8 @@ void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString,float> l_song = ConfigManager::songInformation(l_final_song);
|
QPair<QString,float> l_song = m_music_manager->songInformation(l_final_song, m_current_area);
|
||||||
QString l_real_name = l_song.first;
|
QString l_real_name = l_song.first;
|
||||||
qDebug() << l_real_name;
|
|
||||||
AOPacket l_music_change("MC", {l_real_name, argv[1], m_showname, "1", "0", l_effects});
|
AOPacket l_music_change("MC", {l_real_name, argv[1], m_showname, "1", "0", l_effects});
|
||||||
area->setCurrentMusic(l_final_song);
|
area->setCurrentMusic(l_final_song);
|
||||||
area->setMusicPlayedBy(m_showname);
|
area->setMusicPlayedBy(m_showname);
|
||||||
|
@ -81,21 +81,32 @@ void Server::start()
|
|||||||
//Get characters from config file
|
//Get characters from config file
|
||||||
m_characters = ConfigManager::charlist();
|
m_characters = ConfigManager::charlist();
|
||||||
|
|
||||||
//Get musiclist from config file
|
|
||||||
m_music_list = ConfigManager::musiclist();
|
|
||||||
|
|
||||||
//Get backgrounds from config file
|
//Get backgrounds from config file
|
||||||
m_backgrounds = ConfigManager::backgrounds();
|
m_backgrounds = ConfigManager::backgrounds();
|
||||||
|
|
||||||
|
//Build our music manager.
|
||||||
|
ConfigManager::musiclist();
|
||||||
|
music_manager = new MusicManager(this, ConfigManager::ordered_songs(), ConfigManager::cdnList());
|
||||||
|
connect(music_manager, &MusicManager::sendFMPacket,
|
||||||
|
this, &Server::unicast);
|
||||||
|
connect(music_manager, &MusicManager::sendAreaFMPacket,
|
||||||
|
this, QOverload<AOPacket,int>::of(&Server::broadcast));
|
||||||
|
|
||||||
|
//Get musiclist from config file
|
||||||
|
m_music_list = music_manager->rootMusiclist();
|
||||||
|
|
||||||
//Assembles the area list
|
//Assembles the area list
|
||||||
m_area_names = ConfigManager::sanitizedAreaNames();
|
m_area_names = ConfigManager::sanitizedAreaNames();
|
||||||
QStringList raw_area_names = ConfigManager::rawAreaNames();
|
QStringList raw_area_names = ConfigManager::rawAreaNames();
|
||||||
for (int i = 0; i < raw_area_names.length(); i++) {
|
for (int i = 0; i < raw_area_names.length(); i++) {
|
||||||
QString area_name = raw_area_names[i];
|
QString area_name = raw_area_names[i];
|
||||||
AreaData* l_area = new AreaData(area_name, i);
|
AreaData* l_area = new AreaData(area_name, i, music_manager);
|
||||||
m_areas.insert(i, l_area);
|
m_areas.insert(i, l_area);
|
||||||
connect(l_area, &AreaData::playJukeboxSong,
|
connect(l_area, &AreaData::sendAreaPacket,
|
||||||
this, QOverload<AOPacket,int>::of(&Server::broadcast));
|
this, QOverload<AOPacket,int>::of(&Server::broadcast));
|
||||||
|
connect(l_area, &AreaData::userJoinedArea,
|
||||||
|
music_manager, &MusicManager::userJoinedArea);
|
||||||
|
music_manager->registerArea(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Loads the command help information. This is not stored inside the server.
|
//Loads the command help information. This is not stored inside the server.
|
||||||
@ -130,7 +141,7 @@ void Server::clientConnected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int user_id = m_available_ids.dequeue();
|
int user_id = m_available_ids.dequeue();
|
||||||
AOClient* client = new AOClient(this, socket, this, user_id);
|
AOClient* client = new AOClient(this, socket, this, user_id, music_manager);
|
||||||
m_clients_ids.insert(user_id, client);
|
m_clients_ids.insert(user_id, client);
|
||||||
|
|
||||||
int multiclient_count = 1;
|
int multiclient_count = 1;
|
||||||
@ -247,7 +258,6 @@ void Server::reloadSettings()
|
|||||||
emit updateHTTPConfiguration();
|
emit updateHTTPConfiguration();
|
||||||
handleDiscordIntegration();
|
handleDiscordIntegration();
|
||||||
logger->loadLogtext();
|
logger->loadLogtext();
|
||||||
m_music_list = ConfigManager::musiclist();
|
|
||||||
m_ipban_list = ConfigManager::iprangeBans();
|
m_ipban_list = ConfigManager::iprangeBans();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +314,15 @@ void Server::broadcast(AOPacket packet, AOPacket other_packet, TARGET_TYPE targe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Server::unicast(AOPacket f_packet, int f_client_id)
|
||||||
|
{
|
||||||
|
AOClient* l_client = getClientByID(f_client_id);
|
||||||
|
if (l_client != nullptr) { // This should never happen, but safety first.
|
||||||
|
l_client->sendPacket(f_packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QList<AOClient*> Server::getClientsByIpid(QString ipid)
|
QList<AOClient*> Server::getClientsByIpid(QString ipid)
|
||||||
{
|
{
|
||||||
QList<AOClient*> return_clients;
|
QList<AOClient*> return_clients;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
TEMPLATE = subdirs
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
unittest_area
|
unittest_area \
|
||||||
|
unittest_music_manager
|
||||||
|
@ -66,7 +66,7 @@ private slots:
|
|||||||
|
|
||||||
void Area::init()
|
void Area::init()
|
||||||
{
|
{
|
||||||
m_area = new AreaData("Test Area", 0);
|
m_area = new AreaData("Test Area", 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Area::cleanup()
|
void Area::cleanup()
|
||||||
|
322
tests/unittest_music_manager/tst_unittest_music_manager.cpp
Normal file
322
tests/unittest_music_manager/tst_unittest_music_manager.cpp
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#include <QTest>
|
||||||
|
|
||||||
|
#include <include/music_manager.h>
|
||||||
|
|
||||||
|
namespace tests {
|
||||||
|
namespace unittests {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unit Tester class for the musiclist-related functions.
|
||||||
|
*/
|
||||||
|
class MusicListManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public :
|
||||||
|
|
||||||
|
MusicManager* m_music_manager;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* @brief Initialises every tests with creating a new MusicManager with a small sample root list.
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests the registration of areas in the music manager.
|
||||||
|
*/
|
||||||
|
void registerArea();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests toggling the enabling/disabling of the prepend behaviour of our root list.
|
||||||
|
*/
|
||||||
|
void toggleRootEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The data function for validateSong()
|
||||||
|
*/
|
||||||
|
void validateSong_data();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests validation of song candidates.
|
||||||
|
*/
|
||||||
|
void validateSong();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests the addition of custom music.
|
||||||
|
*/
|
||||||
|
void addCustomSong();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests the addition of a custom category.
|
||||||
|
*/
|
||||||
|
void addCustomCategory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test the sanitisation of the custom list when root prepend is reenabled.
|
||||||
|
*/
|
||||||
|
void sanitiseCustomList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests the removing of custom songs and categories.
|
||||||
|
*/
|
||||||
|
void removeCategorySong();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests the retrieval of song information.
|
||||||
|
*/
|
||||||
|
void songInformation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tests the retrieval of the full musiclist for an area.
|
||||||
|
*/
|
||||||
|
void musiclist();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void MusicListManager::init()
|
||||||
|
{
|
||||||
|
QMap<QString,QPair<QString,int>> l_test_list;
|
||||||
|
l_test_list.insert("==Music==",{"==Music==",0});
|
||||||
|
l_test_list.insert("Announce The Truth (AJ).opus",{"Announce The Truth (AJ).opus",59});
|
||||||
|
l_test_list.insert("Announce The Truth (JFA).opus",{"Announce The Truth (JFA).opus",98});
|
||||||
|
|
||||||
|
QStringList l_list = {};
|
||||||
|
l_list << "==Music==" << "Announce The Truth (AJ).opus" << "Announce The Truth (JFA).opus";
|
||||||
|
|
||||||
|
m_music_manager = new MusicManager(nullptr, l_list ,{"my.cdn.com","your.cdn.com"}, l_test_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::registerArea()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//We register a single area with the music manager of ID 0.
|
||||||
|
//Creation should work as there are no other areas yet.
|
||||||
|
bool l_creation_success = m_music_manager->registerArea(0);
|
||||||
|
QCOMPARE(l_creation_success,true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Someone tries to register the same area again!
|
||||||
|
//This should fail as this area already exists.
|
||||||
|
bool l_creation_success = m_music_manager->registerArea(0);
|
||||||
|
QCOMPARE(l_creation_success,false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::toggleRootEnabled()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//We register an area of ID0 and toggle the inclusion of global list.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
QCOMPARE(m_music_manager->toggleRootEnabled(0), false);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//We toggle it again. It should return true now.
|
||||||
|
//Since this is now true, we should have the root list with customs cleared.
|
||||||
|
QCOMPARE(m_music_manager->toggleRootEnabled(0), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::validateSong_data()
|
||||||
|
{
|
||||||
|
//Songname can also be the realname.
|
||||||
|
QTest::addColumn<QString>("songname");
|
||||||
|
QTest::addColumn<bool>("expectedResult");
|
||||||
|
|
||||||
|
QTest::addRow("Songname - No extension") << "Announce The Truth (AA)" << false;
|
||||||
|
QTest::addRow("Songname - Valid Extension") << "Announce The Truth (AA).opus" << true;
|
||||||
|
QTest::addRow("Songname - Invalid Extension") << "Announce The Truth (AA).aac" << false;
|
||||||
|
QTest::addRow("URL - Valid primary") << "https://my.cdn.com/mysong.opus" << true;
|
||||||
|
QTest::addRow("URL - Valid secondary") << "https://your.cdn.com/mysong.opus" << true;
|
||||||
|
QTest::addRow("URL - Invalid extension") << "https://my.cdn.com/mysong.aac." << false;
|
||||||
|
QTest::addRow("URL - Invalid prefix") << "ftp://my.cdn.com/mysong.opus" << false;
|
||||||
|
QTest::addRow("URL - Invalid missing prefix") << "my.cdn.com/mysong.opus" << false;
|
||||||
|
QTest::addRow("URL - Invalid CDN") << "https://myipgrabber.com/mysong.opus" << false;
|
||||||
|
QTest::addRow("URL - Subdomain Attack") << "https://my.cdn.com.fakedomain.com/mysong.opus" << false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::validateSong()
|
||||||
|
{
|
||||||
|
QFETCH(QString,songname);
|
||||||
|
QFETCH(bool,expectedResult);
|
||||||
|
|
||||||
|
bool l_result = m_music_manager->validateSong(songname, {"my.cdn.com","your.cdn.com"});
|
||||||
|
QCOMPARE(expectedResult,l_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::addCustomSong()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//Dummy register.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
|
||||||
|
//No custom songs, so musiclist = root_list.size()
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Add a song that's valid. The musiclist is now root_list.size() + custom_list.size()
|
||||||
|
m_music_manager->addCustomSong("mysong","mysong.opus",0,0);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Add a song that's part of the root list. This should fail and not increase the size.
|
||||||
|
bool l_result = m_music_manager->addCustomSong("Announce The Truth (AJ)","Announce The Truth (AJ).opus",0,0);
|
||||||
|
QCOMPARE(l_result,false);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Disable the root list. Musiclist is now custom_list.size()
|
||||||
|
m_music_manager->toggleRootEnabled(0);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Add an item that is in the root list into the custom list. Size is still custom_list.size()
|
||||||
|
bool l_result = m_music_manager->addCustomSong("Announce The Truth (AJ)","Announce The Truth (AJ).opus",0,0);
|
||||||
|
QCOMPARE(l_result,true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
bool l_result = m_music_manager->addCustomSong("Announce The Truth (AJ)2","https://my.cdn.com/mysong.opus",0,0);
|
||||||
|
QCOMPARE(l_result,true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::addCustomCategory()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//Dummy register.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
|
||||||
|
//Add category to the custom list. Category marker are added manually.
|
||||||
|
bool l_result = m_music_manager->addCustomCategory("Music2",0);
|
||||||
|
QCOMPARE(l_result,true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 4);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).at(3), "==Music2==");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Add a category that already exists on root. This should fail and not increase the size of our list.
|
||||||
|
bool l_result = m_music_manager->addCustomCategory("Music",0);
|
||||||
|
QCOMPARE(l_result, false);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//We disable the root list. We now insert the category again.
|
||||||
|
m_music_manager->toggleRootEnabled(0);
|
||||||
|
bool l_result = m_music_manager->addCustomCategory("Music",0);
|
||||||
|
QCOMPARE(l_result, true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 2);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).at(1), "==Music==");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Global now enabled. We add a song with three ===.
|
||||||
|
m_music_manager->toggleRootEnabled(0);
|
||||||
|
bool l_result = m_music_manager->addCustomCategory("===Music===",0);
|
||||||
|
QCOMPARE(l_result, true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 5);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).at(4), "===Music===");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::sanitiseCustomList()
|
||||||
|
{
|
||||||
|
//Prepare a dummy area with root list disabled.Insert both non-root and root elements.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
m_music_manager->toggleRootEnabled(0);
|
||||||
|
m_music_manager->addCustomCategory("Music",0);
|
||||||
|
m_music_manager->addCustomCategory("Music2",0);
|
||||||
|
m_music_manager->addCustomSong("Announce The Truth (AJ)","Announce The Truth (AJ).opus",0,0);
|
||||||
|
m_music_manager->addCustomSong("mysong","mysong.opus",0,0);
|
||||||
|
|
||||||
|
//We now only have custom elements.
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 4);
|
||||||
|
|
||||||
|
//We reenable the root list. Sanisation should only leave the non-root elements in the custom list.
|
||||||
|
m_music_manager->toggleRootEnabled(0);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 5);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).at(3), "==Music2==");
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).at(4), "mysong.opus");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::removeCategorySong()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//Prepare dummy area. Add both custom songs and categories.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
m_music_manager->addCustomCategory("Music2",0);
|
||||||
|
m_music_manager->addCustomSong("mysong","mysong.opus",0,0);
|
||||||
|
m_music_manager->addCustomCategory("Music3",0);
|
||||||
|
m_music_manager->addCustomSong("mysong2","mysong.opus",0,0);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Delete a category that is not custom. This should fail.
|
||||||
|
bool l_success = m_music_manager->removeCategorySong("==Music==",0);
|
||||||
|
QCOMPARE(l_success, false);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Correct category name, wrong format.
|
||||||
|
bool l_success = m_music_manager->removeCategorySong("Music2",0);
|
||||||
|
QCOMPARE(l_success, false);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Correct category name. This should be removed.
|
||||||
|
bool l_success = m_music_manager->removeCategorySong("==Music2==",0);
|
||||||
|
QCOMPARE(l_success, true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 6);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Correct song name. This should be removed. This needs to be with the extension.
|
||||||
|
bool l_success = m_music_manager->removeCategorySong("mysong2.opus",0);
|
||||||
|
QCOMPARE(l_success, true);
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::songInformation()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//Prepare dummy area. Add both custom songs and categories.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
m_music_manager->addCustomCategory("Music2",0);
|
||||||
|
m_music_manager->addCustomSong("mysong","realmysong.opus",47,0);
|
||||||
|
m_music_manager->addCustomCategory("Music3",0);
|
||||||
|
m_music_manager->addCustomSong("mysong2","mysong.opus",42,0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QPair<QString,int> l_song_information = m_music_manager->songInformation("mysong.opus",0);
|
||||||
|
QCOMPARE(l_song_information.first, "realmysong.opus");
|
||||||
|
QCOMPARE(l_song_information.second, 47);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QPair<QString,int> l_song_information = m_music_manager->songInformation("Announce The Truth (AJ).opus",0);
|
||||||
|
QCOMPARE(l_song_information.first, "Announce The Truth (AJ).opus");
|
||||||
|
QCOMPARE(l_song_information.second, 59);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicListManager::musiclist()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//Prepare dummy area. Add both custom songs and categories.
|
||||||
|
m_music_manager->registerArea(0);
|
||||||
|
m_music_manager->addCustomCategory("Music2",0);
|
||||||
|
m_music_manager->addCustomSong("mysong","realmysong.opus",47,0);
|
||||||
|
m_music_manager->addCustomCategory("Music3",0);
|
||||||
|
m_music_manager->addCustomSong("mysong2","mysong.opus",42,0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QCOMPARE(m_music_manager->musiclist(0).size(), 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_APPLESS_MAIN(tests::unittests::MusicListManager)
|
||||||
|
|
||||||
|
#include "tst_unittest_music_manager.moc"
|
5
tests/unittest_music_manager/unittest_music_manager.pro
Normal file
5
tests/unittest_music_manager/unittest_music_manager.pro
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
QT -= gui
|
||||||
|
|
||||||
|
include(../tests_common.pri)
|
||||||
|
|
||||||
|
SOURCES += tst_unittest_music_manager.cpp
|
Loading…
Reference in New Issue
Block a user