2017-12-31 00:50:07 +01:00
|
|
|
#include "singletons/commandmanager.hpp"
|
2018-01-05 02:38:00 +01:00
|
|
|
#include "debug/log.hpp"
|
2018-02-06 00:31:30 +01:00
|
|
|
#include "messages/messagebuilder.hpp"
|
|
|
|
#include "providers/twitch/twitchserver.hpp"
|
|
|
|
#include "singletons/accountmanager.hpp"
|
2018-01-05 02:38:00 +01:00
|
|
|
#include "singletons/pathmanager.hpp"
|
2017-12-27 19:50:05 +01:00
|
|
|
|
2018-04-09 22:59:19 +02:00
|
|
|
#include <QApplication>
|
2018-01-04 02:50:36 +01:00
|
|
|
#include <QFile>
|
2017-12-27 19:50:05 +01:00
|
|
|
#include <QRegularExpression>
|
2017-11-12 17:21:50 +01:00
|
|
|
|
2018-01-05 02:05:59 +01:00
|
|
|
#include "channel.hpp"
|
2018-02-05 15:11:50 +01:00
|
|
|
#include "providers/twitch/twitchchannel.hpp"
|
|
|
|
|
|
|
|
using namespace chatterino::providers::twitch;
|
2018-01-05 02:05:59 +01:00
|
|
|
|
2017-11-12 17:21:50 +01:00
|
|
|
namespace chatterino {
|
2017-12-31 22:58:35 +01:00
|
|
|
namespace singletons {
|
2018-01-05 02:38:00 +01:00
|
|
|
|
2017-12-31 00:50:07 +01:00
|
|
|
CommandManager &CommandManager::getInstance()
|
|
|
|
{
|
|
|
|
static CommandManager instance;
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2018-01-04 02:50:36 +01:00
|
|
|
void CommandManager::loadCommands()
|
|
|
|
{
|
2018-01-05 02:38:00 +01:00
|
|
|
this->filePath = PathManager::getInstance().customFolderPath + "/Commands.txt";
|
|
|
|
|
|
|
|
QFile textFile(this->filePath);
|
|
|
|
if (!textFile.open(QIODevice::ReadOnly)) {
|
|
|
|
// No commands file created yet
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QByteArray> test = textFile.readAll().split('\n');
|
|
|
|
|
|
|
|
QStringList loadedCommands;
|
|
|
|
|
|
|
|
for (const auto &command : test) {
|
|
|
|
loadedCommands.append(command);
|
|
|
|
}
|
2018-01-04 02:50:36 +01:00
|
|
|
|
2018-01-05 02:38:00 +01:00
|
|
|
this->setCommands(loadedCommands);
|
|
|
|
|
|
|
|
textFile.close();
|
2018-01-04 02:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommandManager::saveCommands()
|
|
|
|
{
|
2018-01-05 02:38:00 +01:00
|
|
|
QFile textFile(this->filePath);
|
|
|
|
if (!textFile.open(QIODevice::WriteOnly)) {
|
|
|
|
debug::Log("[CommandManager::saveCommands] Unable to open {} for writing", this->filePath);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString commandsString = this->commandsStringList.join('\n');
|
|
|
|
|
|
|
|
textFile.write(commandsString.toUtf8());
|
|
|
|
|
|
|
|
textFile.close();
|
2018-01-04 02:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommandManager::setCommands(const QStringList &_commands)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(this->mutex);
|
|
|
|
|
|
|
|
this->commands.clear();
|
|
|
|
|
|
|
|
for (const QString &commandRef : _commands) {
|
|
|
|
QString command = commandRef;
|
|
|
|
|
|
|
|
if (command.size() == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-04 04:03:51 +01:00
|
|
|
// if (command.at(0) != '/') {
|
|
|
|
// command = QString("/") + command;
|
|
|
|
// }
|
2018-01-04 02:50:36 +01:00
|
|
|
|
|
|
|
QString commandName = command.mid(0, command.indexOf(' '));
|
|
|
|
|
|
|
|
if (this->commands.find(commandName) == this->commands.end()) {
|
|
|
|
this->commands.insert(commandName, Command(command));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this->commandsStringList = _commands;
|
|
|
|
this->commandsStringList.detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList CommandManager::getCommands()
|
|
|
|
{
|
|
|
|
return this->commandsStringList;
|
|
|
|
}
|
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
QString CommandManager::execCommand(const QString &text, ChannelPtr channel, bool dryRun)
|
2018-01-04 02:50:36 +01:00
|
|
|
{
|
|
|
|
QStringList words = text.split(' ', QString::SkipEmptyParts);
|
2018-01-05 02:05:59 +01:00
|
|
|
Command command;
|
2018-01-04 02:50:36 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(this->mutex);
|
|
|
|
|
|
|
|
if (words.length() == 0) {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString commandName = words[0];
|
|
|
|
|
2018-01-05 02:05:59 +01:00
|
|
|
// check if default command exists
|
2018-02-05 15:11:50 +01:00
|
|
|
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
2018-01-05 02:05:59 +01:00
|
|
|
|
|
|
|
if (!dryRun && twitchChannel != nullptr) {
|
2018-04-09 22:59:19 +02:00
|
|
|
if (commandName == "/debug-args") {
|
|
|
|
QString msg = QApplication::instance()->arguments().join(' ');
|
|
|
|
|
|
|
|
channel->addMessage(messages::Message::createSystemMessage(msg));
|
|
|
|
|
|
|
|
return "";
|
|
|
|
} else if (commandName == "/uptime") {
|
2018-03-30 15:05:33 +02:00
|
|
|
const auto &streamStatus = twitchChannel->GetStreamStatus();
|
|
|
|
|
2018-01-05 02:05:59 +01:00
|
|
|
QString messageText =
|
2018-03-30 15:05:33 +02:00
|
|
|
streamStatus.live ? streamStatus.uptime : "Channel is not live.";
|
2018-01-11 20:16:25 +01:00
|
|
|
|
|
|
|
channel->addMessage(messages::Message::createSystemMessage(messageText));
|
2018-01-05 02:05:59 +01:00
|
|
|
|
|
|
|
return "";
|
|
|
|
} else if (commandName == "/ignore" && words.size() >= 2) {
|
2018-02-05 15:11:50 +01:00
|
|
|
// fourtf: ignore user
|
|
|
|
// QString messageText;
|
2018-01-05 02:05:59 +01:00
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
// if (IrcManager::getInstance().tryAddIgnoredUser(words.at(1),
|
|
|
|
// messageText)) {
|
|
|
|
// messageText = "Ignored user \"" + words.at(1) + "\".";
|
|
|
|
// }
|
2018-01-05 02:05:59 +01:00
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
// channel->addMessage(messages::Message::createSystemMessage(messageText));
|
2018-01-05 02:05:59 +01:00
|
|
|
return "";
|
|
|
|
} else if (commandName == "/unignore") {
|
2018-02-05 15:11:50 +01:00
|
|
|
// fourtf: ignore user
|
|
|
|
// QString messageText;
|
2018-01-05 02:05:59 +01:00
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
// if (IrcManager::getInstance().tryRemoveIgnoredUser(words.at(1),
|
|
|
|
// messageText)) {
|
|
|
|
// messageText = "Ignored user \"" + words.at(1) + "\".";
|
|
|
|
// }
|
2018-01-05 02:05:59 +01:00
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
// channel->addMessage(messages::Message::createSystemMessage(messageText));
|
2018-01-05 02:05:59 +01:00
|
|
|
return "";
|
2018-02-06 00:31:30 +01:00
|
|
|
} else if (commandName == "/w") {
|
|
|
|
if (words.length() <= 2) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
messages::MessageBuilder b;
|
|
|
|
|
|
|
|
b.emplace<messages::TextElement>(
|
|
|
|
singletons::AccountManager::getInstance().Twitch.getCurrent()->getUserName(),
|
|
|
|
messages::MessageElement::Text);
|
|
|
|
b.emplace<messages::TextElement>("->", messages::MessageElement::Text);
|
|
|
|
b.emplace<messages::TextElement>(words[1], messages::MessageElement::Text);
|
|
|
|
|
|
|
|
QString rest = "";
|
|
|
|
|
|
|
|
for (int i = 2; i < words.length(); i++) {
|
|
|
|
rest += words[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
b.emplace<messages::TextElement>(rest, messages::MessageElement::Text);
|
|
|
|
|
|
|
|
TwitchServer::getInstance().whispersChannel->addMessage(b.getMessage());
|
2018-01-05 02:05:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if custom command exists
|
2018-01-04 02:50:36 +01:00
|
|
|
auto it = this->commands.find(commandName);
|
|
|
|
|
|
|
|
if (it == this->commands.end()) {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
command = it.value();
|
|
|
|
}
|
|
|
|
|
2018-01-05 02:05:59 +01:00
|
|
|
return this->execCustomCommand(words, command);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString CommandManager::execCustomCommand(const QStringList &words, const Command &command)
|
|
|
|
{
|
2018-01-04 02:50:36 +01:00
|
|
|
QString result;
|
|
|
|
|
|
|
|
static QRegularExpression parseCommand("(^|[^{])({{)*{(\\d+\\+?)}");
|
|
|
|
|
|
|
|
int lastCaptureEnd = 0;
|
|
|
|
|
|
|
|
auto globalMatch = parseCommand.globalMatch(command.text);
|
|
|
|
int matchOffset = 0;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
QRegularExpressionMatch match = parseCommand.match(command.text, matchOffset);
|
|
|
|
|
|
|
|
if (!match.hasMatch()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
result += command.text.mid(lastCaptureEnd, match.capturedStart() - lastCaptureEnd + 1);
|
|
|
|
|
|
|
|
lastCaptureEnd = match.capturedEnd();
|
|
|
|
matchOffset = lastCaptureEnd - 1;
|
|
|
|
|
|
|
|
QString wordIndexMatch = match.captured(3);
|
|
|
|
|
|
|
|
bool plus = wordIndexMatch.at(wordIndexMatch.size() - 1) == '+';
|
|
|
|
wordIndexMatch = wordIndexMatch.replace("+", "");
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
int wordIndex = wordIndexMatch.replace("=", "").toInt(&ok);
|
|
|
|
if (!ok || wordIndex == 0) {
|
|
|
|
result += "{" + match.captured(3) + "}";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (words.length() <= wordIndex) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (plus) {
|
|
|
|
bool first = true;
|
|
|
|
for (int i = wordIndex; i < words.length(); i++) {
|
|
|
|
if (!first) {
|
|
|
|
result += " ";
|
|
|
|
}
|
|
|
|
result += words[i];
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result += words[wordIndex];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result += command.text.mid(lastCaptureEnd);
|
|
|
|
|
|
|
|
if (result.size() > 0 && result.at(0) == '{') {
|
|
|
|
result = result.mid(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result.replace("{{", "{");
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandManager::Command::Command(QString _text)
|
|
|
|
{
|
|
|
|
int index = _text.indexOf(' ');
|
|
|
|
|
|
|
|
if (index == -1) {
|
|
|
|
this->name == _text;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->name = _text.mid(0, index);
|
|
|
|
this->text = _text.mid(index + 1);
|
|
|
|
}
|
2018-01-05 02:05:38 +01:00
|
|
|
|
|
|
|
} // namespace singletons
|
|
|
|
} // namespace chatterino
|