mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Move ChatSettings commands to their own file (#4116)
* Move ChatSettings commands to their own file * reformat error message strings * move ChatCommands together in CommandController.cpp * Allow CommandContext to be provided for builtin functions using variants MEGADANK * add missing include * rename to ComandFunctionVariants also include some move magic & const reffing
This commit is contained in:
parent
ac7baf4073
commit
c6a162c7ff
6 changed files with 526 additions and 469 deletions
|
@ -59,10 +59,13 @@ set(SOURCE_FILES
|
||||||
controllers/accounts/AccountModel.cpp
|
controllers/accounts/AccountModel.cpp
|
||||||
controllers/accounts/AccountModel.hpp
|
controllers/accounts/AccountModel.hpp
|
||||||
|
|
||||||
controllers/commands/Command.cpp
|
controllers/commands/builtin/twitch/ChatSettings.cpp
|
||||||
controllers/commands/Command.hpp
|
controllers/commands/builtin/twitch/ChatSettings.hpp
|
||||||
|
controllers/commands/CommandContext.hpp
|
||||||
controllers/commands/CommandController.cpp
|
controllers/commands/CommandController.cpp
|
||||||
controllers/commands/CommandController.hpp
|
controllers/commands/CommandController.hpp
|
||||||
|
controllers/commands/Command.cpp
|
||||||
|
controllers/commands/Command.hpp
|
||||||
controllers/commands/CommandModel.cpp
|
controllers/commands/CommandModel.cpp
|
||||||
controllers/commands/CommandModel.hpp
|
controllers/commands/CommandModel.hpp
|
||||||
|
|
||||||
|
|
20
src/controllers/commands/CommandContext.hpp
Normal file
20
src/controllers/commands/CommandContext.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Channel.hpp"
|
||||||
|
#include "providers/twitch/TwitchChannel.hpp"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
struct CommandContext {
|
||||||
|
QStringList words;
|
||||||
|
|
||||||
|
// Can be null
|
||||||
|
ChannelPtr channel;
|
||||||
|
|
||||||
|
// Can be null if `channel` is null or if `channel` is not a Twitch channel
|
||||||
|
TwitchChannel *twitchChannel;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
|
@ -7,6 +7,7 @@
|
||||||
#include "controllers/accounts/AccountController.hpp"
|
#include "controllers/accounts/AccountController.hpp"
|
||||||
#include "controllers/commands/Command.hpp"
|
#include "controllers/commands/Command.hpp"
|
||||||
#include "controllers/commands/CommandModel.hpp"
|
#include "controllers/commands/CommandModel.hpp"
|
||||||
|
#include "controllers/commands/builtin/twitch/ChatSettings.hpp"
|
||||||
#include "messages/Message.hpp"
|
#include "messages/Message.hpp"
|
||||||
#include "messages/MessageBuilder.hpp"
|
#include "messages/MessageBuilder.hpp"
|
||||||
#include "messages/MessageElement.hpp"
|
#include "messages/MessageElement.hpp"
|
||||||
|
@ -2557,409 +2558,22 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
return "";
|
return "";
|
||||||
}); // unraid
|
}); // unraid
|
||||||
|
|
||||||
const auto formatChatSettingsError = [](const HelixUpdateChatSettingsError
|
this->registerCommand("/emoteonly", &commands::emoteOnly);
|
||||||
error,
|
this->registerCommand("/emoteonlyoff", &commands::emoteOnlyOff);
|
||||||
const QString &message,
|
|
||||||
int durationUnitMultiplier = 1) {
|
|
||||||
static const QRegularExpression invalidRange("(\\d+) through (\\d+)");
|
|
||||||
|
|
||||||
QString errorMessage = QString("Failed to update - ");
|
this->registerCommand("/subscribers", &commands::subscribers);
|
||||||
using Error = HelixUpdateChatSettingsError;
|
this->registerCommand("/subscribersoff", &commands::subscribersOff);
|
||||||
switch (error)
|
|
||||||
{
|
|
||||||
case Error::UserMissingScope: {
|
|
||||||
// TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE
|
|
||||||
errorMessage += "Missing required scope. "
|
|
||||||
"Re-login with your "
|
|
||||||
"account and try again.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Error::UserNotAuthorized:
|
this->registerCommand("/slow", &commands::slow);
|
||||||
case Error::Forbidden: {
|
this->registerCommand("/slowoff", &commands::slowOff);
|
||||||
// TODO(pajlada): Phrase MISSING_PERMISSION
|
|
||||||
errorMessage += "You don't have permission to "
|
|
||||||
"perform that action.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Error::Ratelimited: {
|
this->registerCommand("/followers", &commands::followers);
|
||||||
errorMessage += "You are being ratelimited by Twitch. Try "
|
this->registerCommand("/followersoff", &commands::followersOff);
|
||||||
"again in a few seconds.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Error::OutOfRange: {
|
this->registerCommand("/uniquechat", &commands::uniqueChat);
|
||||||
QRegularExpressionMatch matched = invalidRange.match(message);
|
this->registerCommand("/r9kbeta", &commands::uniqueChat);
|
||||||
if (matched.hasMatch())
|
this->registerCommand("/uniquechatoff", &commands::uniqueChatOff);
|
||||||
{
|
this->registerCommand("/r9kbetaoff", &commands::uniqueChatOff);
|
||||||
auto from = matched.captured(1).toInt();
|
|
||||||
auto to = matched.captured(2).toInt();
|
|
||||||
errorMessage +=
|
|
||||||
QString("The duration is out of the valid range: "
|
|
||||||
"%1 through %2.")
|
|
||||||
.arg(from == 0 ? "0s"
|
|
||||||
: formatTime(from *
|
|
||||||
durationUnitMultiplier),
|
|
||||||
to == 0
|
|
||||||
? "0s"
|
|
||||||
: formatTime(to * durationUnitMultiplier));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errorMessage += message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Error::Forwarded: {
|
|
||||||
errorMessage = message;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Error::Unknown:
|
|
||||||
default: {
|
|
||||||
errorMessage += "An unknown error has occurred.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return errorMessage;
|
|
||||||
};
|
|
||||||
|
|
||||||
this->registerCommand("/emoteonly", [formatChatSettingsError](
|
|
||||||
const QStringList & /* words */,
|
|
||||||
auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /emoteonly command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->emoteOnly)
|
|
||||||
{
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage("This room is already in emote-only mode."));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateEmoteMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), true,
|
|
||||||
[](auto) {
|
|
||||||
//we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage(formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/emoteonlyoff", [formatChatSettingsError](
|
|
||||||
const QStringList & /* words */, auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /emoteonlyoff command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!twitchChannel->accessRoomModes()->emoteOnly)
|
|
||||||
{
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage("This room is not in emote-only mode."));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateEmoteMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), false,
|
|
||||||
[](auto) {
|
|
||||||
// we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/subscribers", [formatChatSettingsError](
|
|
||||||
const QStringList & /* words */, auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /subscribers command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->submode)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"This room is already in subscribers-only mode."));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateSubscriberMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), true,
|
|
||||||
[](auto) {
|
|
||||||
//we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand("/subscribersoff", [formatChatSettingsError](
|
|
||||||
const QStringList
|
|
||||||
& /* words */,
|
|
||||||
auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /subscribersoff command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!twitchChannel->accessRoomModes()->submode)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"This room is not in subscribers-only mode."));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateSubscriberMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), false,
|
|
||||||
[](auto) {
|
|
||||||
// we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage(formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand("/slow", [formatChatSettingsError](
|
|
||||||
const QStringList &words, auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /slow command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int duration = 30;
|
|
||||||
if (words.length() >= 2)
|
|
||||||
{
|
|
||||||
bool ok = false;
|
|
||||||
duration = words.at(1).toInt(&ok);
|
|
||||||
if (!ok || duration <= 0)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"Usage: \"/slow [duration]\" - Enables slow mode (limit "
|
|
||||||
"how often users may send messages). Duration (optional, "
|
|
||||||
"default=30) must be a positive number of seconds. Use "
|
|
||||||
"\"slowoff\" to disable. "));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->slowMode == duration)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
QString("This room is already in %1-second slow mode.")
|
|
||||||
.arg(duration)));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateSlowMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), duration,
|
|
||||||
[](auto) {
|
|
||||||
//we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage(formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/slowoff", [formatChatSettingsError](const QStringList & /* words */,
|
|
||||||
auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /slowoff command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->slowMode <= 0)
|
|
||||||
{
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage("This room is not in slow mode."));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateSlowMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), boost::none,
|
|
||||||
[](auto) {
|
|
||||||
// we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand("/followers", [formatChatSettingsError](
|
|
||||||
const QStringList &words,
|
|
||||||
auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /followers command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int duration = 0;
|
|
||||||
if (words.length() >= 2)
|
|
||||||
{
|
|
||||||
auto parsed = parseDurationToSeconds(words.mid(1).join(' '), 60);
|
|
||||||
duration = (int)(parsed / 60);
|
|
||||||
// -1 / 60 == 0 => use parsed
|
|
||||||
if (parsed < 0)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"Usage: \"/followers [duration]\" - Enables followers-only"
|
|
||||||
" mode (only users who have followed for 'duration' may "
|
|
||||||
"chat). Examples: \"30m\", \"1 week\", \"5 days 12 "
|
|
||||||
"hours\". Must be less than 3 months. "));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->followerOnly == duration)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
QString("This room is already in %1 followers-only mode.")
|
|
||||||
.arg(formatTime(duration * 60))));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateFollowerMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), duration,
|
|
||||||
[](auto) {
|
|
||||||
//we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
formatChatSettingsError(error, message, 60)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand("/followersoff", [formatChatSettingsError](
|
|
||||||
const QStringList & /* words */,
|
|
||||||
auto channel) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"The /followersoff command only works in Twitch channels"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->followerOnly < 0)
|
|
||||||
{
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage("This room is not in followers-only mode. "));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateFollowerMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), boost::none,
|
|
||||||
[](auto) {
|
|
||||||
// we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage(formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
auto formatBanTimeoutError =
|
auto formatBanTimeoutError =
|
||||||
[](const char *operation, HelixBanUserError error,
|
[](const char *operation, HelixBanUserError error,
|
||||||
|
@ -3337,67 +2951,6 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
auto uniqueChatLambda = [formatChatSettingsError](auto words, auto channel,
|
|
||||||
bool target) {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to update chat settings!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
QString("The /%1 command only works in Twitch channels")
|
|
||||||
.arg(target ? "uniquechat" : "uniquechatoff")));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twitchChannel->accessRoomModes()->r9k == target)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
target ? "This room is already in unique-chat mode."
|
|
||||||
: "This room is not in unique-chat mode."));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getHelix()->updateUniqueChatMode(
|
|
||||||
twitchChannel->roomId(), currentUser->getUserId(), target,
|
|
||||||
[](auto) {
|
|
||||||
// we'll get a message from irc
|
|
||||||
},
|
|
||||||
[channel, formatChatSettingsError](auto error, auto message) {
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage(formatChatSettingsError(error, message)));
|
|
||||||
});
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/uniquechatoff",
|
|
||||||
[uniqueChatLambda](const QStringList &words, auto channel) {
|
|
||||||
return uniqueChatLambda(words, channel, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/r9kbetaoff",
|
|
||||||
[uniqueChatLambda](const QStringList &words, auto channel) {
|
|
||||||
return uniqueChatLambda(words, channel, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/uniquechat",
|
|
||||||
[uniqueChatLambda](const QStringList &words, auto channel) {
|
|
||||||
return uniqueChatLambda(words, channel, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
|
||||||
"/r9kbeta", [uniqueChatLambda](const QStringList &words, auto channel) {
|
|
||||||
return uniqueChatLambda(words, channel, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand(
|
this->registerCommand(
|
||||||
"/commercial",
|
"/commercial",
|
||||||
[formatStartCommercialError](const QStringList &words,
|
[formatStartCommercialError](const QStringList &words,
|
||||||
|
@ -3544,7 +3097,22 @@ QString CommandController::execCommand(const QString &textNoEmoji,
|
||||||
const auto it = this->commands_.find(commandName);
|
const auto it = this->commands_.find(commandName);
|
||||||
if (it != this->commands_.end())
|
if (it != this->commands_.end())
|
||||||
{
|
{
|
||||||
return it.value()(words, channel);
|
if (auto *command = std::get_if<CommandFunction>(&it->second))
|
||||||
|
{
|
||||||
|
return (*command)(words, channel);
|
||||||
|
}
|
||||||
|
if (auto *command =
|
||||||
|
std::get_if<CommandFunctionWithContext>(&it->second))
|
||||||
|
{
|
||||||
|
CommandContext ctx{
|
||||||
|
words,
|
||||||
|
channel,
|
||||||
|
dynamic_cast<TwitchChannel *>(channel.get()),
|
||||||
|
};
|
||||||
|
return (*command)(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3570,12 +3138,12 @@ QString CommandController::execCommand(const QString &textNoEmoji,
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandController::registerCommand(QString commandName,
|
void CommandController::registerCommand(const QString &commandName,
|
||||||
CommandFunction commandFunction)
|
CommandFunctionVariants commandFunction)
|
||||||
{
|
{
|
||||||
assert(!this->commands_.contains(commandName));
|
assert(this->commands_.count(commandName) == 0);
|
||||||
|
|
||||||
this->commands_[commandName] = commandFunction;
|
this->commands_[commandName] = std::move(commandFunction);
|
||||||
|
|
||||||
this->defaultChatterinoCommandAutoCompletions_.append(commandName);
|
this->defaultChatterinoCommandAutoCompletions_.append(commandName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "common/SignalVector.hpp"
|
#include "common/SignalVector.hpp"
|
||||||
#include "common/Singleton.hpp"
|
#include "common/Singleton.hpp"
|
||||||
#include "controllers/commands/Command.hpp"
|
#include "controllers/commands/Command.hpp"
|
||||||
|
#include "controllers/commands/CommandContext.hpp"
|
||||||
#include "providers/twitch/TwitchChannel.hpp"
|
#include "providers/twitch/TwitchChannel.hpp"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
@ -46,10 +48,16 @@ private:
|
||||||
using CommandFunction =
|
using CommandFunction =
|
||||||
std::function<QString(QStringList /*words*/, ChannelPtr /*channel*/)>;
|
std::function<QString(QStringList /*words*/, ChannelPtr /*channel*/)>;
|
||||||
|
|
||||||
void registerCommand(QString commandName, CommandFunction commandFunction);
|
using CommandFunctionWithContext = std::function<QString(CommandContext)>;
|
||||||
|
|
||||||
|
using CommandFunctionVariants =
|
||||||
|
std::variant<CommandFunction, CommandFunctionWithContext>;
|
||||||
|
|
||||||
|
void registerCommand(const QString &commandName,
|
||||||
|
CommandFunctionVariants commandFunction);
|
||||||
|
|
||||||
// Chatterino commands
|
// Chatterino commands
|
||||||
QMap<QString, CommandFunction> commands_;
|
std::unordered_map<QString, CommandFunctionVariants> commands_;
|
||||||
|
|
||||||
// User-created commands
|
// User-created commands
|
||||||
QMap<QString, Command> userCommands_;
|
QMap<QString, Command> userCommands_;
|
||||||
|
|
434
src/controllers/commands/builtin/twitch/ChatSettings.cpp
Normal file
434
src/controllers/commands/builtin/twitch/ChatSettings.cpp
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
#include "controllers/commands/builtin/twitch/ChatSettings.hpp"
|
||||||
|
|
||||||
|
#include "Application.hpp"
|
||||||
|
#include "controllers/accounts/AccountController.hpp"
|
||||||
|
#include "messages/MessageBuilder.hpp"
|
||||||
|
#include "providers/twitch/TwitchChannel.hpp"
|
||||||
|
#include "providers/twitch/api/Helix.hpp"
|
||||||
|
#include "util/FormatTime.hpp"
|
||||||
|
#include "util/Helpers.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace chatterino;
|
||||||
|
|
||||||
|
QString formatError(const HelixUpdateChatSettingsError error,
|
||||||
|
const QString &message, int durationUnitMultiplier = 1)
|
||||||
|
{
|
||||||
|
static const QRegularExpression invalidRange("(\\d+) through (\\d+)");
|
||||||
|
|
||||||
|
QString errorMessage = QString("Failed to update - ");
|
||||||
|
using Error = HelixUpdateChatSettingsError;
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case Error::UserMissingScope: {
|
||||||
|
// TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE
|
||||||
|
errorMessage += "Missing required scope. "
|
||||||
|
"Re-login with your "
|
||||||
|
"account and try again.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Error::UserNotAuthorized:
|
||||||
|
case Error::Forbidden: {
|
||||||
|
// TODO(pajlada): Phrase MISSING_PERMISSION
|
||||||
|
errorMessage += "You don't have permission to "
|
||||||
|
"perform that action.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Error::Ratelimited: {
|
||||||
|
errorMessage += "You are being ratelimited by Twitch. Try "
|
||||||
|
"again in a few seconds.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Error::OutOfRange: {
|
||||||
|
QRegularExpressionMatch matched = invalidRange.match(message);
|
||||||
|
if (matched.hasMatch())
|
||||||
|
{
|
||||||
|
auto from = matched.captured(1).toInt();
|
||||||
|
auto to = matched.captured(2).toInt();
|
||||||
|
errorMessage +=
|
||||||
|
QString("The duration is out of the valid range: "
|
||||||
|
"%1 through %2.")
|
||||||
|
.arg(from == 0
|
||||||
|
? "0s"
|
||||||
|
: formatTime(from * durationUnitMultiplier),
|
||||||
|
to == 0 ? "0s"
|
||||||
|
: formatTime(to * durationUnitMultiplier));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorMessage += message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Error::Forwarded: {
|
||||||
|
errorMessage = message;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Error::Unknown:
|
||||||
|
default: {
|
||||||
|
errorMessage += "An unknown error has occurred.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do nothing as we'll receive a message from IRC about updates
|
||||||
|
auto successCallback = [](auto result) {};
|
||||||
|
|
||||||
|
auto failureCallback = [](ChannelPtr channel, int durationUnitMultiplier = 1) {
|
||||||
|
return [channel, durationUnitMultiplier](const auto &error,
|
||||||
|
const QString &message) {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
formatError(error, message, durationUnitMultiplier)));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto P_NOT_LOGGED_IN =
|
||||||
|
QStringLiteral("You must be logged in to update chat settings!");
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace chatterino::commands {
|
||||||
|
|
||||||
|
QString emoteOnly(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /emoteonly command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->emoteOnly)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is already in emote-only mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateEmoteMode(ctx.twitchChannel->roomId(),
|
||||||
|
currentUser->getUserId(), true, successCallback,
|
||||||
|
failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString emoteOnlyOff(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /emoteonlyoff command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.twitchChannel->accessRoomModes()->emoteOnly)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is not in emote-only mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateEmoteMode(ctx.twitchChannel->roomId(),
|
||||||
|
currentUser->getUserId(), false,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString subscribers(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /subscribers command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->submode)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"This room is already in subscribers-only mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateSubscriberMode(
|
||||||
|
ctx.twitchChannel->roomId(), currentUser->getUserId(), true,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString subscribersOff(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /subscribersoff command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.twitchChannel->accessRoomModes()->submode)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is not in subscribers-only mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateSubscriberMode(
|
||||||
|
ctx.twitchChannel->roomId(), currentUser->getUserId(), false,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString slow(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /slow command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int duration = 30;
|
||||||
|
if (ctx.words.length() >= 2)
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
duration = ctx.words.at(1).toInt(&ok);
|
||||||
|
if (!ok || duration <= 0)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"Usage: \"/slow [duration]\" - Enables slow mode (limit how "
|
||||||
|
"often users may send messages). Duration (optional, "
|
||||||
|
"default=30) must be a positive number of seconds. Use "
|
||||||
|
"\"slowoff\" to disable."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->slowMode == duration)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
QString("This room is already in %1-second slow mode.")
|
||||||
|
.arg(duration)));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateSlowMode(ctx.twitchChannel->roomId(),
|
||||||
|
currentUser->getUserId(), duration,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString slowOff(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /slowoff command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->slowMode <= 0)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is not in slow mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateSlowMode(ctx.twitchChannel->roomId(),
|
||||||
|
currentUser->getUserId(), boost::none,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString followers(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /followers command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int duration = 0;
|
||||||
|
if (ctx.words.length() >= 2)
|
||||||
|
{
|
||||||
|
auto parsed = parseDurationToSeconds(ctx.words.mid(1).join(' '), 60);
|
||||||
|
duration = (int)(parsed / 60);
|
||||||
|
// -1 / 60 == 0 => use parsed
|
||||||
|
if (parsed < 0)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"Usage: \"/followers [duration]\" - Enables followers-only "
|
||||||
|
"mode (only users who have followed for 'duration' may chat). "
|
||||||
|
"Examples: \"30m\", \"1 week\", \"5 days 12 hours\". Must be "
|
||||||
|
"less than 3 months."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->followerOnly == duration)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
QString("This room is already in %1 followers-only mode.")
|
||||||
|
.arg(formatTime(duration * 60))));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateFollowerMode(
|
||||||
|
ctx.twitchChannel->roomId(), currentUser->getUserId(), duration,
|
||||||
|
successCallback, failureCallback(ctx.channel, 60));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString followersOff(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /followersoff command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->followerOnly < 0)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is not in followers-only mode. "));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateFollowerMode(
|
||||||
|
ctx.twitchChannel->roomId(), currentUser->getUserId(), boost::none,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString uniqueChat(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /uniquechat command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel->accessRoomModes()->r9k)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is already in unique-chat mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateUniqueChatMode(
|
||||||
|
ctx.twitchChannel->roomId(), currentUser->getUserId(), true,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString uniqueChatOff(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
if (currentUser->isAnon())
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.twitchChannel == nullptr)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(makeSystemMessage(
|
||||||
|
"The /uniquechatoff command only works in Twitch channels"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.twitchChannel->accessRoomModes()->r9k)
|
||||||
|
{
|
||||||
|
ctx.channel->addMessage(
|
||||||
|
makeSystemMessage("This room is not in unique-chat mode."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelix()->updateUniqueChatMode(
|
||||||
|
ctx.twitchChannel->roomId(), currentUser->getUserId(), false,
|
||||||
|
successCallback, failureCallback(ctx.channel));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino::commands
|
24
src/controllers/commands/builtin/twitch/ChatSettings.hpp
Normal file
24
src/controllers/commands/builtin/twitch/ChatSettings.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "controllers/commands/CommandContext.hpp"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace chatterino::commands {
|
||||||
|
|
||||||
|
QString emoteOnly(const CommandContext &ctx);
|
||||||
|
QString emoteOnlyOff(const CommandContext &ctx);
|
||||||
|
|
||||||
|
QString subscribers(const CommandContext &ctx);
|
||||||
|
QString subscribersOff(const CommandContext &ctx);
|
||||||
|
|
||||||
|
QString slow(const CommandContext &ctx);
|
||||||
|
QString slowOff(const CommandContext &ctx);
|
||||||
|
|
||||||
|
QString followers(const CommandContext &ctx);
|
||||||
|
QString followersOff(const CommandContext &ctx);
|
||||||
|
|
||||||
|
QString uniqueChat(const CommandContext &ctx);
|
||||||
|
QString uniqueChatOff(const CommandContext &ctx);
|
||||||
|
|
||||||
|
} // namespace chatterino::commands
|
Loading…
Reference in a new issue