From cc5eb7000f0d4dbe545e2ce56d174cf381d83e8c Mon Sep 17 00:00:00 2001 From: Auro <35087590+MrAuro@users.noreply.github.com> Date: Sat, 26 Sep 2020 07:06:37 -0400 Subject: [PATCH 1/3] Fixed the english of a system message (#1878) * Update TwitchIrcServer.cpp * made english better changed "sending messages too fast" to "You are sending messages too fast" * changed english * Changed English Changed the English in 2 system messages * Update CHANGELOG.md * Changed too fast to too quickly Co-authored-by: fourtf --- CHANGELOG.md | 1 + src/providers/twitch/TwitchIrcServer.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2f67d3a..4c2e7b5ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - Minor: Removed "Online Logs" functionality as services are shut down (#1640) - Minor: CTRL+F now selects the Find text input field in the Settings Dialog (#1806 #1811) - Minor: CTRL+F now selects the search text input field in the Search Popup (#1812) +- Minor: Changed the English in two rate-limited system messages (#1878) - Minor: Modify our word boundary logic in highlight phrase searching to accomodate non-regex phrases with "word-boundary-creating" characters like ! (#1885, #1890) - Bugfix: Fixed not being able to open links in incognito with Microsoft Edge (Chromium) (#1875) - Bugfix: Fix the incorrect `Open stream in browser` labelling in the whisper split (#1860) diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index b2c2fe98a..d31e844fa 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -336,7 +336,7 @@ void TwitchIrcServer::onMessageSendRequested(TwitchChannel *channel, if (this->lastErrorTimeSpeed_ + 30s < now) { auto errorMessage = - makeSystemMessage("sending messages too fast"); + makeSystemMessage("You are sending messages too quickly."); channel->addMessage(errorMessage); @@ -357,7 +357,7 @@ void TwitchIrcServer::onMessageSendRequested(TwitchChannel *channel, if (this->lastErrorTimeAmount_ + 30s < now) { auto errorMessage = - makeSystemMessage("sending too many messages"); + makeSystemMessage("You are sending too many messages."); channel->addMessage(errorMessage); From d9e6488be3ac41a2dc31f1d70e0331857383a5b4 Mon Sep 17 00:00:00 2001 From: apa420 <17131426+apa420@users.noreply.github.com> Date: Sat, 26 Sep 2020 13:38:15 +0200 Subject: [PATCH 2/3] Update CHANGELOG.md (#1990) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2e7b5ee..1b046d692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Minor: Deprecate loading of "v1" window layouts. If you haven't updated Chatterino in more than 2 years, there's a chance you will lose your window layout. - Minor: Disable checking for updates on unsupported platforms (#1874) +- Minor: Changed the English in two rate-limited system messages (#1878) - Bugfix: Fix bug preventing users from setting the highlight color of the second entry in the "User" highlights tab (#1898) - Bugfix: Fix bug where the "check user follow state" event could trigger a network request requesting the user to follow or unfollow a user. By itself its quite harmless as it just repeats to Twitch the same follow state we had, so no follows should have been lost by this but it meant there was a rogue network request that was fired that could cause a crash (#1906) - Bugfix: /usercard command will now respect the "Automatically close user popup" setting (#1918) @@ -29,7 +30,6 @@ - Minor: Removed "Online Logs" functionality as services are shut down (#1640) - Minor: CTRL+F now selects the Find text input field in the Settings Dialog (#1806 #1811) - Minor: CTRL+F now selects the search text input field in the Search Popup (#1812) -- Minor: Changed the English in two rate-limited system messages (#1878) - Minor: Modify our word boundary logic in highlight phrase searching to accomodate non-regex phrases with "word-boundary-creating" characters like ! (#1885, #1890) - Bugfix: Fixed not being able to open links in incognito with Microsoft Edge (Chromium) (#1875) - Bugfix: Fix the incorrect `Open stream in browser` labelling in the whisper split (#1860) From 20e4d6b3d257b53c34b3f4fd7c26f38b7e5395b5 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 26 Sep 2020 08:21:46 -0400 Subject: [PATCH 3/3] Update emote parsing (#1714) Fixes #1707 --- CHANGELOG.md | 1 + src/providers/twitch/TwitchMessageBuilder.cpp | 189 +++++++++++------- src/providers/twitch/TwitchMessageBuilder.hpp | 23 ++- src/widgets/Window.cpp | 18 +- 4 files changed, 147 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b046d692..dc7f671ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Bugfix: /usercard command will now respect the "Automatically close user popup" setting (#1918) - Bugfix: Handle symlinks properly when saving commands & settings (#1856, #1908) - Bugfix: Starting Chatterino in a minimized state after an update will no longer cause a crash +- Bugfix: Modify the emote parsing to handle some edge-cases with dots and stuff (#1704, #1714) ## 2.2.0 diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 0e64beaf4..9eca8ad4c 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -282,7 +282,7 @@ MessagePtr TwitchMessageBuilder::build() } // twitch emotes - std::vector> twitchEmotes; + std::vector twitchEmotes; iterator = this->tags.find("emotes"); if (iterator != this->tags.end()) @@ -307,12 +307,11 @@ MessagePtr TwitchMessageBuilder::build() std::sort(twitchEmotes.begin(), twitchEmotes.end(), [](const auto &a, const auto &b) { - return std::get<0>(a) < std::get<0>(b); + return a.start < b.start; // }); twitchEmotes.erase(std::unique(twitchEmotes.begin(), twitchEmotes.end(), [](const auto &first, const auto &second) { - return std::get<0>(first) == - std::get<0>(second); + return first.start == second.start; }), twitchEmotes.end()); @@ -339,47 +338,90 @@ MessagePtr TwitchMessageBuilder::build() return this->release(); } +bool doesWordContainATwitchEmote( + int cursor, const QString &word, + const std::vector &twitchEmotes, + std::vector::const_iterator ¤tTwitchEmoteIt) +{ + if (currentTwitchEmoteIt == twitchEmotes.end()) + { + // No emote to add! + return false; + } + + const auto ¤tTwitchEmote = *currentTwitchEmoteIt; + + auto wordEnd = cursor + word.length(); + + // Check if this emote fits within the word boundaries + if (currentTwitchEmote.start < cursor || currentTwitchEmote.end > wordEnd) + { + // this emote does not fit xd + return false; + } + + return true; +} + void TwitchMessageBuilder::addWords( const QStringList &words, - const std::vector> &twitchEmotes) + const std::vector &twitchEmotes) { - auto i = int(); - auto currentTwitchEmote = twitchEmotes.begin(); + // cursor currently indicates what character index we're currently operating in the full list of words + int cursor = 0; + auto currentTwitchEmoteIt = twitchEmotes.begin(); for (auto word : words) { - // check if it's a twitch emote twitch emote - while (currentTwitchEmote != twitchEmotes.end() && - std::get<0>(*currentTwitchEmote) < i) + while (doesWordContainATwitchEmote(cursor, word, twitchEmotes, + currentTwitchEmoteIt)) { - ++currentTwitchEmote; - } - if (currentTwitchEmote != twitchEmotes.end() && - std::get<0>(*currentTwitchEmote) == i) - { - auto emoteImage = std::get<1>(*currentTwitchEmote); - if (emoteImage == nullptr) - { - qDebug() << "emoteImage nullptr" - << std::get<2>(*currentTwitchEmote).string; - } - this->emplace(emoteImage, - MessageElementFlag::TwitchEmote); - - i += word.length() + 1; - - int len = std::get<2>(*currentTwitchEmote).string.length(); - currentTwitchEmote++; - - if (len < word.length()) + auto wordEnd = cursor + word.length(); + const auto ¤tTwitchEmote = *currentTwitchEmoteIt; + + if (currentTwitchEmote.start == cursor) { + // This emote exists right at the start of the word! + this->emplace(currentTwitchEmote.ptr, + MessageElementFlag::TwitchEmote); + auto len = currentTwitchEmote.name.string.length(); + cursor += len; word = word.mid(len); - this->message().elements.back()->setTrailingSpace(false); - } - else - { + + ++currentTwitchEmoteIt; + + if (word.isEmpty()) + { + // space + cursor += 1; + break; + } + else + { + this->message().elements.back()->setTrailingSpace(false); + } + continue; } + + // Emote is not at the start + + // 1. Add text before the emote + QString preText = word.left(currentTwitchEmote.start - cursor); + for (auto &variant : getApp()->emotes->emojis.parse(preText)) + { + boost::apply_visitor( + [&](auto &&arg) { this->addTextOrEmoji(arg); }, variant); + } + + cursor += preText.size(); + + word = word.mid(preText.size()); + } + + if (word.isEmpty()) + { + continue; } // split words @@ -389,7 +431,7 @@ void TwitchMessageBuilder::addWords( variant); } - i += word.size() + 1; + cursor += word.size() + 1; } } @@ -660,36 +702,32 @@ void TwitchMessageBuilder::appendUsername() } void TwitchMessageBuilder::runIgnoreReplaces( - std::vector> &twitchEmotes) + std::vector &twitchEmotes) { auto phrases = getCSettings().ignoredMessages.readOnly(); - auto removeEmotesInRange = - [](int pos, int len, - std::vector> - &twitchEmotes) mutable { - auto it = - std::partition(twitchEmotes.begin(), twitchEmotes.end(), - [pos, len](const auto &item) { - return !((std::get<0>(item) >= pos) && - std::get<0>(item) < (pos + len)); - }); - for (auto copy = it; copy != twitchEmotes.end(); ++copy) + auto removeEmotesInRange = [](int pos, int len, + auto &twitchEmotes) mutable { + auto it = std::partition( + twitchEmotes.begin(), twitchEmotes.end(), + [pos, len](const auto &item) { + return !((item.start >= pos) && item.start < (pos + len)); + }); + for (auto copy = it; copy != twitchEmotes.end(); ++copy) + { + if ((*copy).ptr == nullptr) { - if (std::get<1>(*copy) == nullptr) - { - qDebug() << "remem nullptr" << std::get<2>(*copy).string; - } + qDebug() << "remem nullptr" << (*copy).name.string; } - std::vector> v( - it, twitchEmotes.end()); - twitchEmotes.erase(it, twitchEmotes.end()); - return v; - }; + } + std::vector v(it, twitchEmotes.end()); + twitchEmotes.erase(it, twitchEmotes.end()); + return v; + }; auto shiftIndicesAfter = [&twitchEmotes](int pos, int by) mutable { for (auto &item : twitchEmotes) { - auto &index = std::get<0>(item); + auto &index = item.start; if (index >= pos) { index += by; @@ -717,8 +755,12 @@ void TwitchMessageBuilder::runIgnoreReplaces( { qDebug() << "emote null" << emote.first.string; } - twitchEmotes.push_back(std::tuple{ - startIndex + pos, emote.second, emote.first}); + twitchEmotes.push_back(TwitchEmoteOccurence{ + startIndex + pos, + startIndex + pos + emote.first.string.length(), + emote.second, + emote.first, + }); } } pos += word.length() + 1; @@ -776,13 +818,13 @@ void TwitchMessageBuilder::runIgnoreReplaces( for (auto &tup : vret) { - if (std::get<1>(tup) == nullptr) + if (tup.ptr == nullptr) { - qDebug() << "v nullptr" << std::get<2>(tup).string; + qDebug() << "v nullptr" << tup.name.string; continue; } QRegularExpression emoteregex( - "\\b" + std::get<2>(tup).string + "\\b", + "\\b" + tup.name.string + "\\b", QRegularExpression::UseUnicodePropertiesOption); auto _match = emoteregex.match(midExtendedRef); if (_match.hasMatch()) @@ -790,7 +832,7 @@ void TwitchMessageBuilder::runIgnoreReplaces( int last = _match.lastCapturedIndex(); for (int i = 0; i <= last; ++i) { - std::get<0>(tup) = from + _match.capturedStart(); + tup.start = from + _match.capturedStart(); twitchEmotes.push_back(std::move(tup)); } } @@ -845,13 +887,13 @@ void TwitchMessageBuilder::runIgnoreReplaces( for (auto &tup : vret) { - if (std::get<1>(tup) == nullptr) + if (tup.ptr == nullptr) { - qDebug() << "v nullptr" << std::get<2>(tup).string; + qDebug() << "v nullptr" << tup.name.string; continue; } QRegularExpression emoteregex( - "\\b" + std::get<2>(tup).string + "\\b", + "\\b" + tup.name.string + "\\b", QRegularExpression::UseUnicodePropertiesOption); auto match = emoteregex.match(midExtendedRef); if (match.hasMatch()) @@ -859,7 +901,7 @@ void TwitchMessageBuilder::runIgnoreReplaces( int last = match.lastCapturedIndex(); for (int i = 0; i <= last; ++i) { - std::get<0>(tup) = from + match.capturedStart(); + tup.start = from + match.capturedStart(); twitchEmotes.push_back(std::move(tup)); } } @@ -874,8 +916,7 @@ void TwitchMessageBuilder::runIgnoreReplaces( } void TwitchMessageBuilder::appendTwitchEmote( - const QString &emote, - std::vector> &vec, + const QString &emote, std::vector &vec, std::vector &correctPositions) { auto app = getApp(); @@ -914,13 +955,13 @@ void TwitchMessageBuilder::appendTwitchEmote( auto name = EmoteName{this->originalMessage_.mid(start, end - start + 1)}; - auto tup = std::tuple{ - start, app->emotes->twitch.getOrCreateEmote(id, name), name}; - if (std::get<1>(tup) == nullptr) + TwitchEmoteOccurence emoteOccurence{ + start, end, app->emotes->twitch.getOrCreateEmote(id, name), name}; + if (emoteOccurence.ptr == nullptr) { - qDebug() << "nullptr" << std::get<2>(tup).string; + qDebug() << "nullptr" << emoteOccurence.name.string; } - vec.push_back(std::move(tup)); + vec.push_back(std::move(emoteOccurence)); } } diff --git a/src/providers/twitch/TwitchMessageBuilder.hpp b/src/providers/twitch/TwitchMessageBuilder.hpp index 5bdaebbf4..0da213443 100644 --- a/src/providers/twitch/TwitchMessageBuilder.hpp +++ b/src/providers/twitch/TwitchMessageBuilder.hpp @@ -18,6 +18,13 @@ using EmotePtr = std::shared_ptr; class Channel; class TwitchChannel; +struct TwitchEmoteOccurence { + int start; + int end; + EmotePtr ptr; + EmoteName name; +}; + class TwitchMessageBuilder : public SharedMessageBuilder { public: @@ -52,19 +59,17 @@ private: void parseMessageID(); void parseRoomID(); void appendUsername(); - void runIgnoreReplaces( - std::vector> &twitchEmotes); + + void runIgnoreReplaces(std::vector &twitchEmotes); boost::optional getTwitchBadge(const Badge &badge); - void appendTwitchEmote( - const QString &emote, - std::vector> &vec, - std::vector &correctPositions); + void appendTwitchEmote(const QString &emote, + std::vector &vec, + std::vector &correctPositions); Outcome tryAppendEmote(const EmoteName &name); - void addWords( - const QStringList &words, - const std::vector> &twitchEmotes); + void addWords(const QStringList &words, + const std::vector &twitchEmotes); void addTextOrEmoji(EmotePtr emote) override; void addTextOrEmoji(const QString &value) override; diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index 6076d7755..1affbdba7 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -177,7 +177,8 @@ void Window::addCustomTitlebarButtons() void Window::addDebugStuff() { #ifdef C_DEBUG - std::vector cheerMessages, subMessages, miscMessages, linkMessages; + std::vector cheerMessages, subMessages, miscMessages, linkMessages, + emoteTestMessages; cheerMessages = getSampleCheerMessage(); auto validLinks = getValidLinks(); @@ -222,6 +223,14 @@ void Window::addDebugStuff() const char *channelRewardMessage2 = "{ \"type\": \"MESSAGE\", \"data\": { \"topic\": \"community-points-channel-v1.11148817\", \"message\": { \"type\": \"reward-redeemed\", \"data\": { \"timestamp\": \"2020-07-13T20:19:31.430785354Z\", \"redemption\": { \"id\": \"b9628798-1b4e-4122-b2a6-031658df6755\", \"user\": { \"id\": \"91800084\", \"login\": \"cranken1337\", \"display_name\": \"cranken1337\" }, \"channel_id\": \"11148817\", \"redeemed_at\": \"2020-07-13T20:19:31.345237005Z\", \"reward\": { \"id\": \"313969fe-cc9f-4a0a-83c6-172acbd96957\", \"channel_id\": \"11148817\", \"title\": \"annoying reward pogchamp\", \"prompt\": \"\", \"cost\": 3000, \"is_user_input_required\": false, \"is_sub_only\": false, \"image\": null, \"default_image\": { \"url_1x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-1.png\", \"url_2x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-2.png\", \"url_4x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-4.png\" }, \"background_color\": \"#52ACEC\", \"is_enabled\": true, \"is_paused\": false, \"is_in_stock\": true, \"max_per_stream\": { \"is_enabled\": false, \"max_per_stream\": 0 }, \"should_redemptions_skip_request_queue\": false, \"template_id\": null, \"updated_for_indicator_at\": \"2020-01-20T04:33:33.624956679Z\" }, \"status\": \"UNFULFILLED\", \"cursor\": \"Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo=\" } } } } }"; const char *channelRewardIRCMessage(R"(@badge-info=subscriber/43;badges=subscriber/42;color=#1E90FF;custom-reward-id=313969fe-cc9f-4a0a-83c6-172acbd96957;display-name=Cranken1337;emotes=;flags=;id=3cee3f27-a1d0-44d1-a606-722cebdad08b;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1594756484132;turbo=0;user-id=91800084;user-type= :cranken1337!cranken1337@cranken1337.tmi.twitch.tv PRIVMSG #pajlada :wow, amazing reward)"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/3;badges=subscriber/3;color=#0000FF;display-name=Linkoping;emotes=25:40-44;flags=17-26:S.6;id=744f9c58-b180-4f46-bd9e-b515b5ef75c1;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1566335866017;turbo=0;user-id=91673457;user-type= :linkoping!linkoping@linkoping.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa)"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/1;badges=subscriber/0;color=;display-name=jhoelsc;emotes=301683486:46-58,60-72,74-86/301683544:88-100;flags=0-4:S.6;id=1f1afcdd-d94c-4699-b35f-d214deb1e11a;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1588640587462;turbo=0;user-id=505763008;user-type= :jhoelsc!jhoelsc@jhoelsc.tmi.twitch.tv PRIVMSG #pajlada :pensé que no habría directo que bueno que si staryuukiLove staryuukiLove staryuukiLove staryuukiBits)"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,16-23;flags=;id=97c28382-e8d2-45a0-bb5d-2305fc4ef139;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922036771;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm, Kreygasm)"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:24-28/41:6-13,15-22;flags=;id=5a36536b-a952-43f7-9c41-88c829371b7a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922039721;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm Kappa (no space then space))"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:6-10/1902:12-16/88:18-25;flags=;id=aed9e67e-f8cd-493e-aa6b-da054edd7292;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922042881;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kappa.Keepo.PogChamp.extratext (3 emotes with extra text))"); + emoteTestMessages.emplace_back(R"(@badge-info=;badges=moderator/1,partner/1;color=#5B99FF;display-name=StreamElements;emotes=86:30-39/822112:73-79;flags=22-27:S.5;id=03c3eec9-afd1-4858-a2e0-fccbf6ad8d1a;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1588638345928;turbo=0;user-id=100135110;user-type=mod :streamelements!streamelements@streamelements.tmi.twitch.tv PRIVMSG #pajlada :╔ACTION A LOJA AINDA NÃO ESTÁ PRONTA BibleThump , AGUARDE... NOVIDADES EM BREVE FortOne╔)"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/20;badges=moderator/1,subscriber/12;color=#19E6E6;display-name=randers;emotes=25:39-43;flags=;id=3ea97f01-abb2-4acf-bdb8-f52e79cd0324;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1588837097115;turbo=0;user-id=40286300;user-type=mod :randers!randers@randers.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa)"); + emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,15-22;flags=;id=a3196c7e-be4c-4b49-9c5a-8b8302b50c2a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922213730;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm (no space))"); // clang-format on createWindowShortcut(this, "F6", [=] { @@ -268,6 +277,13 @@ void Window::addDebugStuff() } }); + createWindowShortcut(this, "F11", [=] { + const auto &messages = emoteTestMessages; + static int index = 0; + const auto &msg = messages[index++ % messages.size()]; + getApp()->twitch.server->addFakeMessage(msg); + }); + #endif } // namespace chatterino