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
|
## 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: 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: 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)
|
- 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;
|
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
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
@ -855,7 +921,7 @@ QString CommandController::execCommand(const QString &textNoEmoji,
|
||||||
if (it != this->userCommands_.end())
|
if (it != this->userCommands_.end())
|
||||||
{
|
{
|
||||||
text = getApp()->emotes->emojis.replaceShortCodes(
|
text = getApp()->emotes->emojis.replaceShortCodes(
|
||||||
this->execCustomCommand(words, it.value(), dryRun));
|
this->execCustomCommand(words, it.value(), dryRun, channel));
|
||||||
|
|
||||||
words = text.split(' ', QString::SkipEmptyParts);
|
words = text.split(' ', QString::SkipEmptyParts);
|
||||||
|
|
||||||
|
@ -887,7 +953,7 @@ QString CommandController::execCommand(const QString &textNoEmoji,
|
||||||
const auto it = this->userCommands_.find(commandName);
|
const auto it = this->userCommands_.find(commandName);
|
||||||
if (it != this->userCommands_.end())
|
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,
|
QString CommandController::execCustomCommand(const QStringList &words,
|
||||||
const Command &command,
|
const Command &command,
|
||||||
bool dryRun)
|
bool dryRun, ChannelPtr channel,
|
||||||
|
std::map<QString, QString> context)
|
||||||
{
|
{
|
||||||
QString result;
|
QString result;
|
||||||
|
|
||||||
static QRegularExpression parseCommand("(^|[^{])({{)*{(\\d+\\+?)}");
|
static QRegularExpression parseCommand(
|
||||||
|
R"((^|[^{])({{)*{(\d+\+?|([a-zA-Z.-]+)(?:;(.+?))?)})");
|
||||||
|
|
||||||
int lastCaptureEnd = 0;
|
int lastCaptureEnd = 0;
|
||||||
|
|
||||||
|
@ -941,8 +1009,28 @@ QString CommandController::execCustomCommand(const QStringList &words,
|
||||||
bool ok;
|
bool ok;
|
||||||
int wordIndex = wordIndexMatch.replace("=", "").toInt(&ok);
|
int wordIndex = wordIndexMatch.replace("=", "").toInt(&ok);
|
||||||
if (!ok || wordIndex == 0)
|
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) + "}";
|
result += "{" + match.captured(3) + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,10 @@ public:
|
||||||
|
|
||||||
CommandModel *createModel(QObject *parent);
|
CommandModel *createModel(QObject *parent);
|
||||||
|
|
||||||
|
QString execCustomCommand(const QStringList &words, const Command &command,
|
||||||
|
bool dryRun, ChannelPtr channel,
|
||||||
|
std::map<QString, QString> context = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void load(Paths &paths);
|
void load(Paths &paths);
|
||||||
|
|
||||||
|
@ -57,9 +61,6 @@ private:
|
||||||
std::unique_ptr<pajlada::Settings::Setting<std::vector<Command>>>
|
std::unique_ptr<pajlada::Settings::Setting<std::vector<Command>>>
|
||||||
commandsSetting_;
|
commandsSetting_;
|
||||||
|
|
||||||
QString execCustomCommand(const QStringList &words, const Command &command,
|
|
||||||
bool dryRun);
|
|
||||||
|
|
||||||
QStringList commandAutoCompletions_;
|
QStringList commandAutoCompletions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2101,12 +2101,24 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value.replace("{user}", layout->getMessage()->loginName)
|
value = getApp()->commands->execCustomCommand(
|
||||||
.replace("{channel}", this->channel_->getName())
|
QStringList(), Command{"(modaction)", value}, true, channel,
|
||||||
.replace("{msg-id}", layout->getMessage()->id)
|
{
|
||||||
.replace("{message}", layout->getMessage()->messageText);
|
{"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);
|
value = getApp()->commands->execCommand(value, channel, false);
|
||||||
|
|
||||||
channel->sendMessage(value);
|
channel->sendMessage(value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -157,8 +157,8 @@ ModerationPage::ModerationPage()
|
||||||
// clang-format off
|
// clang-format off
|
||||||
auto label = modMode.emplace<QLabel>(
|
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 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>"
|
"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>"
|
"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>.");
|
"More information can be found <a href='https://wiki.chatterino.com/Moderation/#moderation-mode'>here</a>.");
|
||||||
label->setOpenExternalLinks(true);
|
label->setOpenExternalLinks(true);
|
||||||
label->setWordWrap(true);
|
label->setWordWrap(true);
|
||||||
|
@ -188,7 +188,7 @@ ModerationPage::ModerationPage()
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
view->addButtonPressed.connect([] {
|
||||||
getSettings()->moderationActions.append(
|
getSettings()->moderationActions.append(
|
||||||
ModerationAction("/timeout {user} 300"));
|
ModerationAction("/timeout {user.name} 300"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue