Makes it possible to hide one man spam (#1496)

This commit is contained in:
hemirt 2020-02-02 14:31:37 +01:00 committed by GitHub
parent 497ce2d2f2
commit 1fd64be7f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 164 additions and 1 deletions

View file

@ -3,6 +3,7 @@
#include "Application.hpp" #include "Application.hpp"
#include "messages/Message.hpp" #include "messages/Message.hpp"
#include "messages/MessageBuilder.hpp" #include "messages/MessageBuilder.hpp"
#include "providers/twitch/IrcMessageHandler.hpp"
#include "singletons/Emotes.hpp" #include "singletons/Emotes.hpp"
#include "singletons/Logging.hpp" #include "singletons/Logging.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"

View file

@ -33,6 +33,7 @@ enum class MessageFlag : uint32_t {
Whisper = (1 << 16), Whisper = (1 << 16),
HighlightedWhisper = (1 << 17), HighlightedWhisper = (1 << 17),
Debug = (1 << 18), Debug = (1 << 18),
Similar = (1 << 19),
}; };
using MessageFlags = FlagsEnum<MessageFlag>; using MessageFlags = FlagsEnum<MessageFlag>;

View file

@ -141,6 +141,12 @@ void MessageLayout::actuallyLayout(int width, MessageElementFlags flags)
continue; continue;
} }
if (getSettings()->hideSimilar &&
this->message_->flags.has(MessageFlag::Similar))
{
continue;
}
element->addToContainer(*this->container_, flags); element->addToContainer(*this->container_, flags);
} }

View file

@ -21,6 +21,97 @@
namespace chatterino { namespace chatterino {
static float relativeSimilarity(const QString &str1, const QString &str2)
{
// Longest Common Substring Problem
std::vector<std::vector<int>> tree(str1.size(),
std::vector<int>(str2.size(), 0));
int z = 0;
for (int i = 0; i < str1.size(); ++i)
{
for (int j = 0; j < str2.size(); ++j)
{
if (str1[i] == str2[j])
{
if (i == 0 || j == 0)
{
tree[i][j] = 1;
}
else
{
tree[i][j] = tree[i - 1][j - 1] + 1;
}
if (tree[i][j] > z)
{
z = tree[i][j];
}
}
else
{
tree[i][j] = 0;
}
}
}
return z == 0 ? 0.f : float(z) / std::max(str1.size(), str2.size());
};
float IrcMessageHandler::similarity(
MessagePtr msg, const LimitedQueueSnapshot<MessagePtr> &messages)
{
float similarityPercent = 0.0f;
int bySameUser = 0;
for (int i = 1; bySameUser < getSettings()->hideSimilarMaxMessagesToCheck;
++i)
{
if (messages.size() < i)
{
break;
}
const auto &prevMsg = messages[messages.size() - i];
if (prevMsg->parseTime.secsTo(QTime::currentTime()) >=
getSettings()->hideSimilarMaxDelay)
{
break;
}
if (msg->loginName != prevMsg->loginName)
{
continue;
}
++bySameUser;
similarityPercent = std::max(
similarityPercent,
relativeSimilarity(msg->messageText, prevMsg->messageText));
}
return similarityPercent;
}
void IrcMessageHandler::setSimilarityFlags(MessagePtr msg, ChannelPtr chan)
{
if (getSettings()->similarityEnabled)
{
bool isMyself = msg->loginName ==
getApp()->accounts->twitch.getCurrent()->getUserName();
bool hideMyself = getSettings()->hideSimilarMyself;
if (isMyself && !hideMyself)
{
return;
}
if (IrcMessageHandler::similarity(msg, chan->getMessageSnapshot()) >
getSettings()->similarityPercentage)
{
msg->flags.set(MessageFlag::Similar, true);
if (getSettings()->colorSimilarDisabled)
{
msg->flags.set(MessageFlag::Disabled, true);
}
}
}
}
static QMap<QString, QString> parseBadges(QString badgesString) static QMap<QString, QString> parseBadges(QString badgesString)
{ {
QMap<QString, QString> badges; QMap<QString, QString> badges;
@ -133,7 +224,16 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *_message,
} }
auto msg = builder.build(); auto msg = builder.build();
IrcMessageHandler::setSimilarityFlags(msg, chan);
if (!msg->flags.has(MessageFlag::Similar) ||
(!getSettings()->hideSimilar &&
getSettings()->shownSimilarTriggerHighlights))
{
builder.triggerHighlights(); builder.triggerHighlights();
}
auto highlighted = msg->flags.has(MessageFlag::Highlighted); auto highlighted = msg->flags.has(MessageFlag::Highlighted);
if (!isSub) if (!isSub)

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <IrcMessage> #include <IrcMessage>
#include "common/Channel.hpp"
#include "messages/Message.hpp" #include "messages/Message.hpp"
namespace chatterino { namespace chatterino {
@ -49,6 +50,10 @@ public:
void handleJoinMessage(Communi::IrcMessage *message); void handleJoinMessage(Communi::IrcMessage *message);
void handlePartMessage(Communi::IrcMessage *message); void handlePartMessage(Communi::IrcMessage *message);
static float similarity(MessagePtr msg,
const LimitedQueueSnapshot<MessagePtr> &messages);
static void setSimilarityFlags(MessagePtr message, ChannelPtr channel);
private: private:
void addMessage(Communi::IrcMessage *message, const QString &target, void addMessage(Communi::IrcMessage *message, const QString &target,
const QString &content, TwitchIrcServer &server, const QString &content, TwitchIrcServer &server,

View file

@ -249,6 +249,20 @@ public:
IntSetting lastSelectChannelTab = {"/ui/lastSelectChannelTab", 0}; IntSetting lastSelectChannelTab = {"/ui/lastSelectChannelTab", 0};
IntSetting lastSelectIrcConn = {"/ui/lastSelectIrcConn", 0}; IntSetting lastSelectIrcConn = {"/ui/lastSelectIrcConn", 0};
// Similarity
BoolSetting similarityEnabled = {"/similarity/similarityEnabled", false};
BoolSetting colorSimilarDisabled = {"/similarity/colorSimilarDisabled",
true};
BoolSetting hideSimilar = {"/similarity/hideSimilar", false};
BoolSetting hideSimilarMyself = {"/similarity/hideSimilarMyself", false};
BoolSetting shownSimilarTriggerHighlights = {
"/similarity/shownSimilarTriggerHighlights", false};
FloatSetting similarityPercentage = {"/similarity/similarityPercentage",
0.9f};
IntSetting hideSimilarMaxDelay = {"/similarity/hideSimilarMaxDelay", 5};
IntSetting hideSimilarMaxMessagesToCheck = {
"/similarity/hideSimilarMaxMessagesToCheck", 3};
private: private:
void updateModerationActions(); void updateModerationActions();
}; };

View file

@ -351,6 +351,11 @@ void Window::addShortcuts()
getApp()->twitch.server->getOrAddChannel(si.channelName)); getApp()->twitch.server->getOrAddChannel(si.channelName));
splitContainer->appendSplit(split); splitContainer->appendSplit(split);
}); });
createWindowShortcut(this, "CTRL+H", [this] {
getSettings()->hideSimilar.setValue(!getSettings()->hideSimilar);
getApp()->windows->forceLayoutChannelViews();
});
} }
void Window::addMenuBar() void Window::addMenuBar()

View file

@ -547,6 +547,33 @@ void GeneralPage::initLayout(SettingsLayout &layout)
QDesktopServices::openUrl(getPaths()->rootAppDataDirectory); QDesktopServices::openUrl(getPaths()->rootAppDataDirectory);
}); });
layout.addTitle("Similarity");
layout.addDescription(
"Hides or grays out similar messages from the same user");
layout.addCheckbox("Similarity enabled", s.similarityEnabled);
layout.addCheckbox("Gray out similar messages", s.colorSimilarDisabled);
layout.addCheckbox("Hide similar messages (Ctrl + H)", s.hideSimilar);
layout.addCheckbox("Hide or gray out my own similar messages",
s.hideSimilarMyself);
layout.addCheckbox("Shown similar messages trigger highlights",
s.shownSimilarTriggerHighlights);
layout.addDropdown<float>(
"Similarity percentage", {"0.5", "0.75", "0.9"}, s.similarityPercentage,
[](auto val) { return QString::number(val); },
[](auto args) { return fuzzyToFloat(args.value, 0.9f); });
s.hideSimilar.connect(
[]() { getApp()->windows->forceLayoutChannelViews(); }, false);
layout.addDropdown<int>(
"Similar messages max delay in seconds",
{"5", "10", "15", "30", "60", "120"}, s.hideSimilarMaxDelay,
[](auto val) { return QString::number(val); },
[](auto args) { return fuzzyToInt(args.value, 5); });
layout.addDropdown<int>(
"Similar messages max previous messages to check",
{"1", "2", "3", "4", "5"}, s.hideSimilarMaxMessagesToCheck,
[](auto val) { return QString::number(val); },
[](auto args) { return fuzzyToInt(args.value, 3); });
// invisible element for width // invisible element for width
auto inv = new BaseWidget(this); auto inv = new BaseWidget(this);
inv->setScaleIndependantWidth(500); inv->setScaleIndependantWidth(500);

View file

@ -26,6 +26,10 @@ KeyboardSettingsPage::KeyboardSettingsPage()
form->addRow(new QLabel("Ctrl + Shift + T"), new QLabel("Create new tab")); form->addRow(new QLabel("Ctrl + Shift + T"), new QLabel("Create new tab"));
form->addRow(new QLabel("Ctrl + Shift + W"), form->addRow(new QLabel("Ctrl + Shift + W"),
new QLabel("Close current tab")); new QLabel("Close current tab"));
form->addRow(
new QLabel("Ctrl + H"),
new QLabel(
"Hide/Show similar messages (Enable in General under Similarity)"));
form->addItem(new QSpacerItem(16, 16)); form->addItem(new QSpacerItem(16, 16));
form->addRow(new QLabel("Ctrl + 1/2/3/..."), form->addRow(new QLabel("Ctrl + 1/2/3/..."),