From 2f534dc6dabe84c002ca4e54325a779a596980e9 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 30 Mar 2024 14:24:47 +0100 Subject: [PATCH] fix: override broken base sizes & scales for some Twitch emotes (#5279) --- CHANGELOG.md | 1 + src/providers/twitch/TwitchEmotes.cpp | 407 +++++++++++++++++++++++++- src/providers/twitch/TwitchEmotes.hpp | 1 - 3 files changed, 398 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b82b51b8a..b3b0c0500 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -104,6 +104,7 @@ - Bugfix: Fixed popup windows not persisting between restarts. (#5081) - Bugfix: Fixed splits not retaining their focus after minimizing. (#5080) - Bugfix: Fixed _Copy message_ copying the channel name in global search. (#5106) +- Bugfix: Fixed some Twitch emotes sizes being wrong at certain zoom levels. (#5279) - Bugfix: Fixed a missing space when the image uploader provided a delete link. (#5269) - Bugfix: Reply contexts now use the color of the replied-to message. (#5145) - Bugfix: Fixed top-level window getting stuck after opening settings. (#5161, #5166) diff --git a/src/providers/twitch/TwitchEmotes.cpp b/src/providers/twitch/TwitchEmotes.cpp index 4c87e472b..918d504a4 100644 --- a/src/providers/twitch/TwitchEmotes.cpp +++ b/src/providers/twitch/TwitchEmotes.cpp @@ -5,6 +5,400 @@ #include "messages/Image.hpp" #include "util/QStringHash.hpp" +namespace { + +using namespace chatterino; + +Url getEmoteLink(const EmoteId &id, const QString &emoteScale) +{ + return {QString(TWITCH_EMOTE_TEMPLATE) + .replace("{id}", id.string) + .replace("{scale}", emoteScale)}; +} + +QSize getEmoteExpectedBaseSize(const EmoteId &id) +{ + // From Twitch docs - expected size for an emote (1x) + constexpr QSize defaultBaseSize(28, 28); + static std::unordered_map outliers{ + {"555555635", {21, 18}}, /* ;p */ + {"555555636", {21, 18}}, /* ;-p */ + {"555555614", {21, 18}}, /* O_o */ + {"555555641", {21, 18}}, /* :z */ + {"555555604", {21, 18}}, /* :\\ */ + {"444", {21, 18}}, /* :| */ + {"555555634", {21, 18}}, /* ;-P */ + {"439", {21, 18}}, /* ;) */ + {"555555642", {21, 18}}, /* :-z */ + {"555555613", {21, 18}}, /* :-o */ + {"555555625", {21, 18}}, /* :-p */ + {"433", {21, 18}}, /* :/ */ + {"555555622", {21, 18}}, /* :P */ + {"555555640", {21, 18}}, /* :-| */ + {"555555623", {21, 18}}, /* :-P */ + {"555555628", {21, 18}}, /* :) */ + {"555555632", {21, 18}}, /* 8-) */ + {"555555667", {20, 18}}, /* ;p */ + {"445", {21, 18}}, /* <3 */ + {"555555668", {20, 18}}, /* ;-p */ + {"555555679", {20, 18}}, /* :z */ + {"483", {20, 18}}, /* <3 */ + {"555555666", {20, 18}}, /* ;-P */ + {"497", {20, 18}}, /* O_o */ + {"555555664", {20, 18}}, /* :-p */ + {"555555671", {20, 18}}, /* :o */ + {"555555681", {20, 18}}, /* :Z */ + {"555555672", {20, 18}}, /* :-o */ + {"555555676", {20, 18}}, /* :-\\ */ + {"555555611", {21, 18}}, /* :-O */ + {"555555670", {20, 18}}, /* :-O */ + {"555555688", {20, 18}}, /* :-D */ + {"441", {21, 18}}, /* B) */ + {"555555601", {21, 18}}, /* >( */ + {"491", {20, 18}}, /* ;P */ + {"496", {20, 18}}, /* :D */ + {"492", {20, 18}}, /* :O */ + {"555555573", {24, 18}}, /* o_O */ + {"555555643", {21, 18}}, /* :Z */ + {"1898", {26, 28}}, /* ThunBeast */ + {"555555682", {20, 18}}, /* :-Z */ + {"1896", {20, 30}}, /* WholeWheat */ + {"1906", {24, 30}}, /* SoBayed */ + {"555555607", {21, 18}}, /* :-( */ + {"555555660", {20, 18}}, /* :-( */ + {"489", {20, 18}}, /* :( */ + {"495", {20, 18}}, /* :s */ + {"555555638", {21, 18}}, /* :-D */ + {"357", {28, 30}}, /* HotPokket */ + {"555555624", {21, 18}}, /* :p */ + {"73", {21, 30}}, /* DBstyle */ + {"555555674", {20, 18}}, /* :-/ */ + {"555555629", {21, 18}}, /* :-) */ + {"555555600", {24, 18}}, /* R-) */ + {"41", {19, 27}}, /* Kreygasm */ + {"555555612", {21, 18}}, /* :o */ + {"488", {29, 24}}, /* :7 */ + {"69", {41, 28}}, /* BloodTrail */ + {"555555608", {21, 18}}, /* R) */ + {"501", {20, 18}}, /* ;) */ + {"50", {18, 27}}, /* ArsonNoSexy */ + {"443", {21, 18}}, /* :D */ + {"1904", {24, 30}}, /* BigBrother */ + {"555555595", {24, 18}}, /* ;P */ + {"555555663", {20, 18}}, /* :p */ + {"555555576", {24, 18}}, /* o.o */ + {"360", {22, 30}}, /* FailFish */ + {"500", {20, 18}}, /* B) */ + {"3", {24, 18}}, /* :D */ + {"484", {20, 22}}, /* R) */ + {"555555678", {20, 18}}, /* :-| */ + {"7", {24, 18}}, /* B) */ + {"52", {32, 32}}, /* SMOrc */ + {"555555644", {21, 18}}, /* :-Z */ + {"18", {20, 27}}, /* TheRinger */ + {"49106", {27, 28}}, /* CorgiDerp */ + {"6", {24, 18}}, /* O_o */ + {"10", {24, 18}}, /* :/ */ + {"47", {24, 24}}, /* PunchTrees */ + {"555555561", {24, 18}}, /* :-D */ + {"555555564", {24, 18}}, /* :-| */ + {"13", {24, 18}}, /* ;P */ + {"555555593", {24, 18}}, /* :p */ + {"555555589", {24, 18}}, /* ;) */ + {"555555590", {24, 18}}, /* ;-) */ + {"486", {27, 42}}, /* :> */ + {"40", {21, 27}}, /* KevinTurtle */ + {"555555558", {24, 18}}, /* :( */ + {"555555597", {24, 18}}, /* ;p */ + {"555555580", {24, 18}}, /* :O */ + {"555555567", {24, 18}}, /* :Z */ + {"1", {24, 18}}, /* :) */ + {"11", {24, 18}}, /* ;) */ + {"33", {25, 32}}, /* DansGame */ + {"555555586", {24, 18}}, /* :-/ */ + {"4", {24, 18}}, /* >( */ + {"555555588", {24, 18}}, /* :-\\ */ + {"12", {24, 18}}, /* :P */ + {"555555563", {24, 18}}, /* :| */ + {"555555581", {24, 18}}, /* :-O */ + {"555555598", {24, 18}}, /* ;-p */ + {"555555596", {24, 18}}, /* ;-P */ + {"555555557", {24, 18}}, /* :-) */ + {"498", {20, 18}}, /* >( */ + {"555555680", {20, 18}}, /* :-z */ + {"555555587", {24, 18}}, /* :\\ */ + {"5", {24, 18}}, /* :| */ + {"354", {20, 30}}, /* 4Head */ + {"555555562", {24, 18}}, /* >( */ + {"555555594", {24, 18}}, /* :-p */ + {"490", {20, 18}}, /* :P */ + {"555555662", {20, 18}}, /* :-P */ + {"2", {24, 18}}, /* :( */ + {"1902", {27, 29}}, /* Keepo */ + {"555555627", {21, 18}}, /* ;-) */ + {"555555566", {24, 18}}, /* :-z */ + {"555555559", {24, 18}}, /* :-( */ + {"555555592", {24, 18}}, /* :-P */ + {"28", {39, 27}}, /* MrDestructoid */ + {"8", {24, 18}}, /* :O */ + {"244", {24, 30}}, /* FUNgineer */ + {"555555591", {24, 18}}, /* :P */ + {"555555585", {24, 18}}, /* :/ */ + {"494", {20, 18}}, /* :| */ + {"9", {24, 18}}, /* <3 */ + {"555555584", {24, 18}}, /* <3 */ + {"555555579", {24, 18}}, /* 8-) */ + {"14", {24, 18}}, /* R) */ + {"485", {27, 18}}, /* #/ */ + {"555555560", {24, 18}}, /* :D */ + {"86", {36, 30}}, /* BibleThump */ + {"555555578", {24, 18}}, /* B-) */ + {"17", {20, 27}}, /* StoneLightning */ + {"436", {21, 18}}, /* :O */ + {"555555675", {20, 18}}, /* :\\ */ + {"22", {19, 27}}, /* RedCoat */ + {"555555574", {24, 18}}, /* o.O */ + {"555555603", {21, 18}}, /* :-/ */ + {"1901", {24, 28}}, /* Kippa */ + {"15", {21, 27}}, /* JKanStyle */ + {"555555605", {21, 18}}, /* :-\\ */ + {"555555701", {20, 18}}, /* ;-) */ + {"487", {20, 42}}, /* <] */ + {"555555572", {24, 18}}, /* O.O */ + {"65", {40, 30}}, /* FrankerZ */ + {"25", {25, 28}}, /* Kappa */ + {"36", {36, 30}}, /* PJSalt */ + {"499", {20, 18}}, /* :) */ + {"555555565", {24, 18}}, /* :z */ + {"434", {21, 18}}, /* :( */ + {"555555577", {24, 18}}, /* B) */ + {"34", {21, 28}}, /* SwiftRage */ + {"555555575", {24, 18}}, /* o_o */ + {"92", {23, 30}}, /* PMSTwin */ + {"555555570", {24, 18}}, /* O.o */ + {"555555569", {24, 18}}, /* O_o */ + {"493", {20, 18}}, /* :/ */ + {"26", {20, 27}}, /* JonCarnage */ + {"66", {20, 27}}, /* OneHand */ + {"555555568", {24, 18}}, /* :-Z */ + {"555555599", {24, 18}}, /* R) */ + {"1900", {33, 30}}, /* RalpherZ */ + {"555555582", {24, 18}}, /* :o */ + {"1899", {22, 30}}, /* TF2John */ + {"555555633", {21, 18}}, /* ;P */ + {"16", {22, 27}}, /* OptimizePrime */ + {"30", {29, 27}}, /* BCWarrior */ + {"555555583", {24, 18}}, /* :-o */ + {"32", {21, 27}}, /* GingerPower */ + {"87", {24, 30}}, /* ShazBotstix */ + {"74", {24, 30}}, /* AsianGlow */ + {"555555571", {24, 18}}, /* O_O */ + {"46", {24, 24}}, /* SSSsss */ + }; + + auto it = outliers.find(id.string); + if (it != outliers.end()) + { + return it->second; + } + + return defaultBaseSize; +} + +qreal getEmote3xScaleFactor(const EmoteId &id) +{ + // From Twitch docs - expected size for an emote (1x) + constexpr qreal default3xScaleFactor = 0.25; + static std::unordered_map outliers{ + {"555555635", 0.3333333333333333}, /* ;p */ + {"555555636", 0.3333333333333333}, /* ;-p */ + {"555555614", 0.3333333333333333}, /* O_o */ + {"555555641", 0.3333333333333333}, /* :z */ + {"555555604", 0.3333333333333333}, /* :\\ */ + {"444", 0.3333333333333333}, /* :| */ + {"555555634", 0.3333333333333333}, /* ;-P */ + {"439", 0.3333333333333333}, /* ;) */ + {"555555642", 0.3333333333333333}, /* :-z */ + {"555555613", 0.3333333333333333}, /* :-o */ + {"555555625", 0.3333333333333333}, /* :-p */ + {"433", 0.3333333333333333}, /* :/ */ + {"555555622", 0.3333333333333333}, /* :P */ + {"555555640", 0.3333333333333333}, /* :-| */ + {"555555623", 0.3333333333333333}, /* :-P */ + {"555555628", 0.3333333333333333}, /* :) */ + {"555555632", 0.3333333333333333}, /* 8-) */ + {"555555667", 0.3333333333333333}, /* ;p */ + {"445", 0.3333333333333333}, /* <3 */ + {"555555668", 0.3333333333333333}, /* ;-p */ + {"555555679", 0.3333333333333333}, /* :z */ + {"483", 0.3333333333333333}, /* <3 */ + {"555555666", 0.3333333333333333}, /* ;-P */ + {"497", 0.3333333333333333}, /* O_o */ + {"555555664", 0.3333333333333333}, /* :-p */ + {"555555671", 0.3333333333333333}, /* :o */ + {"555555681", 0.3333333333333333}, /* :Z */ + {"555555672", 0.3333333333333333}, /* :-o */ + {"555555676", 0.3333333333333333}, /* :-\\ */ + {"555555611", 0.3333333333333333}, /* :-O */ + {"555555670", 0.3333333333333333}, /* :-O */ + {"555555688", 0.3333333333333333}, /* :-D */ + {"441", 0.3333333333333333}, /* B) */ + {"555555601", 0.3333333333333333}, /* >( */ + {"491", 0.3333333333333333}, /* ;P */ + {"496", 0.3333333333333333}, /* :D */ + {"492", 0.3333333333333333}, /* :O */ + {"555555573", 0.3333333333333333}, /* o_O */ + {"555555643", 0.3333333333333333}, /* :Z */ + {"1898", 0.3333333333333333}, /* ThunBeast */ + {"555555682", 0.3333333333333333}, /* :-Z */ + {"1896", 0.3333333333333333}, /* WholeWheat */ + {"1906", 0.3333333333333333}, /* SoBayed */ + {"555555607", 0.3333333333333333}, /* :-( */ + {"555555660", 0.3333333333333333}, /* :-( */ + {"489", 0.3333333333333333}, /* :( */ + {"495", 0.3333333333333333}, /* :s */ + {"555555638", 0.3333333333333333}, /* :-D */ + {"357", 0.3333333333333333}, /* HotPokket */ + {"555555624", 0.3333333333333333}, /* :p */ + {"73", 0.3333333333333333}, /* DBstyle */ + {"555555674", 0.3333333333333333}, /* :-/ */ + {"555555629", 0.3333333333333333}, /* :-) */ + {"555555600", 0.3333333333333333}, /* R-) */ + {"41", 0.3333333333333333}, /* Kreygasm */ + {"555555612", 0.3333333333333333}, /* :o */ + {"488", 0.3333333333333333}, /* :7 */ + {"69", 0.3333333333333333}, /* BloodTrail */ + {"555555608", 0.3333333333333333}, /* R) */ + {"501", 0.3333333333333333}, /* ;) */ + {"50", 0.3333333333333333}, /* ArsonNoSexy */ + {"443", 0.3333333333333333}, /* :D */ + {"1904", 0.3333333333333333}, /* BigBrother */ + {"555555595", 0.3333333333333333}, /* ;P */ + {"555555663", 0.3333333333333333}, /* :p */ + {"555555576", 0.3333333333333333}, /* o.o */ + {"360", 0.3333333333333333}, /* FailFish */ + {"500", 0.3333333333333333}, /* B) */ + {"3", 0.3333333333333333}, /* :D */ + {"484", 0.3333333333333333}, /* R) */ + {"555555678", 0.3333333333333333}, /* :-| */ + {"7", 0.3333333333333333}, /* B) */ + {"52", 0.3333333333333333}, /* SMOrc */ + {"555555644", 0.3333333333333333}, /* :-Z */ + {"18", 0.3333333333333333}, /* TheRinger */ + {"49106", 0.3333333333333333}, /* CorgiDerp */ + {"6", 0.3333333333333333}, /* O_o */ + {"10", 0.3333333333333333}, /* :/ */ + {"47", 0.3333333333333333}, /* PunchTrees */ + {"555555561", 0.3333333333333333}, /* :-D */ + {"555555564", 0.3333333333333333}, /* :-| */ + {"13", 0.3333333333333333}, /* ;P */ + {"555555593", 0.3333333333333333}, /* :p */ + {"555555589", 0.3333333333333333}, /* ;) */ + {"555555590", 0.3333333333333333}, /* ;-) */ + {"486", 0.3333333333333333}, /* :> */ + {"40", 0.3333333333333333}, /* KevinTurtle */ + {"555555558", 0.3333333333333333}, /* :( */ + {"555555597", 0.3333333333333333}, /* ;p */ + {"555555580", 0.3333333333333333}, /* :O */ + {"555555567", 0.3333333333333333}, /* :Z */ + {"1", 0.3333333333333333}, /* :) */ + {"11", 0.3333333333333333}, /* ;) */ + {"33", 0.3333333333333333}, /* DansGame */ + {"555555586", 0.3333333333333333}, /* :-/ */ + {"4", 0.3333333333333333}, /* >( */ + {"555555588", 0.3333333333333333}, /* :-\\ */ + {"12", 0.3333333333333333}, /* :P */ + {"555555563", 0.3333333333333333}, /* :| */ + {"555555581", 0.3333333333333333}, /* :-O */ + {"555555598", 0.3333333333333333}, /* ;-p */ + {"555555596", 0.3333333333333333}, /* ;-P */ + {"555555557", 0.3333333333333333}, /* :-) */ + {"498", 0.3333333333333333}, /* >( */ + {"555555680", 0.3333333333333333}, /* :-z */ + {"555555587", 0.3333333333333333}, /* :\\ */ + {"5", 0.3333333333333333}, /* :| */ + {"354", 0.3333333333333333}, /* 4Head */ + {"555555562", 0.3333333333333333}, /* >( */ + {"555555594", 0.3333333333333333}, /* :-p */ + {"490", 0.3333333333333333}, /* :P */ + {"555555662", 0.3333333333333333}, /* :-P */ + {"2", 0.3333333333333333}, /* :( */ + {"1902", 0.3333333333333333}, /* Keepo */ + {"555555627", 0.3333333333333333}, /* ;-) */ + {"555555566", 0.3333333333333333}, /* :-z */ + {"555555559", 0.3333333333333333}, /* :-( */ + {"555555592", 0.3333333333333333}, /* :-P */ + {"28", 0.3333333333333333}, /* MrDestructoid */ + {"8", 0.3333333333333333}, /* :O */ + {"244", 0.3333333333333333}, /* FUNgineer */ + {"555555591", 0.3333333333333333}, /* :P */ + {"555555585", 0.3333333333333333}, /* :/ */ + {"494", 0.3333333333333333}, /* :| */ + {"9", 0.21428571428571427}, /* <3 */ + {"555555584", 0.21428571428571427}, /* <3 */ + {"555555579", 0.3333333333333333}, /* 8-) */ + {"14", 0.3333333333333333}, /* R) */ + {"485", 0.3333333333333333}, /* #/ */ + {"555555560", 0.3333333333333333}, /* :D */ + {"86", 0.3333333333333333}, /* BibleThump */ + {"555555578", 0.3333333333333333}, /* B-) */ + {"17", 0.3333333333333333}, /* StoneLightning */ + {"436", 0.3333333333333333}, /* :O */ + {"555555675", 0.3333333333333333}, /* :\\ */ + {"22", 0.3333333333333333}, /* RedCoat */ + {"245", 0.3333333333333333}, /* ResidentSleeper */ + {"555555574", 0.3333333333333333}, /* o.O */ + {"555555603", 0.3333333333333333}, /* :-/ */ + {"1901", 0.3333333333333333}, /* Kippa */ + {"15", 0.3333333333333333}, /* JKanStyle */ + {"555555605", 0.3333333333333333}, /* :-\\ */ + {"555555701", 0.3333333333333333}, /* ;-) */ + {"487", 0.3333333333333333}, /* <] */ + {"22639", 0.3333333333333333}, /* BabyRage */ + {"555555572", 0.3333333333333333}, /* O.O */ + {"65", 0.3333333333333333}, /* FrankerZ */ + {"25", 0.3333333333333333}, /* Kappa */ + {"36", 0.3333333333333333}, /* PJSalt */ + {"499", 0.3333333333333333}, /* :) */ + {"555555565", 0.3333333333333333}, /* :z */ + {"434", 0.3333333333333333}, /* :( */ + {"555555577", 0.3333333333333333}, /* B) */ + {"34", 0.3333333333333333}, /* SwiftRage */ + {"555555575", 0.3333333333333333}, /* o_o */ + {"92", 0.3333333333333333}, /* PMSTwin */ + {"555555570", 0.3333333333333333}, /* O.o */ + {"555555569", 0.3333333333333333}, /* O_o */ + {"493", 0.3333333333333333}, /* :/ */ + {"26", 0.3333333333333333}, /* JonCarnage */ + {"66", 0.3333333333333333}, /* OneHand */ + {"973", 0.3333333333333333}, /* DAESuppy */ + {"555555568", 0.3333333333333333}, /* :-Z */ + {"555555599", 0.3333333333333333}, /* R) */ + {"1900", 0.3333333333333333}, /* RalpherZ */ + {"555555582", 0.3333333333333333}, /* :o */ + {"1899", 0.3333333333333333}, /* TF2John */ + {"555555633", 0.3333333333333333}, /* ;P */ + {"16", 0.3333333333333333}, /* OptimizePrime */ + {"30", 0.3333333333333333}, /* BCWarrior */ + {"555555583", 0.3333333333333333}, /* :-o */ + {"32", 0.3333333333333333}, /* GingerPower */ + {"87", 0.3333333333333333}, /* ShazBotstix */ + {"74", 0.3333333333333333}, /* AsianGlow */ + {"555555571", 0.3333333333333333}, /* O_O */ + {"46", 0.3333333333333333}, /* SSSsss */ + }; + + auto it = outliers.find(id.string); + if (it != outliers.end()) + { + return it->second; + } + + return default3xScaleFactor; +} + +} // namespace + namespace chatterino { QString TwitchEmotes::cleanUpEmoteCode(const QString &dirtyEmoteCode) @@ -44,14 +438,14 @@ EmotePtr TwitchEmotes::getOrCreateEmote(const EmoteId &id, if (!shared) { - // From Twitch docs - expected size for an emote (1x) - constexpr QSize baseSize(28, 28); + auto baseSize = getEmoteExpectedBaseSize(id); (*cache)[id] = shared = std::make_shared(Emote{ EmoteName{name}, ImageSet{ Image::fromUrl(getEmoteLink(id, "1.0"), 1, baseSize), Image::fromUrl(getEmoteLink(id, "2.0"), 0.5, baseSize * 2), - Image::fromUrl(getEmoteLink(id, "3.0"), 0.25, baseSize * 4), + Image::fromUrl(getEmoteLink(id, "3.0"), + getEmote3xScaleFactor(id), baseSize * 4), }, Tooltip{name.toHtmlEscaped() + "
Twitch Emote"}, }); @@ -60,11 +454,4 @@ EmotePtr TwitchEmotes::getOrCreateEmote(const EmoteId &id, return shared; } -Url TwitchEmotes::getEmoteLink(const EmoteId &id, const QString &emoteScale) -{ - return {QString(TWITCH_EMOTE_TEMPLATE) - .replace("{id}", id.string) - .replace("{scale}", emoteScale)}; -} - } // namespace chatterino diff --git a/src/providers/twitch/TwitchEmotes.hpp b/src/providers/twitch/TwitchEmotes.hpp index d793ce723..17e50b11f 100644 --- a/src/providers/twitch/TwitchEmotes.hpp +++ b/src/providers/twitch/TwitchEmotes.hpp @@ -52,7 +52,6 @@ public: const EmoteName &name) override; private: - Url getEmoteLink(const EmoteId &id, const QString &emoteScale); UniqueAccess>> twitchEmotesCache_; };