[irc] Partially fix IRC colors (#1594)
Doesn't fix #1379 but it is a big step forward. Needs some "real life" testing, but should be good.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||
#include "providers/twitch/TwitchBadges.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchCommon.hpp"
|
||||
#include "providers/twitch/TwitchIrcServer.hpp"
|
||||
#include "singletons/Emotes.hpp"
|
||||
#include "singletons/Resources.hpp"
|
||||
@@ -31,65 +32,27 @@ const QSet<QString> zeroWidthEmotes{
|
||||
"ReinDeer", "CandyCane", "cvMask", "cvHazmat",
|
||||
};
|
||||
|
||||
QColor getRandomColor(const QVariant &userId)
|
||||
{
|
||||
static const std::vector<QColor> twitchUsernameColors = {
|
||||
{255, 0, 0}, // Red
|
||||
{0, 0, 255}, // Blue
|
||||
{0, 255, 0}, // Green
|
||||
{178, 34, 34}, // FireBrick
|
||||
{255, 127, 80}, // Coral
|
||||
{154, 205, 50}, // YellowGreen
|
||||
{255, 69, 0}, // OrangeRed
|
||||
{46, 139, 87}, // SeaGreen
|
||||
{218, 165, 32}, // GoldenRod
|
||||
{210, 105, 30}, // Chocolate
|
||||
{95, 158, 160}, // CadetBlue
|
||||
{30, 144, 255}, // DodgerBlue
|
||||
{255, 105, 180}, // HotPink
|
||||
{138, 43, 226}, // BlueViolet
|
||||
{0, 255, 127}, // SpringGreen
|
||||
};
|
||||
|
||||
bool ok = true;
|
||||
int colorSeed = userId.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
// We were unable to convert the user ID to an integer, this means Twitch has decided to start using non-integer user IDs
|
||||
// Just randomize the users color
|
||||
colorSeed = std::rand();
|
||||
}
|
||||
|
||||
assert(twitchUsernameColors.size() != 0);
|
||||
const auto colorIndex = colorSeed % twitchUsernameColors.size();
|
||||
return twitchUsernameColors[colorIndex];
|
||||
}
|
||||
|
||||
QUrl getFallbackHighlightSound()
|
||||
{
|
||||
using namespace chatterino;
|
||||
|
||||
QString path = getSettings()->pathHighlightSound;
|
||||
bool fileExists = QFileInfo::exists(path) && QFileInfo(path).isFile();
|
||||
|
||||
// Use fallback sound when checkbox is not checked
|
||||
// or custom file doesn't exist
|
||||
if (getSettings()->customHighlightSound && fileExists)
|
||||
{
|
||||
return QUrl::fromLocalFile(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QUrl("qrc:/sounds/ping2.wav");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
namespace {
|
||||
|
||||
QColor getRandomColor(const QVariant &userId)
|
||||
{
|
||||
bool ok = true;
|
||||
int colorSeed = userId.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
// We were unable to convert the user ID to an integer, this means Twitch has decided to start using non-integer user IDs
|
||||
// Just randomize the users color
|
||||
colorSeed = std::rand();
|
||||
}
|
||||
|
||||
const auto colorIndex = colorSeed % TWITCH_USERNAME_COLORS.size();
|
||||
return TWITCH_USERNAME_COLORS[colorIndex];
|
||||
}
|
||||
|
||||
QStringList parseTagList(const QVariantMap &tags, const QString &key)
|
||||
{
|
||||
auto iterator = tags.find(key);
|
||||
@@ -141,13 +104,8 @@ namespace {
|
||||
TwitchMessageBuilder::TwitchMessageBuilder(
|
||||
Channel *_channel, const Communi::IrcPrivateMessage *_ircMessage,
|
||||
const MessageParseArgs &_args)
|
||||
: channel(_channel)
|
||||
: SharedMessageBuilder(_channel, _ircMessage, _args)
|
||||
, twitchChannel(dynamic_cast<TwitchChannel *>(_channel))
|
||||
, ircMessage(_ircMessage)
|
||||
, args(_args)
|
||||
, tags(this->ircMessage->tags())
|
||||
, originalMessage_(_ircMessage->content())
|
||||
, action_(_ircMessage->isAction())
|
||||
{
|
||||
this->usernameColor_ = getApp()->themes->messages.textColors.system;
|
||||
}
|
||||
@@ -155,31 +113,21 @@ TwitchMessageBuilder::TwitchMessageBuilder(
|
||||
TwitchMessageBuilder::TwitchMessageBuilder(
|
||||
Channel *_channel, const Communi::IrcMessage *_ircMessage,
|
||||
const MessageParseArgs &_args, QString content, bool isAction)
|
||||
: channel(_channel)
|
||||
: SharedMessageBuilder(_channel, _ircMessage, _args, content, isAction)
|
||||
, twitchChannel(dynamic_cast<TwitchChannel *>(_channel))
|
||||
, ircMessage(_ircMessage)
|
||||
, args(_args)
|
||||
, tags(this->ircMessage->tags())
|
||||
, originalMessage_(content)
|
||||
, action_(isAction)
|
||||
{
|
||||
this->usernameColor_ = getApp()->themes->messages.textColors.system;
|
||||
}
|
||||
|
||||
bool TwitchMessageBuilder::isIgnored() const
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
// TODO(pajlada): Do we need to check if the phrase is valid first?
|
||||
auto phrases = getCSettings().ignoredMessages.readOnly();
|
||||
for (const auto &phrase : *phrases)
|
||||
if (SharedMessageBuilder::isIgnored())
|
||||
{
|
||||
if (phrase.isBlock() && phrase.isMatch(this->originalMessage_))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
if (getSettings()->enableTwitchIgnoredUsers &&
|
||||
this->tags.contains("user-id"))
|
||||
{
|
||||
@@ -214,75 +162,29 @@ bool TwitchMessageBuilder::isIgnored() const
|
||||
return false;
|
||||
}
|
||||
|
||||
inline QMediaPlayer *getPlayer()
|
||||
{
|
||||
if (isGuiThread())
|
||||
{
|
||||
static auto player = new QMediaPlayer;
|
||||
return player;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::triggerHighlights()
|
||||
{
|
||||
static QUrl currentPlayerUrl;
|
||||
|
||||
if (this->historicalMessage_)
|
||||
{
|
||||
// Do nothing. Highlights should not be triggered on historical messages.
|
||||
return;
|
||||
}
|
||||
|
||||
if (getCSettings().isMutedChannel(this->channel->getName()))
|
||||
{
|
||||
// Do nothing. Pings are muted in this channel.
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasFocus = (QApplication::focusWidget() != nullptr);
|
||||
bool resolveFocus = !hasFocus || getSettings()->highlightAlwaysPlaySound;
|
||||
|
||||
if (this->highlightSound_ && resolveFocus)
|
||||
{
|
||||
if (auto player = getPlayer())
|
||||
{
|
||||
// update the media player url if necessary
|
||||
if (currentPlayerUrl != this->highlightSoundUrl_)
|
||||
{
|
||||
player->setMedia(this->highlightSoundUrl_);
|
||||
|
||||
currentPlayerUrl = this->highlightSoundUrl_;
|
||||
}
|
||||
|
||||
player->play();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->highlightAlert_)
|
||||
{
|
||||
getApp()->windows->sendAlert();
|
||||
}
|
||||
SharedMessageBuilder::triggerHighlights();
|
||||
}
|
||||
|
||||
MessagePtr TwitchMessageBuilder::build()
|
||||
{
|
||||
// PARSING
|
||||
// PARSE
|
||||
this->userId_ = this->ircMessage->tag("user-id").toString();
|
||||
|
||||
this->parseUsername();
|
||||
this->parse();
|
||||
|
||||
if (this->userName == this->channel->getName())
|
||||
{
|
||||
this->senderIsBroadcaster = true;
|
||||
}
|
||||
|
||||
this->message().flags.set(MessageFlag::Collapsed);
|
||||
|
||||
// PARSING
|
||||
this->parseMessageID();
|
||||
|
||||
this->parseRoomID();
|
||||
@@ -479,7 +381,7 @@ void TwitchMessageBuilder::addWords(
|
||||
|
||||
void TwitchMessageBuilder::addTextOrEmoji(EmotePtr emote)
|
||||
{
|
||||
this->emplace<EmoteElement>(emote, MessageElementFlag::EmojiAll);
|
||||
return SharedMessageBuilder::addTextOrEmoji(emote);
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
|
||||
@@ -528,40 +430,6 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
|
||||
{
|
||||
this->addLink(string, linkString);
|
||||
}
|
||||
|
||||
// if (!linkString.isEmpty()) {
|
||||
// if (getSettings()->lowercaseLink) {
|
||||
// QRegularExpression httpRegex("\\bhttps?://",
|
||||
// QRegularExpression::CaseInsensitiveOption); QRegularExpression
|
||||
// ftpRegex("\\bftps?://",
|
||||
// QRegularExpression::CaseInsensitiveOption); QRegularExpression
|
||||
// getDomain("\\/\\/([^\\/]*)"); QString tempString = string;
|
||||
|
||||
// if (!string.contains(httpRegex)) {
|
||||
// if (!string.contains(ftpRegex)) {
|
||||
// tempString.insert(0, "http://");
|
||||
// }
|
||||
// }
|
||||
// QString domain = getDomain.match(tempString).captured(1);
|
||||
// string.replace(domain, domain.toLower());
|
||||
// }
|
||||
// link = Link(Link::Url, linkString);
|
||||
// textColor = MessageColor(MessageColor::Link);
|
||||
//}
|
||||
// if (string.startsWith('@')) {
|
||||
// this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
|
||||
// textColor,
|
||||
// FontStyle::ChatMediumBold) //
|
||||
// ->setLink(link);
|
||||
// this->emplace<TextElement>(string,
|
||||
// MessageElementFlag::NonBoldUsername,
|
||||
// textColor) //
|
||||
// ->setLink(link);
|
||||
//} else {
|
||||
// this->emplace<TextElement>(string, MessageElementFlag::Text,
|
||||
// textColor) //
|
||||
// ->setLink(link);
|
||||
//}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::parseMessageID()
|
||||
@@ -594,16 +462,6 @@ void TwitchMessageBuilder::parseRoomID()
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::appendChannelName()
|
||||
{
|
||||
QString channelName("#" + this->channel->getName());
|
||||
Link link(Link::Url, this->channel->getName() + "\n" + this->message().id);
|
||||
|
||||
this->emplace<TextElement>(channelName, MessageElementFlag::ChannelName,
|
||||
MessageColor::System) //
|
||||
->setLink(link);
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::parseUsernameColor()
|
||||
{
|
||||
const auto iterator = this->tags.find("color");
|
||||
@@ -624,10 +482,7 @@ void TwitchMessageBuilder::parseUsernameColor()
|
||||
|
||||
void TwitchMessageBuilder::parseUsername()
|
||||
{
|
||||
this->parseUsernameColor();
|
||||
|
||||
// username
|
||||
this->userName = this->ircMessage->nick();
|
||||
SharedMessageBuilder::parseUsername();
|
||||
|
||||
if (this->userName.isEmpty() || this->args.trimSubscriberUsername)
|
||||
{
|
||||
@@ -983,193 +838,6 @@ void TwitchMessageBuilder::runIgnoreReplaces(
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::parseHighlights()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
if (this->message().flags.has(MessageFlag::Subscription) &&
|
||||
getSettings()->enableSubHighlight)
|
||||
{
|
||||
if (getSettings()->enableSubHighlightTaskbar)
|
||||
{
|
||||
this->highlightAlert_ = true;
|
||||
}
|
||||
|
||||
if (getSettings()->enableSubHighlightSound)
|
||||
{
|
||||
this->highlightSound_ = true;
|
||||
|
||||
// Use custom sound if set, otherwise use fallback
|
||||
if (!getSettings()->subHighlightSoundUrl.getValue().isEmpty())
|
||||
{
|
||||
this->highlightSoundUrl_ =
|
||||
QUrl(getSettings()->subHighlightSoundUrl.getValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->highlightSoundUrl_ = getFallbackHighlightSound();
|
||||
}
|
||||
}
|
||||
|
||||
this->message().flags.set(MessageFlag::Highlighted);
|
||||
this->message().highlightColor =
|
||||
ColorProvider::instance().color(ColorType::Subscription);
|
||||
|
||||
// This message was a subscription.
|
||||
// Don't check for any other highlight phrases.
|
||||
return;
|
||||
}
|
||||
|
||||
auto currentUser = app->accounts->twitch.getCurrent();
|
||||
|
||||
QString currentUsername = currentUser->getUserName();
|
||||
|
||||
if (getCSettings().isBlacklistedUser(this->ircMessage->nick()))
|
||||
{
|
||||
// Do nothing. We ignore highlights from this user.
|
||||
return;
|
||||
}
|
||||
|
||||
// Highlight because it's a whisper
|
||||
if (this->args.isReceivedWhisper && getSettings()->enableWhisperHighlight)
|
||||
{
|
||||
if (getSettings()->enableWhisperHighlightTaskbar)
|
||||
{
|
||||
this->highlightAlert_ = true;
|
||||
}
|
||||
|
||||
if (getSettings()->enableWhisperHighlightSound)
|
||||
{
|
||||
this->highlightSound_ = true;
|
||||
|
||||
// Use custom sound if set, otherwise use fallback
|
||||
if (!getSettings()->whisperHighlightSoundUrl.getValue().isEmpty())
|
||||
{
|
||||
this->highlightSoundUrl_ =
|
||||
QUrl(getSettings()->whisperHighlightSoundUrl.getValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->highlightSoundUrl_ = getFallbackHighlightSound();
|
||||
}
|
||||
}
|
||||
|
||||
this->message().highlightColor =
|
||||
ColorProvider::instance().color(ColorType::Whisper);
|
||||
|
||||
/*
|
||||
* Do _NOT_ return yet, we might want to apply phrase/user name
|
||||
* highlights (which override whisper color/sound).
|
||||
*/
|
||||
}
|
||||
|
||||
// Highlight because of sender
|
||||
auto userHighlights = getCSettings().highlightedUsers.readOnly();
|
||||
for (const HighlightPhrase &userHighlight : *userHighlights)
|
||||
{
|
||||
if (!userHighlight.isMatch(this->ircMessage->nick()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this->message().flags.set(MessageFlag::Highlighted);
|
||||
this->message().highlightColor = userHighlight.getColor();
|
||||
|
||||
if (userHighlight.hasAlert())
|
||||
{
|
||||
this->highlightAlert_ = true;
|
||||
}
|
||||
|
||||
if (userHighlight.hasSound())
|
||||
{
|
||||
this->highlightSound_ = true;
|
||||
// Use custom sound if set, otherwise use the fallback sound
|
||||
if (userHighlight.hasCustomSound())
|
||||
{
|
||||
this->highlightSoundUrl_ = userHighlight.getSoundUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->highlightSoundUrl_ = getFallbackHighlightSound();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->highlightAlert_ && this->highlightSound_)
|
||||
{
|
||||
/*
|
||||
* User name highlights "beat" highlight phrases: If a message has
|
||||
* all attributes (color, taskbar flashing, sound) set, highlight
|
||||
* phrases will not be checked.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->ircMessage->nick() == currentUsername)
|
||||
{
|
||||
// Do nothing. Highlights cannot be triggered by yourself
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: This vector should only be rebuilt upon highlights being changed
|
||||
// fourtf: should be implemented in the HighlightsController
|
||||
std::vector<HighlightPhrase> activeHighlights =
|
||||
getSettings()->highlightedMessages.cloneVector();
|
||||
|
||||
if (getSettings()->enableSelfHighlight && currentUsername.size() > 0)
|
||||
{
|
||||
HighlightPhrase selfHighlight(
|
||||
currentUsername, getSettings()->enableSelfHighlightTaskbar,
|
||||
getSettings()->enableSelfHighlightSound, false, false,
|
||||
getSettings()->selfHighlightSoundUrl.getValue(),
|
||||
ColorProvider::instance().color(ColorType::SelfHighlight));
|
||||
activeHighlights.emplace_back(std::move(selfHighlight));
|
||||
}
|
||||
|
||||
// Highlight because of message
|
||||
for (const HighlightPhrase &highlight : activeHighlights)
|
||||
{
|
||||
if (!highlight.isMatch(this->originalMessage_))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this->message().flags.set(MessageFlag::Highlighted);
|
||||
this->message().highlightColor = highlight.getColor();
|
||||
|
||||
if (highlight.hasAlert())
|
||||
{
|
||||
this->highlightAlert_ = true;
|
||||
}
|
||||
|
||||
// Only set highlightSound_ if it hasn't been set by username
|
||||
// highlights already.
|
||||
if (highlight.hasSound() && !this->highlightSound_)
|
||||
{
|
||||
this->highlightSound_ = true;
|
||||
|
||||
// Use custom sound if set, otherwise use fallback sound
|
||||
if (highlight.hasCustomSound())
|
||||
{
|
||||
this->highlightSoundUrl_ = highlight.getSoundUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->highlightSoundUrl_ = getFallbackHighlightSound();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->highlightAlert_ && this->highlightSound_)
|
||||
{
|
||||
/*
|
||||
* Break once no further attributes (taskbar, sound) can be
|
||||
* applied.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::appendTwitchEmote(
|
||||
const QString &emote,
|
||||
std::vector<std::tuple<int, EmotePtr, EmoteName>> &vec,
|
||||
|
||||
Reference in New Issue
Block a user