Make builtin commands work in IRC channels (#4160)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
Mm2PL 2022-11-17 20:22:47 +01:00 committed by GitHub
parent 32d077c43b
commit 49eb5c90cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 171 additions and 117 deletions

View file

@ -82,6 +82,7 @@
- Minor: Improved text selection to match Windows native behaviour. (#4127) - Minor: Improved text selection to match Windows native behaviour. (#4127)
- Minor: Add settings tooltips. (#3437) - Minor: Add settings tooltips. (#3437)
- Minor: Add setting to limit message input length. (#3418) - Minor: Add setting to limit message input length. (#3418)
- Minor: Make built-in commands work in IRC channels. (#4160)
- Minor: Improved look of tabs when using a layout other than top. (#3925, #4152) - Minor: Improved look of tabs when using a layout other than top. (#3925, #4152)
- Bugfix: Fixed channels with two leading `#`s not being usable on IRC (#4154) - Bugfix: Fixed channels with two leading `#`s not being usable on IRC (#4154)
- Bugfix: Fixed `Add new account` dialog causing main chatterino window to be non movable. (#4121) - Bugfix: Fixed `Add new account` dialog causing main chatterino window to be non movable. (#4121)

View file

@ -607,6 +607,13 @@ void CommandController::initialize(Settings &, Paths &paths)
/// Deprecated commands /// Deprecated commands
auto blockLambda = [](const auto &words, auto channel) { auto blockLambda = [](const auto &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /block command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage("Usage: /block <user>")); channel->addMessage(makeSystemMessage("Usage: /block <user>"));
@ -653,6 +660,13 @@ void CommandController::initialize(Settings &, Paths &paths)
}; };
auto unblockLambda = [](const auto &words, auto channel) { auto unblockLambda = [](const auto &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unblock command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage("Usage: /unblock <user>")); channel->addMessage(makeSystemMessage("Usage: /unblock <user>"));
@ -717,6 +731,11 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/follow", [](const auto &words, auto channel) { this->registerCommand("/follow", [](const auto &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
return "";
}
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
"Twitch has removed the ability to follow users through " "Twitch has removed the ability to follow users through "
"third-party applications. For more information, see " "third-party applications. For more information, see "
@ -725,6 +744,11 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/unfollow", [](const auto &words, auto channel) { this->registerCommand("/unfollow", [](const auto &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
return "";
}
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
"Twitch has removed the ability to unfollow users through " "Twitch has removed the ability to unfollow users through "
"third-party applications. For more information, see " "third-party applications. For more information, see "
@ -1067,6 +1091,15 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand( this->registerCommand(
"/mods", "/mods",
[formatModsError](const QStringList &words, auto channel) -> QString { [formatModsError](const QStringList &words, auto channel) -> QString {
auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /mods command only works in Twitch Channels"));
return "";
}
switch (getSettings()->helixTimegateModerators.getValue()) switch (getSettings()->helixTimegateModerators.getValue())
{ {
case HelixTimegateOverride::Timegate: { case HelixTimegateOverride::Timegate: {
@ -1087,15 +1120,6 @@ void CommandController::initialize(Settings &, Paths &paths)
break; break;
} }
auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /mods command only works in Twitch Channels"));
return "";
}
getHelix()->getModerators( getHelix()->getModerators(
twitchChannel->roomId(), 500, twitchChannel->roomId(), 500,
[channel, twitchChannel](auto result) { [channel, twitchChannel](auto result) {
@ -1119,6 +1143,8 @@ void CommandController::initialize(Settings &, Paths &paths)
type != Channel::Type::Twitch && type != Channel::Type::Twitch &&
type != Channel::Type::TwitchWatching) type != Channel::Type::TwitchWatching)
{ {
channel->addMessage(makeSystemMessage(
"The /clip command only works in Twitch Channels"));
return ""; return "";
} }
@ -1443,8 +1469,17 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
}); });
this->registerCommand("/raw", [](const QStringList &words, ChannelPtr) { this->registerCommand(
"/raw", [](const QStringList &words, ChannelPtr channel) -> QString {
if (channel->isTwitchChannel())
{
getApp()->twitch->sendRawMessage(words.mid(1).join(" ")); getApp()->twitch->sendRawMessage(words.mid(1).join(" "));
}
else
{
// other code down the road handles this for IRC
return words.join(" ");
}
return ""; return "";
}); });
@ -1502,6 +1537,12 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand( this->registerCommand(
"/fakemsg", "/fakemsg",
[](const QStringList &words, ChannelPtr channel) -> QString { [](const QStringList &words, ChannelPtr channel) -> QString {
if (!channel->isTwitchChannel())
{
channel->addMessage(makeSystemMessage(
"The /fakemsg command only works in Twitch channels."));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
@ -1529,6 +1570,12 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/color", [](const QStringList &words, auto channel) { this->registerCommand("/color", [](const QStringList &words, auto channel) {
if (!channel->isTwitchChannel())
{
channel->addMessage(makeSystemMessage(
"The /color command only works in Twitch channels"));
return "";
}
auto user = getApp()->accounts->twitch.getCurrent(); auto user = getApp()->accounts->twitch.getCurrent();
// Avoid Helix calls without Client ID and/or OAuth Token // Avoid Helix calls without Client ID and/or OAuth Token
@ -1601,23 +1648,16 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
}); });
auto deleteMessages = [](auto channel, const QString &messageID) { auto deleteMessages = [](TwitchChannel *twitchChannel,
const QString &messageID) {
const auto *commandName = messageID.isEmpty() ? "/clear" : "/delete"; const auto *commandName = messageID.isEmpty() ? "/clear" : "/delete";
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The %1 command only works in Twitch channels")
.arg(commandName)));
return "";
}
auto user = getApp()->accounts->twitch.getCurrent(); auto user = getApp()->accounts->twitch.getCurrent();
// Avoid Helix calls without Client ID and/or OAuth Token // Avoid Helix calls without Client ID and/or OAuth Token
if (user->isAnon()) if (user->isAnon())
{ {
channel->addMessage(makeSystemMessage( twitchChannel->addMessage(makeSystemMessage(
QString("You must be logged in to use the %1 command.") QString("You must be logged in to use the %1 command.")
.arg(commandName))); .arg(commandName)));
return ""; return "";
@ -1629,7 +1669,7 @@ void CommandController::initialize(Settings &, Paths &paths)
// Success handling, we do nothing: IRC/pubsub-edge will dispatch the correct // Success handling, we do nothing: IRC/pubsub-edge will dispatch the correct
// events to update state for us. // events to update state for us.
}, },
[channel, messageID](auto error, auto message) { [twitchChannel, messageID](auto error, auto message) {
QString errorMessage = QString errorMessage =
QString("Failed to delete chat messages - "); QString("Failed to delete chat messages - ");
@ -1675,7 +1715,7 @@ void CommandController::initialize(Settings &, Paths &paths)
break; break;
} }
channel->addMessage(makeSystemMessage(errorMessage)); twitchChannel->addMessage(makeSystemMessage(errorMessage));
}); });
return ""; return "";
@ -1684,13 +1724,27 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand( this->registerCommand(
"/clear", [deleteMessages](const QStringList &words, auto channel) { "/clear", [deleteMessages](const QStringList &words, auto channel) {
(void)words; // unused (void)words; // unused
return deleteMessages(channel, QString()); auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /clear command only works in Twitch channels"));
return "";
}
return deleteMessages(twitchChannel, QString());
}); });
this->registerCommand("/delete", [deleteMessages](const QStringList &words, this->registerCommand("/delete", [deleteMessages](const QStringList &words,
auto channel) { auto channel) {
// This is a wrapper over the Helix delete messages endpoint // This is a wrapper over the Helix delete messages endpoint
// We use this to ensure the user gets better error messages for missing or malformed arguments // We use this to ensure the user gets better error messages for missing or malformed arguments
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /delete command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage( channel->addMessage(
@ -1722,10 +1776,17 @@ void CommandController::initialize(Settings &, Paths &paths)
} }
} }
return deleteMessages(channel, messageID); return deleteMessages(twitchChannel, messageID);
}); });
this->registerCommand("/mod", [](const QStringList &words, auto channel) { this->registerCommand("/mod", [](const QStringList &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /mod command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
@ -1742,14 +1803,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /mod command only works in Twitch channels"));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -1837,6 +1890,13 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/unmod", [](const QStringList &words, auto channel) { this->registerCommand("/unmod", [](const QStringList &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unmod command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
@ -1853,14 +1913,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unmod command only works in Twitch channels"));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2003,6 +2055,13 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/vip", [](const QStringList &words, auto channel) { this->registerCommand("/vip", [](const QStringList &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /vip command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
@ -2019,14 +2078,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /vip command only works in Twitch channels"));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2096,6 +2147,13 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/unvip", [](const QStringList &words, auto channel) { this->registerCommand("/unvip", [](const QStringList &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unvip command only works in Twitch channels"));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
@ -2112,14 +2170,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unvip command only works in Twitch channels"));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2202,6 +2252,14 @@ void CommandController::initialize(Settings &, Paths &paths)
// These changes are from the helix-command-migration/unban-untimeout branch // These changes are from the helix-command-migration/unban-untimeout branch
auto unbanLambda = [](auto words, auto channel) { auto unbanLambda = [](auto words, auto channel) {
auto commandName = words.at(0).toLower(); auto commandName = words.at(0).toLower();
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The %1 command only works in Twitch channels")
.arg(commandName)));
return "";
}
if (words.size() < 2) if (words.size() < 2)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
@ -2218,15 +2276,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The %1 command only works in Twitch channels")
.arg(commandName)));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2332,6 +2381,13 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand( // /raid this->registerCommand( // /raid
"/raid", [](const QStringList &words, auto channel) -> QString { "/raid", [](const QStringList &words, auto channel) -> QString {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /raid command only works in Twitch channels"));
return "";
}
switch (getSettings()->helixTimegateRaid.getValue()) switch (getSettings()->helixTimegateRaid.getValue())
{ {
case HelixTimegateOverride::Timegate: { case HelixTimegateOverride::Timegate: {
@ -2371,14 +2427,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /raid command only works in Twitch channels"));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2455,6 +2503,13 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand( // /unraid this->registerCommand( // /unraid
"/unraid", [](const QStringList &words, auto channel) -> QString { "/unraid", [](const QStringList &words, auto channel) -> QString {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unraid command only works in Twitch channels"));
return "";
}
switch (getSettings()->helixTimegateRaid.getValue()) switch (getSettings()->helixTimegateRaid.getValue())
{ {
case HelixTimegateOverride::Timegate: { case HelixTimegateOverride::Timegate: {
@ -2494,14 +2549,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /unraid command only works in Twitch channels"));
return "";
}
getHelix()->cancelRaid( getHelix()->cancelRaid(
twitchChannel->roomId(), twitchChannel->roomId(),
[channel] { [channel] {
@ -2635,6 +2682,13 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand("/timeout", [formatBanTimeoutError]( this->registerCommand("/timeout", [formatBanTimeoutError](
const QStringList &words, const QStringList &words,
auto channel) { auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The /timeout command only works in Twitch channels")));
return "";
}
const auto *usageStr = const auto *usageStr =
"Usage: \"/timeout <username> [duration][time unit] [reason]\" - " "Usage: \"/timeout <username> [duration][time unit] [reason]\" - "
"Temporarily prevent a user from chatting. Duration (optional, " "Temporarily prevent a user from chatting. Duration (optional, "
@ -2657,14 +2711,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The /timeout command only works in Twitch channels")));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2708,6 +2754,14 @@ void CommandController::initialize(Settings &, Paths &paths)
this->registerCommand("/ban", [formatBanTimeoutError]( this->registerCommand("/ban", [formatBanTimeoutError](
const QStringList &words, auto channel) { const QStringList &words, auto channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The /ban command only works in Twitch channels")));
return "";
}
const auto *usageStr = const auto *usageStr =
"Usage: \"/ban <username> [reason]\" - Permanently prevent a user " "Usage: \"/ban <username> [reason]\" - Permanently prevent a user "
"from chatting. Reason is optional and will be shown to the target " "from chatting. Reason is optional and will be shown to the target "
@ -2726,14 +2780,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
QString("The /ban command only works in Twitch channels")));
return "";
}
auto target = words.at(1); auto target = words.at(1);
stripChannelName(target); stripChannelName(target);
@ -2882,6 +2928,14 @@ void CommandController::initialize(Settings &, Paths &paths)
"/vips", "/vips",
[formatVIPListError](const QStringList &words, [formatVIPListError](const QStringList &words,
auto channel) -> QString { auto channel) -> QString {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /vips command only works in Twitch channels"));
return "";
}
switch (getSettings()->helixTimegateVIPs.getValue()) switch (getSettings()->helixTimegateVIPs.getValue())
{ {
case HelixTimegateOverride::Timegate: { case HelixTimegateOverride::Timegate: {
@ -2904,15 +2958,6 @@ void CommandController::initialize(Settings &, Paths &paths)
} }
break; break;
} }
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /vips command only works in Twitch channels"));
return "";
}
auto currentUser = getApp()->accounts->twitch.getCurrent(); auto currentUser = getApp()->accounts->twitch.getCurrent();
if (currentUser->isAnon()) if (currentUser->isAnon())
{ {
@ -2963,6 +3008,14 @@ void CommandController::initialize(Settings &, Paths &paths)
"/commercial", "/commercial",
[formatStartCommercialError](const QStringList &words, [formatStartCommercialError](const QStringList &words,
auto channel) -> QString { auto channel) -> QString {
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
if (tc == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /commercial command only works in Twitch channels"));
return "";
}
const auto *usageStr = "Usage: \"/commercial <length>\" - Starts a " const auto *usageStr = "Usage: \"/commercial <length>\" - Starts a "
"commercial with the " "commercial with the "
"specified duration for the current " "specified duration for the current "
@ -3008,12 +3061,6 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
} }
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
if (tc == nullptr)
{
return "";
}
auto broadcasterID = tc->roomId(); auto broadcasterID = tc->roomId();
auto length = words.at(1).toInt(); auto length = words.at(1).toInt();
@ -3040,6 +3087,13 @@ void CommandController::initialize(Settings &, Paths &paths)
}); });
this->registerCommand("/unstable-set-user-color", [](const auto &ctx) { this->registerCommand("/unstable-set-user-color", [](const auto &ctx) {
if (ctx.twitchChannel == nullptr)
{
ctx.channel->addMessage(
makeSystemMessage("The /unstable-set-user-color command only "
"works in Twitch channels"));
return "";
}
auto userID = ctx.words.at(1); auto userID = ctx.words.at(1);
if (ctx.words.size() < 2) if (ctx.words.size() < 2)
{ {
@ -3101,8 +3155,7 @@ QString CommandController::execCommand(const QString &textNoEmoji,
} }
} }
// works only in a valid Twitch channel if (!dryRun)
if (!dryRun && channel->isTwitchChannel())
{ {
// check if command exists // check if command exists
const auto it = this->commands_.find(commandName); const auto it = this->commands_.find(commandName);