mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Add new command placeholders: {channel.name}, {channel.id}, {stream.game}, {stream.title}, {my.id}, {my.name} (#3155)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
c0f4a410fa
commit
9b9fd7d403
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Unversioned
|
||||
|
||||
- Minor: Add `{channel.name}`, `{channel.id}`, `{stream.game}`, `{stream.title}`, `{my.id}`, `{my.name}` placeholders for commands (#3155)
|
||||
- Minor: Remove TwitchEmotes.com attribution and the open/copy options when right-clicking a Twitch Emote. (#2214, #3136)
|
||||
- Minor: Strip leading @ and trailing , from username in /user and /usercard commands. (#3143)
|
||||
- Minor: Display a system message when reloading subscription emotes to match BTTV/FFZ behavior (#3135)
|
||||
|
|
|
@ -226,6 +226,72 @@ bool appendWhisperMessageStringLocally(const QString &textNoEmoji)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::map<QString,
|
||||
std::function<QString(const QString &, const ChannelPtr &)>>
|
||||
COMMAND_VARS{
|
||||
{
|
||||
"channel.name",
|
||||
[](const auto &altText, const auto &channel) {
|
||||
(void)(altText); //unused
|
||||
return channel->getName();
|
||||
},
|
||||
},
|
||||
{
|
||||
"channel.id",
|
||||
[](const auto &altText, const auto &channel) {
|
||||
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
if (tc == nullptr)
|
||||
{
|
||||
return altText;
|
||||
}
|
||||
|
||||
return tc->roomId();
|
||||
},
|
||||
},
|
||||
{
|
||||
"stream.game",
|
||||
[](const auto &altText, const auto &channel) {
|
||||
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
if (tc == nullptr)
|
||||
{
|
||||
return altText;
|
||||
}
|
||||
const auto &status = tc->accessStreamStatus();
|
||||
return status->live ? status->game : altText;
|
||||
},
|
||||
},
|
||||
{
|
||||
"stream.title",
|
||||
[](const auto &altText, const auto &channel) {
|
||||
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
if (tc == nullptr)
|
||||
{
|
||||
return altText;
|
||||
}
|
||||
const auto &status = tc->accessStreamStatus();
|
||||
return status->live ? status->title : altText;
|
||||
},
|
||||
},
|
||||
{
|
||||
"my.id",
|
||||
[](const auto &altText, const auto &channel) {
|
||||
(void)(channel); //unused
|
||||
auto uid = getApp()->accounts->twitch.getCurrent()->getUserId();
|
||||
return uid.isEmpty() ? altText : uid;
|
||||
},
|
||||
},
|
||||
{
|
||||
"my.name",
|
||||
[](const auto &altText, const auto &channel) {
|
||||
(void)(channel); //unused
|
||||
auto name =
|
||||
getApp()->accounts->twitch.getCurrent()->getUserName();
|
||||
return name.isEmpty() ? altText : name;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chatterino {
|
||||
|
@ -855,7 +921,7 @@ QString CommandController::execCommand(const QString &textNoEmoji,
|
|||
if (it != this->userCommands_.end())
|
||||
{
|
||||
text = getApp()->emotes->emojis.replaceShortCodes(
|
||||
this->execCustomCommand(words, it.value(), dryRun));
|
||||
this->execCustomCommand(words, it.value(), dryRun, channel));
|
||||
|
||||
words = text.split(' ', QString::SkipEmptyParts);
|
||||
|
||||
|
@ -887,7 +953,7 @@ QString CommandController::execCommand(const QString &textNoEmoji,
|
|||
const auto it = this->userCommands_.find(commandName);
|
||||
if (it != this->userCommands_.end())
|
||||
{
|
||||
return this->execCustomCommand(words, it.value(), dryRun);
|
||||
return this->execCustomCommand(words, it.value(), dryRun, channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -906,11 +972,13 @@ void CommandController::registerCommand(QString commandName,
|
|||
|
||||
QString CommandController::execCustomCommand(const QStringList &words,
|
||||
const Command &command,
|
||||
bool dryRun)
|
||||
bool dryRun, ChannelPtr channel,
|
||||
std::map<QString, QString> context)
|
||||
{
|
||||
QString result;
|
||||
|
||||
static QRegularExpression parseCommand("(^|[^{])({{)*{(\\d+\\+?)}");
|
||||
static QRegularExpression parseCommand(
|
||||
R"((^|[^{])({{)*{(\d+\+?|([a-zA-Z.-]+)(?:;(.+?))?)})");
|
||||
|
||||
int lastCaptureEnd = 0;
|
||||
|
||||
|
@ -941,8 +1009,28 @@ QString CommandController::execCustomCommand(const QStringList &words,
|
|||
bool ok;
|
||||
int wordIndex = wordIndexMatch.replace("=", "").toInt(&ok);
|
||||
if (!ok || wordIndex == 0)
|
||||
{
|
||||
auto varName = match.captured(4);
|
||||
auto altText = match.captured(5); // alt text or empty string
|
||||
|
||||
auto var = COMMAND_VARS.find(varName);
|
||||
|
||||
if (var != COMMAND_VARS.end())
|
||||
{
|
||||
result += var->second(altText, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = context.find(varName);
|
||||
if (it != context.end())
|
||||
{
|
||||
result += it->second.isEmpty() ? altText : it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += "{" + match.captured(3) + "}";
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ public:
|
|||
|
||||
CommandModel *createModel(QObject *parent);
|
||||
|
||||
QString execCustomCommand(const QStringList &words, const Command &command,
|
||||
bool dryRun, ChannelPtr channel,
|
||||
std::map<QString, QString> context = {});
|
||||
|
||||
private:
|
||||
void load(Paths &paths);
|
||||
|
||||
|
@ -57,9 +61,6 @@ private:
|
|||
std::unique_ptr<pajlada::Settings::Setting<std::vector<Command>>>
|
||||
commandsSetting_;
|
||||
|
||||
QString execCustomCommand(const QStringList &words, const Command &command,
|
||||
bool dryRun);
|
||||
|
||||
QStringList commandAutoCompletions_;
|
||||
};
|
||||
|
||||
|
|
|
@ -2101,12 +2101,24 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
|||
}
|
||||
}
|
||||
|
||||
value.replace("{user}", layout->getMessage()->loginName)
|
||||
.replace("{channel}", this->channel_->getName())
|
||||
.replace("{msg-id}", layout->getMessage()->id)
|
||||
.replace("{message}", layout->getMessage()->messageText);
|
||||
value = getApp()->commands->execCustomCommand(
|
||||
QStringList(), Command{"(modaction)", value}, true, channel,
|
||||
{
|
||||
{"user.name", layout->getMessage()->loginName},
|
||||
{"msg.id", layout->getMessage()->id},
|
||||
{"msg.text", layout->getMessage()->messageText},
|
||||
|
||||
// old placeholders
|
||||
{"user", layout->getMessage()->loginName},
|
||||
{"msg-id", layout->getMessage()->id},
|
||||
{"message", layout->getMessage()->messageText},
|
||||
|
||||
// new version of this is inside execCustomCommand
|
||||
{"channel", this->channel()->getName()},
|
||||
});
|
||||
|
||||
value = getApp()->commands->execCommand(value, channel, false);
|
||||
|
||||
channel->sendMessage(value);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -157,8 +157,8 @@ ModerationPage::ModerationPage()
|
|||
// clang-format off
|
||||
auto label = modMode.emplace<QLabel>(
|
||||
"Moderation mode is enabled by clicking <img width='18' height='18' src=':/buttons/modModeDisabled.png'> in a channel that you moderate.<br><br>"
|
||||
"Moderation buttons can be bound to chat commands such as \"/ban {user}\", \"/timeout {user} 1000\", \"/w someusername !report {user} was bad in channel {channel}\" or any other custom text commands.<br>"
|
||||
"For deleting messages use /delete {msg-id}.<br><br>"
|
||||
"Moderation buttons can be bound to chat commands such as \"/ban {user.name}\", \"/timeout {user.name} 1000\", \"/w someusername !report {user.name} was bad in channel {channel.name}\" or any other custom text commands.<br>"
|
||||
"For deleting messages use /delete {msg.id}.<br><br>"
|
||||
"More information can be found <a href='https://wiki.chatterino.com/Moderation/#moderation-mode'>here</a>.");
|
||||
label->setOpenExternalLinks(true);
|
||||
label->setWordWrap(true);
|
||||
|
@ -188,7 +188,7 @@ ModerationPage::ModerationPage()
|
|||
|
||||
view->addButtonPressed.connect([] {
|
||||
getSettings()->moderationActions.append(
|
||||
ModerationAction("/timeout {user} 300"));
|
||||
ModerationAction("/timeout {user.name} 300"));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue