Harden emote parsing (#3885)
This commit is contained in:
@@ -107,6 +107,77 @@ namespace {
|
||||
return usernameText;
|
||||
}
|
||||
|
||||
void appendTwitchEmoteOccurrences(const QString &emote,
|
||||
std::vector<TwitchEmoteOccurrence> &vec,
|
||||
const std::vector<int> &correctPositions,
|
||||
const QString &originalMessage,
|
||||
int messageOffset)
|
||||
{
|
||||
auto *app = getIApp();
|
||||
if (!emote.contains(':'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto parameters = emote.split(':');
|
||||
|
||||
if (parameters.length() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto id = EmoteId{parameters.at(0)};
|
||||
|
||||
auto occurrences = parameters.at(1).split(',');
|
||||
|
||||
for (const QString &occurrence : occurrences)
|
||||
{
|
||||
auto coords = occurrence.split('-');
|
||||
|
||||
if (coords.length() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto from = coords.at(0).toUInt() - messageOffset;
|
||||
auto to = coords.at(1).toUInt() - messageOffset;
|
||||
auto maxPositions = correctPositions.size();
|
||||
if (from > to || to >= maxPositions)
|
||||
{
|
||||
// Emote coords are out of range
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< "Emote coords" << from << "-" << to
|
||||
<< "are out of range (" << maxPositions << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
auto start = correctPositions[from];
|
||||
auto end = correctPositions[to];
|
||||
if (start > end || start < 0 || end > originalMessage.length())
|
||||
{
|
||||
// Emote coords are out of range from the modified character positions
|
||||
qCDebug(chatterinoTwitch) << "Emote coords" << from << "-" << to
|
||||
<< "are out of range after offsets ("
|
||||
<< originalMessage.length() << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
auto name = EmoteName{originalMessage.mid(start, end - start + 1)};
|
||||
TwitchEmoteOccurrence emoteOccurrence{
|
||||
start,
|
||||
end,
|
||||
app->getEmotes()->getTwitchEmotes()->getOrCreateEmote(id, name),
|
||||
name,
|
||||
};
|
||||
if (emoteOccurrence.ptr == nullptr)
|
||||
{
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< "nullptr" << emoteOccurrence.name.string;
|
||||
}
|
||||
vec.push_back(std::move(emoteOccurrence));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TwitchMessageBuilder::TwitchMessageBuilder(
|
||||
@@ -304,25 +375,8 @@ MessagePtr TwitchMessageBuilder::build()
|
||||
}
|
||||
|
||||
// Twitch emotes
|
||||
std::vector<TwitchEmoteOccurence> twitchEmotes;
|
||||
|
||||
iterator = this->tags.find("emotes");
|
||||
if (iterator != this->tags.end())
|
||||
{
|
||||
QStringList emoteString = iterator.value().toString().split('/');
|
||||
std::vector<int> correctPositions;
|
||||
for (int i = 0; i < this->originalMessage_.size(); ++i)
|
||||
{
|
||||
if (!this->originalMessage_.at(i).isLowSurrogate())
|
||||
{
|
||||
correctPositions.push_back(i);
|
||||
}
|
||||
}
|
||||
for (QString emote : emoteString)
|
||||
{
|
||||
this->appendTwitchEmote(emote, twitchEmotes, correctPositions);
|
||||
}
|
||||
}
|
||||
auto twitchEmotes = TwitchMessageBuilder::parseTwitchEmotes(
|
||||
this->tags, this->originalMessage_, this->messageOffset_);
|
||||
|
||||
// This runs through all ignored phrases and runs its replacements on this->originalMessage_
|
||||
this->runIgnoreReplaces(twitchEmotes);
|
||||
@@ -379,8 +433,8 @@ MessagePtr TwitchMessageBuilder::build()
|
||||
|
||||
bool doesWordContainATwitchEmote(
|
||||
int cursor, const QString &word,
|
||||
const std::vector<TwitchEmoteOccurence> &twitchEmotes,
|
||||
std::vector<TwitchEmoteOccurence>::const_iterator ¤tTwitchEmoteIt)
|
||||
const std::vector<TwitchEmoteOccurrence> &twitchEmotes,
|
||||
std::vector<TwitchEmoteOccurrence>::const_iterator ¤tTwitchEmoteIt)
|
||||
{
|
||||
if (currentTwitchEmoteIt == twitchEmotes.end())
|
||||
{
|
||||
@@ -404,7 +458,7 @@ bool doesWordContainATwitchEmote(
|
||||
|
||||
void TwitchMessageBuilder::addWords(
|
||||
const QStringList &words,
|
||||
const std::vector<TwitchEmoteOccurence> &twitchEmotes)
|
||||
const std::vector<TwitchEmoteOccurrence> &twitchEmotes)
|
||||
{
|
||||
// cursor currently indicates what character index we're currently operating in the full list of words
|
||||
int cursor = 0;
|
||||
@@ -762,7 +816,7 @@ void TwitchMessageBuilder::appendUsername()
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::runIgnoreReplaces(
|
||||
std::vector<TwitchEmoteOccurence> &twitchEmotes)
|
||||
std::vector<TwitchEmoteOccurrence> &twitchEmotes)
|
||||
{
|
||||
auto phrases = getCSettings().ignoredMessages.readOnly();
|
||||
auto removeEmotesInRange = [](int pos, int len,
|
||||
@@ -780,7 +834,7 @@ void TwitchMessageBuilder::runIgnoreReplaces(
|
||||
<< "remem nullptr" << (*copy).name.string;
|
||||
}
|
||||
}
|
||||
std::vector<TwitchEmoteOccurence> v(it, twitchEmotes.end());
|
||||
std::vector<TwitchEmoteOccurrence> v(it, twitchEmotes.end());
|
||||
twitchEmotes.erase(it, twitchEmotes.end());
|
||||
return v;
|
||||
};
|
||||
@@ -818,7 +872,7 @@ void TwitchMessageBuilder::runIgnoreReplaces(
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< "emote null" << emote.first.string;
|
||||
}
|
||||
twitchEmotes.push_back(TwitchEmoteOccurence{
|
||||
twitchEmotes.push_back(TwitchEmoteOccurrence{
|
||||
startIndex + pos,
|
||||
startIndex + pos + emote.first.string.length(),
|
||||
emote.second,
|
||||
@@ -980,59 +1034,6 @@ void TwitchMessageBuilder::runIgnoreReplaces(
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::appendTwitchEmote(
|
||||
const QString &emote, std::vector<TwitchEmoteOccurence> &vec,
|
||||
std::vector<int> &correctPositions)
|
||||
{
|
||||
auto app = getApp();
|
||||
if (!emote.contains(':'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto parameters = emote.split(':');
|
||||
|
||||
if (parameters.length() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto id = EmoteId{parameters.at(0)};
|
||||
|
||||
auto occurences = parameters.at(1).split(',');
|
||||
|
||||
for (QString occurence : occurences)
|
||||
{
|
||||
auto coords = occurence.split('-');
|
||||
|
||||
if (coords.length() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto start =
|
||||
correctPositions[coords.at(0).toUInt() - this->messageOffset_];
|
||||
auto end =
|
||||
correctPositions[coords.at(1).toUInt() - this->messageOffset_];
|
||||
|
||||
if (start >= end || start < 0 || end > this->originalMessage_.length())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto name =
|
||||
EmoteName{this->originalMessage_.mid(start, end - start + 1)};
|
||||
TwitchEmoteOccurence emoteOccurence{
|
||||
start, end, app->emotes->twitch.getOrCreateEmote(id, name), name};
|
||||
if (emoteOccurence.ptr == nullptr)
|
||||
{
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< "nullptr" << emoteOccurence.name.string;
|
||||
}
|
||||
vec.push_back(std::move(emoteOccurence));
|
||||
}
|
||||
}
|
||||
|
||||
Outcome TwitchMessageBuilder::tryAppendEmote(const EmoteName &name)
|
||||
{
|
||||
auto *app = getApp();
|
||||
@@ -1137,6 +1138,37 @@ std::unordered_map<QString, QString> TwitchMessageBuilder::parseBadgeInfoTag(
|
||||
return infoMap;
|
||||
}
|
||||
|
||||
std::vector<TwitchEmoteOccurrence> TwitchMessageBuilder::parseTwitchEmotes(
|
||||
const QVariantMap &tags, const QString &originalMessage, int messageOffset)
|
||||
{
|
||||
// Twitch emotes
|
||||
std::vector<TwitchEmoteOccurrence> twitchEmotes;
|
||||
|
||||
auto emotesTag = tags.find("emotes");
|
||||
|
||||
if (emotesTag == tags.end())
|
||||
{
|
||||
return twitchEmotes;
|
||||
}
|
||||
|
||||
QStringList emoteString = emotesTag.value().toString().split('/');
|
||||
std::vector<int> correctPositions;
|
||||
for (int i = 0; i < originalMessage.size(); ++i)
|
||||
{
|
||||
if (!originalMessage.at(i).isLowSurrogate())
|
||||
{
|
||||
correctPositions.push_back(i);
|
||||
}
|
||||
}
|
||||
for (const QString &emote : emoteString)
|
||||
{
|
||||
appendTwitchEmoteOccurrences(emote, twitchEmotes, correctPositions,
|
||||
originalMessage, messageOffset);
|
||||
}
|
||||
|
||||
return twitchEmotes;
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::appendTwitchBadges()
|
||||
{
|
||||
if (this->twitchChannel == nullptr)
|
||||
|
||||
Reference in New Issue
Block a user