2018-06-26 14:09:39 +02:00
|
|
|
#include "Application.hpp"
|
|
|
|
|
2019-09-22 15:30:04 +02:00
|
|
|
#include "common/Args.hpp"
|
2020-11-21 16:20:10 +01:00
|
|
|
#include "common/QLogging.hpp"
|
2020-09-06 12:02:15 +02:00
|
|
|
#include "common/Version.hpp"
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "controllers/accounts/AccountController.hpp"
|
2022-12-31 15:41:01 +01:00
|
|
|
#include "controllers/commands/Command.hpp"
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "controllers/commands/CommandController.hpp"
|
2022-06-05 17:40:57 +02:00
|
|
|
#include "controllers/highlights/HighlightController.hpp"
|
2021-11-21 18:46:21 +01:00
|
|
|
#include "controllers/hotkeys/HotkeyController.hpp"
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "controllers/ignores/IgnoreController.hpp"
|
2018-08-09 15:41:03 +02:00
|
|
|
#include "controllers/notifications/NotificationController.hpp"
|
2023-11-26 22:06:12 +01:00
|
|
|
#include "controllers/sound/ISoundController.hpp"
|
2024-01-21 14:20:21 +01:00
|
|
|
#include "providers/bttv/BttvEmotes.hpp"
|
|
|
|
#include "providers/ffz/FfzEmotes.hpp"
|
2024-06-01 14:56:40 +02:00
|
|
|
#include "providers/irc/AbstractIrcServer.hpp"
|
2024-02-18 13:34:00 +01:00
|
|
|
#include "providers/links/LinkResolver.hpp"
|
2023-11-26 16:54:19 +01:00
|
|
|
#include "providers/seventv/SeventvAPI.hpp"
|
2024-01-21 14:20:21 +01:00
|
|
|
#include "providers/seventv/SeventvEmotes.hpp"
|
2024-01-17 23:53:10 +01:00
|
|
|
#include "providers/twitch/TwitchBadges.hpp"
|
2023-11-19 12:05:30 +01:00
|
|
|
#include "singletons/ImageUploader.hpp"
|
2023-04-02 15:31:53 +02:00
|
|
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
|
|
|
# include "controllers/plugins/PluginController.hpp"
|
|
|
|
#endif
|
2023-11-26 22:06:12 +01:00
|
|
|
#include "controllers/sound/MiniaudioBackend.hpp"
|
|
|
|
#include "controllers/sound/NullBackend.hpp"
|
2023-07-02 15:52:15 +02:00
|
|
|
#include "controllers/twitch/LiveController.hpp"
|
2022-11-13 18:21:21 +01:00
|
|
|
#include "controllers/userdata/UserDataController.hpp"
|
2021-05-01 12:47:33 +02:00
|
|
|
#include "debug/AssertInGuiThread.hpp"
|
2022-12-31 15:41:01 +01:00
|
|
|
#include "messages/Message.hpp"
|
2018-08-07 01:35:24 +02:00
|
|
|
#include "messages/MessageBuilder.hpp"
|
2023-01-21 15:06:55 +01:00
|
|
|
#include "providers/bttv/BttvLiveUpdates.hpp"
|
2018-09-16 17:27:51 +02:00
|
|
|
#include "providers/chatterino/ChatterinoBadges.hpp"
|
2020-10-25 10:36:00 +01:00
|
|
|
#include "providers/ffz/FfzBadges.hpp"
|
2019-09-10 23:55:43 +02:00
|
|
|
#include "providers/irc/Irc2.hpp"
|
2023-02-04 13:42:52 +01:00
|
|
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
|
|
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
2022-10-16 13:22:17 +02:00
|
|
|
#include "providers/seventv/SeventvBadges.hpp"
|
2022-11-13 12:07:41 +01:00
|
|
|
#include "providers/seventv/SeventvEventAPI.hpp"
|
2022-12-31 15:41:01 +01:00
|
|
|
#include "providers/twitch/ChannelPointReward.hpp"
|
|
|
|
#include "providers/twitch/PubSubActions.hpp"
|
2022-05-07 17:22:39 +02:00
|
|
|
#include "providers/twitch/PubSubManager.hpp"
|
2022-12-31 15:41:01 +01:00
|
|
|
#include "providers/twitch/PubSubMessages.hpp"
|
2023-12-31 11:44:55 +01:00
|
|
|
#include "providers/twitch/pubsubmessages/LowTrustUsers.hpp"
|
2022-12-31 15:41:01 +01:00
|
|
|
#include "providers/twitch/TwitchChannel.hpp"
|
2019-09-15 13:02:02 +02:00
|
|
|
#include "providers/twitch/TwitchIrcServer.hpp"
|
2021-06-19 13:56:00 +02:00
|
|
|
#include "providers/twitch/TwitchMessageBuilder.hpp"
|
2023-12-24 15:38:58 +01:00
|
|
|
#include "singletons/CrashHandler.hpp"
|
2018-08-11 22:23:06 +02:00
|
|
|
#include "singletons/Emotes.hpp"
|
2018-06-28 19:46:45 +02:00
|
|
|
#include "singletons/Fonts.hpp"
|
2022-12-31 15:41:01 +01:00
|
|
|
#include "singletons/helper/LoggingChannel.hpp"
|
2018-06-28 19:46:45 +02:00
|
|
|
#include "singletons/Logging.hpp"
|
|
|
|
#include "singletons/Paths.hpp"
|
|
|
|
#include "singletons/Settings.hpp"
|
2024-03-01 21:12:02 +01:00
|
|
|
#include "singletons/StreamerMode.hpp"
|
2018-06-28 20:03:04 +02:00
|
|
|
#include "singletons/Theme.hpp"
|
2018-08-11 12:47:03 +02:00
|
|
|
#include "singletons/Toasts.hpp"
|
2019-09-02 10:52:01 +02:00
|
|
|
#include "singletons/Updates.hpp"
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "singletons/WindowManager.hpp"
|
2022-05-07 17:22:39 +02:00
|
|
|
#include "util/Helpers.hpp"
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "util/PostToThread.hpp"
|
2019-09-22 15:32:36 +02:00
|
|
|
#include "widgets/Notebook.hpp"
|
|
|
|
#include "widgets/splits/Split.hpp"
|
Sort and force grouping of includes (#4172)
This change enforces strict include grouping using IncludeCategories
In addition to adding this to the .clang-format file and applying it in the tests/src and src directories, I also did the following small changes:
In ChatterSet.hpp, I changed lrucache to a <>include
In Irc2.hpp, I change common/SignalVector.hpp to a "project-include"
In AttachedWindow.cpp, NativeMessaging.cpp, WindowsHelper.hpp, BaseWindow.cpp, and StreamerMode.cpp, I disabled clang-format for the windows-includes
In WindowDescriptors.hpp, I added the missing vector include. It was previously not needed because the include was handled by another file that was previously included first.
clang-format minimum version has been bumped, so Ubuntu version used in the check-formatting job has been bumped to 22.04 (which is the latest LTS)
2022-11-27 19:32:53 +01:00
|
|
|
#include "widgets/Window.hpp"
|
2017-06-13 21:13:58 +02:00
|
|
|
|
2023-01-29 10:36:25 +01:00
|
|
|
#include <miniaudio.h>
|
2021-05-08 15:57:00 +02:00
|
|
|
#include <QDesktopServices>
|
|
|
|
|
Sort and force grouping of includes (#4172)
This change enforces strict include grouping using IncludeCategories
In addition to adding this to the .clang-format file and applying it in the tests/src and src directories, I also did the following small changes:
In ChatterSet.hpp, I changed lrucache to a <>include
In Irc2.hpp, I change common/SignalVector.hpp to a "project-include"
In AttachedWindow.cpp, NativeMessaging.cpp, WindowsHelper.hpp, BaseWindow.cpp, and StreamerMode.cpp, I disabled clang-format for the windows-includes
In WindowDescriptors.hpp, I added the missing vector include. It was previously not needed because the include was handled by another file that was previously included first.
clang-format minimum version has been bumped, so Ubuntu version used in the check-formatting job has been bumped to 22.04 (which is the latest LTS)
2022-11-27 19:32:53 +01:00
|
|
|
#include <atomic>
|
|
|
|
|
2023-11-26 22:06:12 +01:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
using namespace chatterino;
|
|
|
|
|
|
|
|
ISoundController *makeSoundController(Settings &settings)
|
|
|
|
{
|
|
|
|
SoundBackend soundBackend = settings.soundBackend;
|
|
|
|
switch (soundBackend)
|
|
|
|
{
|
|
|
|
case SoundBackend::Miniaudio: {
|
|
|
|
return new MiniaudioBackend();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SoundBackend::Null: {
|
|
|
|
return new NullBackend();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: {
|
|
|
|
return new MiniaudioBackend();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
const QString TWITCH_PUBSUB_URL = "wss://pubsub-edge.twitch.tv";
|
|
|
|
|
2023-11-26 22:06:12 +01:00
|
|
|
} // namespace
|
|
|
|
|
2017-06-13 21:13:58 +02:00
|
|
|
namespace chatterino {
|
|
|
|
|
2018-04-27 22:11:19 +02:00
|
|
|
static std::atomic<bool> isAppInitialized{false};
|
|
|
|
|
2018-08-02 14:23:27 +02:00
|
|
|
Application *Application::instance = nullptr;
|
2022-05-22 15:00:18 +02:00
|
|
|
IApplication *IApplication::instance = nullptr;
|
|
|
|
|
|
|
|
IApplication::IApplication()
|
|
|
|
{
|
|
|
|
IApplication::instance = this;
|
|
|
|
}
|
2018-04-27 22:11:19 +02:00
|
|
|
|
2017-06-26 16:41:20 +02:00
|
|
|
// this class is responsible for handling the workflow of Chatterino
|
|
|
|
// It will create the instances of the major classes, and connect their signals
|
|
|
|
// to each other
|
|
|
|
|
2024-01-16 21:56:43 +01:00
|
|
|
Application::Application(Settings &_settings, const Paths &paths,
|
|
|
|
const Args &_args, Updates &_updates)
|
|
|
|
: paths_(paths)
|
|
|
|
, args_(_args)
|
2023-12-29 15:40:31 +01:00
|
|
|
, themes(&this->emplace<Theme>())
|
2024-03-10 14:27:08 +01:00
|
|
|
, fonts(new Fonts(_settings))
|
2018-08-02 14:23:27 +02:00
|
|
|
, emotes(&this->emplace<Emotes>())
|
2020-12-06 14:07:33 +01:00
|
|
|
, accounts(&this->emplace<AccountController>())
|
2021-11-21 18:46:21 +01:00
|
|
|
, hotkeys(&this->emplace<HotkeyController>())
|
2024-01-16 21:56:43 +01:00
|
|
|
, windows(&this->emplace(new WindowManager(paths)))
|
2018-08-19 15:09:00 +02:00
|
|
|
, toasts(&this->emplace<Toasts>())
|
2023-11-19 12:05:30 +01:00
|
|
|
, imageUploader(&this->emplace<ImageUploader>())
|
2023-11-26 16:54:19 +01:00
|
|
|
, seventvAPI(&this->emplace<SeventvAPI>())
|
2024-01-16 21:56:43 +01:00
|
|
|
, crashHandler(&this->emplace(new CrashHandler(paths)))
|
2018-08-19 19:02:49 +02:00
|
|
|
|
2018-08-02 14:23:27 +02:00
|
|
|
, commands(&this->emplace<CommandController>())
|
2018-08-09 15:41:03 +02:00
|
|
|
, notifications(&this->emplace<NotificationController>())
|
2022-06-05 17:40:57 +02:00
|
|
|
, highlights(&this->emplace<HighlightController>())
|
2024-06-01 14:56:40 +02:00
|
|
|
, twitch(new TwitchIrcServer)
|
2020-10-25 10:36:00 +01:00
|
|
|
, ffzBadges(&this->emplace<FfzBadges>())
|
2022-10-16 13:22:17 +02:00
|
|
|
, seventvBadges(&this->emplace<SeventvBadges>())
|
2024-01-16 21:56:43 +01:00
|
|
|
, userData(&this->emplace(new UserDataController(paths)))
|
2023-11-26 22:06:12 +01:00
|
|
|
, sound(&this->emplace<ISoundController>(makeSoundController(_settings)))
|
2023-07-02 15:52:15 +02:00
|
|
|
, twitchLiveController(&this->emplace<TwitchLiveController>())
|
2024-01-06 13:18:37 +01:00
|
|
|
, twitchPubSub(new PubSub(TWITCH_PUBSUB_URL))
|
2024-01-17 23:53:10 +01:00
|
|
|
, twitchBadges(new TwitchBadges)
|
2024-01-19 17:25:52 +01:00
|
|
|
, chatterinoBadges(new ChatterinoBadges)
|
2024-01-21 14:20:21 +01:00
|
|
|
, bttvEmotes(new BttvEmotes)
|
|
|
|
, ffzEmotes(new FfzEmotes)
|
|
|
|
, seventvEmotes(new SeventvEmotes)
|
2023-12-31 13:51:40 +01:00
|
|
|
, logging(new Logging(_settings))
|
2024-02-18 13:34:00 +01:00
|
|
|
, linkResolver(new LinkResolver)
|
2024-03-01 21:12:02 +01:00
|
|
|
, streamerMode(new StreamerMode)
|
2023-04-02 15:31:53 +02:00
|
|
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
2024-01-16 21:56:43 +01:00
|
|
|
, plugins(&this->emplace(new PluginController(paths)))
|
2023-04-02 15:31:53 +02:00
|
|
|
#endif
|
2024-01-16 21:56:43 +01:00
|
|
|
, updates(_updates)
|
2017-06-13 21:13:58 +02:00
|
|
|
{
|
2023-12-31 13:51:40 +01:00
|
|
|
Application::instance = this;
|
2018-08-02 14:23:27 +02:00
|
|
|
|
2023-09-16 13:52:51 +02:00
|
|
|
// We can safely ignore this signal's connection since the Application will always
|
|
|
|
// be destroyed after fonts
|
|
|
|
std::ignore = this->fonts->fontChanged.connect([this]() {
|
2020-11-08 12:02:19 +01:00
|
|
|
this->windows->layoutChannelViews();
|
|
|
|
});
|
2018-04-27 22:11:19 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 13:51:40 +01:00
|
|
|
Application::~Application() = default;
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
void Application::fakeDtor()
|
|
|
|
{
|
|
|
|
this->twitchPubSub.reset();
|
2024-01-17 23:53:10 +01:00
|
|
|
this->twitchBadges.reset();
|
2024-01-19 17:25:52 +01:00
|
|
|
this->chatterinoBadges.reset();
|
2024-01-21 14:20:21 +01:00
|
|
|
this->bttvEmotes.reset();
|
|
|
|
this->ffzEmotes.reset();
|
|
|
|
this->seventvEmotes.reset();
|
2024-06-01 14:56:40 +02:00
|
|
|
// this->twitch.reset();
|
2024-03-10 14:27:08 +01:00
|
|
|
this->fonts.reset();
|
2024-01-06 13:18:37 +01:00
|
|
|
}
|
|
|
|
|
2024-01-16 21:56:43 +01:00
|
|
|
void Application::initialize(Settings &settings, const Paths &paths)
|
2018-04-27 22:11:19 +02:00
|
|
|
{
|
|
|
|
assert(isAppInitialized == false);
|
|
|
|
isAppInitialized = true;
|
2018-01-05 02:23:49 +01:00
|
|
|
|
2020-09-06 12:02:15 +02:00
|
|
|
// Show changelog
|
2023-12-29 15:40:31 +01:00
|
|
|
if (!this->args_.isFramelessEmbed &&
|
2021-04-17 16:15:23 +02:00
|
|
|
getSettings()->currentVersion.getValue() != "" &&
|
2020-09-06 12:02:15 +02:00
|
|
|
getSettings()->currentVersion.getValue() != CHATTERINO_VERSION)
|
|
|
|
{
|
2024-01-14 17:54:52 +01:00
|
|
|
auto *box = new QMessageBox(QMessageBox::Information, "Chatterino 2",
|
|
|
|
"Show changelog?",
|
|
|
|
QMessageBox::Yes | QMessageBox::No);
|
2020-09-06 12:02:15 +02:00
|
|
|
box->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
if (box->exec() == QMessageBox::Yes)
|
|
|
|
{
|
|
|
|
QDesktopServices::openUrl(
|
|
|
|
QUrl("https://www.chatterino.com/changelog"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-29 15:40:31 +01:00
|
|
|
if (!this->args_.isFramelessEmbed)
|
2019-10-03 17:36:44 +02:00
|
|
|
{
|
2021-04-17 16:15:23 +02:00
|
|
|
getSettings()->currentVersion.setValue(CHATTERINO_VERSION);
|
|
|
|
|
|
|
|
if (getSettings()->enableExperimentalIrc)
|
|
|
|
{
|
|
|
|
Irc::instance().load();
|
|
|
|
}
|
2019-10-03 17:36:44 +02:00
|
|
|
}
|
2019-09-14 20:45:01 +02:00
|
|
|
|
2018-08-02 14:23:27 +02:00
|
|
|
for (auto &singleton : this->singletons_)
|
|
|
|
{
|
|
|
|
singleton->initialize(settings, paths);
|
2018-07-07 11:41:01 +02:00
|
|
|
}
|
2018-04-28 15:20:18 +02:00
|
|
|
|
2024-02-02 15:28:27 +01:00
|
|
|
// XXX: Loading Twitch badges after Helix has been initialized, which only happens after
|
|
|
|
// the AccountController initialize has been called
|
|
|
|
this->twitchBadges->loadTwitchBadges();
|
|
|
|
|
2023-12-24 15:38:58 +01:00
|
|
|
// Show crash message.
|
|
|
|
// On Windows, the crash message was already shown.
|
|
|
|
#ifndef Q_OS_WIN
|
2023-12-29 15:40:31 +01:00
|
|
|
if (!this->args_.isFramelessEmbed && this->args_.crashRecovery)
|
2019-09-22 15:32:36 +02:00
|
|
|
{
|
2024-01-14 17:54:52 +01:00
|
|
|
if (auto *selected =
|
2019-09-22 15:32:36 +02:00
|
|
|
this->windows->getMainWindow().getNotebook().getSelectedPage())
|
|
|
|
{
|
2024-01-14 17:54:52 +01:00
|
|
|
if (auto *container = dynamic_cast<SplitContainer *>(selected))
|
2019-09-22 15:32:36 +02:00
|
|
|
{
|
|
|
|
for (auto &&split : container->getSplits())
|
|
|
|
{
|
|
|
|
if (auto channel = split->getChannel(); !channel->isEmpty())
|
|
|
|
{
|
|
|
|
channel->addMessage(makeSystemMessage(
|
|
|
|
"Chatterino unexpectedly crashed and restarted. "
|
|
|
|
"You can disable automatic restarts in the "
|
|
|
|
"settings."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-24 15:38:58 +01:00
|
|
|
#endif
|
2019-09-22 15:32:36 +02:00
|
|
|
|
2018-06-28 19:38:57 +02:00
|
|
|
this->windows->updateWordTypeMask();
|
2018-04-12 00:33:55 +02:00
|
|
|
|
2023-12-29 15:40:31 +01:00
|
|
|
if (!this->args_.isFramelessEmbed)
|
2021-04-17 16:15:23 +02:00
|
|
|
{
|
|
|
|
this->initNm(paths);
|
|
|
|
}
|
2022-05-07 17:22:39 +02:00
|
|
|
this->initPubSub();
|
2022-11-13 12:07:41 +01:00
|
|
|
|
2023-01-21 15:06:55 +01:00
|
|
|
this->initBttvLiveUpdates();
|
2022-11-13 12:07:41 +01:00
|
|
|
this->initSeventvEventAPI();
|
2018-08-02 14:23:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int Application::run(QApplication &qtApp)
|
|
|
|
{
|
|
|
|
assert(isAppInitialized);
|
|
|
|
|
2022-03-19 12:02:29 +01:00
|
|
|
this->twitch->connect();
|
2018-08-02 14:23:27 +02:00
|
|
|
|
2023-12-29 15:40:31 +01:00
|
|
|
if (!this->args_.isFramelessEmbed)
|
2021-04-17 16:15:23 +02:00
|
|
|
{
|
|
|
|
this->windows->getMainWindow().show();
|
|
|
|
}
|
2018-08-02 14:23:27 +02:00
|
|
|
|
2019-10-03 22:17:57 +02:00
|
|
|
getSettings()->betaUpdates.connect(
|
2024-01-16 21:56:43 +01:00
|
|
|
[this] {
|
|
|
|
this->updates.checkForUpdates();
|
2020-11-08 12:02:19 +01:00
|
|
|
},
|
|
|
|
false);
|
2019-09-02 10:52:01 +02:00
|
|
|
|
2023-09-16 13:52:51 +02:00
|
|
|
// We can safely ignore the signal connections since Application will always live longer than
|
|
|
|
// everything else, including settings. right?
|
|
|
|
// NOTE: SETTINGS_LIFETIME
|
|
|
|
std::ignore =
|
|
|
|
getSettings()->moderationActions.delayedItemsChanged.connect([this] {
|
|
|
|
this->windows->forceLayoutChannelViews();
|
|
|
|
});
|
|
|
|
|
|
|
|
std::ignore =
|
|
|
|
getSettings()->highlightedMessages.delayedItemsChanged.connect([this] {
|
|
|
|
this->windows->forceLayoutChannelViews();
|
|
|
|
});
|
|
|
|
std::ignore =
|
|
|
|
getSettings()->highlightedUsers.delayedItemsChanged.connect([this] {
|
|
|
|
this->windows->forceLayoutChannelViews();
|
|
|
|
});
|
2024-01-20 12:56:09 +01:00
|
|
|
std::ignore =
|
|
|
|
getSettings()->highlightedBadges.delayedItemsChanged.connect([this] {
|
|
|
|
this->windows->forceLayoutChannelViews();
|
|
|
|
});
|
2020-04-15 23:15:45 +02:00
|
|
|
|
2021-04-26 00:25:23 +02:00
|
|
|
getSettings()->removeSpacesBetweenEmotes.connect([this] {
|
|
|
|
this->windows->forceLayoutChannelViews();
|
|
|
|
});
|
|
|
|
|
2022-09-14 13:21:01 +02:00
|
|
|
getSettings()->enableBTTVGlobalEmotes.connect(
|
|
|
|
[this] {
|
|
|
|
this->twitch->reloadBTTVGlobalEmotes();
|
|
|
|
},
|
|
|
|
false);
|
|
|
|
getSettings()->enableBTTVChannelEmotes.connect(
|
|
|
|
[this] {
|
|
|
|
this->twitch->reloadAllBTTVChannelEmotes();
|
|
|
|
},
|
|
|
|
false);
|
|
|
|
getSettings()->enableFFZGlobalEmotes.connect(
|
|
|
|
[this] {
|
|
|
|
this->twitch->reloadFFZGlobalEmotes();
|
|
|
|
},
|
|
|
|
false);
|
|
|
|
getSettings()->enableFFZChannelEmotes.connect(
|
|
|
|
[this] {
|
|
|
|
this->twitch->reloadAllFFZChannelEmotes();
|
|
|
|
},
|
2022-10-16 13:22:17 +02:00
|
|
|
false);
|
|
|
|
getSettings()->enableSevenTVGlobalEmotes.connect(
|
|
|
|
[this] {
|
|
|
|
this->twitch->reloadSevenTVGlobalEmotes();
|
|
|
|
},
|
|
|
|
false);
|
|
|
|
getSettings()->enableSevenTVChannelEmotes.connect(
|
|
|
|
[this] {
|
|
|
|
this->twitch->reloadAllSevenTVChannelEmotes();
|
|
|
|
},
|
2022-09-14 13:21:01 +02:00
|
|
|
false);
|
2022-08-28 12:20:47 +02:00
|
|
|
|
2018-08-02 14:23:27 +02:00
|
|
|
return qtApp.exec();
|
|
|
|
}
|
|
|
|
|
2024-01-19 17:59:55 +01:00
|
|
|
Theme *Application::getThemes()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->themes;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fonts *Application::getFonts()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
2024-03-10 14:27:08 +01:00
|
|
|
assert(this->fonts);
|
2024-01-19 17:59:55 +01:00
|
|
|
|
2024-03-10 14:27:08 +01:00
|
|
|
return this->fonts.get();
|
2024-01-19 17:59:55 +01:00
|
|
|
}
|
|
|
|
|
2022-11-05 11:04:35 +01:00
|
|
|
IEmotes *Application::getEmotes()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2022-11-05 11:04:35 +01:00
|
|
|
return this->emotes;
|
|
|
|
}
|
|
|
|
|
2024-01-19 17:59:55 +01:00
|
|
|
AccountController *Application::getAccounts()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->accounts;
|
|
|
|
}
|
|
|
|
|
|
|
|
HotkeyController *Application::getHotkeys()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->hotkeys;
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowManager *Application::getWindows()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
assert(this->windows);
|
|
|
|
|
|
|
|
return this->windows;
|
|
|
|
}
|
|
|
|
|
|
|
|
Toasts *Application::getToasts()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->toasts;
|
|
|
|
}
|
|
|
|
|
|
|
|
CrashHandler *Application::getCrashHandler()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->crashHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandController *Application::getCommands()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->commands;
|
|
|
|
}
|
|
|
|
|
|
|
|
NotificationController *Application::getNotifications()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->notifications;
|
|
|
|
}
|
|
|
|
|
|
|
|
HighlightController *Application::getHighlights()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->highlights;
|
|
|
|
}
|
|
|
|
|
|
|
|
FfzBadges *Application::getFfzBadges()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->ffzBadges;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeventvBadges *Application::getSeventvBadges()
|
|
|
|
{
|
|
|
|
// SeventvBadges handles its own locks, so we don't need to assert that this is called in the GUI thread
|
|
|
|
|
|
|
|
return this->seventvBadges;
|
|
|
|
}
|
|
|
|
|
2022-11-13 18:21:21 +01:00
|
|
|
IUserDataController *Application::getUserData()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2022-11-13 18:21:21 +01:00
|
|
|
return this->userData;
|
|
|
|
}
|
|
|
|
|
2023-11-26 22:06:12 +01:00
|
|
|
ISoundController *Application::getSound()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2023-11-26 22:06:12 +01:00
|
|
|
return this->sound;
|
|
|
|
}
|
|
|
|
|
2023-07-02 15:52:15 +02:00
|
|
|
ITwitchLiveController *Application::getTwitchLiveController()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2023-07-02 15:52:15 +02:00
|
|
|
return this->twitchLiveController;
|
|
|
|
}
|
|
|
|
|
2024-01-17 23:53:10 +01:00
|
|
|
TwitchBadges *Application::getTwitchBadges()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
2024-01-17 23:53:10 +01:00
|
|
|
assert(this->twitchBadges);
|
|
|
|
|
|
|
|
return this->twitchBadges.get();
|
|
|
|
}
|
|
|
|
|
2024-01-19 17:25:52 +01:00
|
|
|
IChatterinoBadges *Application::getChatterinoBadges()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
assert(this->chatterinoBadges);
|
|
|
|
|
|
|
|
return this->chatterinoBadges.get();
|
|
|
|
}
|
|
|
|
|
2024-01-19 17:59:55 +01:00
|
|
|
ImageUploader *Application::getImageUploader()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->imageUploader;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeventvAPI *Application::getSeventvAPI()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->seventvAPI;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
|
|
|
PluginController *Application::getPlugins()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->plugins;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-05-21 12:10:49 +02:00
|
|
|
ITwitchIrcServer *Application::getTwitch()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2024-06-01 14:56:40 +02:00
|
|
|
return this->twitch.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
IAbstractIrcServer *Application::getTwitchAbstract()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->twitch.get();
|
2023-05-21 12:10:49 +02:00
|
|
|
}
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
PubSub *Application::getTwitchPubSub()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
return this->twitchPubSub.get();
|
|
|
|
}
|
|
|
|
|
2023-12-31 13:51:40 +01:00
|
|
|
Logging *Application::getChatLogger()
|
|
|
|
{
|
2024-01-18 20:50:57 +01:00
|
|
|
assertInGuiThread();
|
|
|
|
|
2023-12-31 13:51:40 +01:00
|
|
|
return this->logging.get();
|
|
|
|
}
|
|
|
|
|
2024-02-18 13:34:00 +01:00
|
|
|
ILinkResolver *Application::getLinkResolver()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
|
|
|
|
return this->linkResolver.get();
|
|
|
|
}
|
|
|
|
|
2024-03-01 21:12:02 +01:00
|
|
|
IStreamerMode *Application::getStreamerMode()
|
|
|
|
{
|
|
|
|
return this->streamerMode.get();
|
|
|
|
}
|
|
|
|
|
2024-01-21 14:20:21 +01:00
|
|
|
BttvEmotes *Application::getBttvEmotes()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
assert(this->bttvEmotes);
|
|
|
|
|
|
|
|
return this->bttvEmotes.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
FfzEmotes *Application::getFfzEmotes()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
assert(this->ffzEmotes);
|
|
|
|
|
|
|
|
return this->ffzEmotes.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
SeventvEmotes *Application::getSeventvEmotes()
|
|
|
|
{
|
|
|
|
assertInGuiThread();
|
|
|
|
assert(this->seventvEmotes);
|
|
|
|
|
|
|
|
return this->seventvEmotes.get();
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:23:27 +02:00
|
|
|
void Application::save()
|
|
|
|
{
|
|
|
|
for (auto &singleton : this->singletons_)
|
|
|
|
{
|
|
|
|
singleton->save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-16 21:56:43 +01:00
|
|
|
void Application::initNm(const Paths &paths)
|
2018-08-02 14:23:27 +02:00
|
|
|
{
|
2019-09-08 18:06:43 +02:00
|
|
|
(void)paths;
|
|
|
|
|
2018-06-24 14:03:26 +02:00
|
|
|
#ifdef Q_OS_WIN
|
2023-07-30 13:14:58 +02:00
|
|
|
# if defined QT_NO_DEBUG || defined CHATTERINO_DEBUG_NM
|
2018-09-17 12:51:16 +02:00
|
|
|
registerNmHost(paths);
|
|
|
|
this->nmServer.start();
|
2018-08-15 22:46:20 +02:00
|
|
|
# endif
|
2018-06-24 14:03:26 +02:00
|
|
|
#endif
|
2018-08-02 14:23:27 +02:00
|
|
|
}
|
2018-04-15 15:09:31 +02:00
|
|
|
|
2022-05-07 17:22:39 +02:00
|
|
|
void Application::initPubSub()
|
2018-08-02 14:23:27 +02:00
|
|
|
{
|
2023-09-16 13:52:51 +02:00
|
|
|
// We can safely ignore these signal connections since the twitch object will always
|
|
|
|
// be destroyed before the Application
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.chatCleared.connect(
|
2018-06-26 17:42:35 +02:00
|
|
|
[this](const auto &action) {
|
2022-03-19 12:02:29 +01:00
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2018-04-29 13:24:37 +02:00
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString text =
|
2024-01-03 12:24:23 +01:00
|
|
|
QString("%1 cleared the chat.").arg(action.source.login);
|
2018-04-29 13:24:37 +02:00
|
|
|
|
2018-08-07 01:35:24 +02:00
|
|
|
auto msg = makeSystemMessage(text);
|
2020-11-08 12:02:19 +01:00
|
|
|
postToThread([chan, msg] {
|
|
|
|
chan->addMessage(msg);
|
|
|
|
});
|
2018-04-15 15:09:31 +02:00
|
|
|
});
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.modeChanged.connect(
|
2018-06-26 17:42:35 +02:00
|
|
|
[this](const auto &action) {
|
2022-03-19 12:02:29 +01:00
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2018-04-29 13:24:37 +02:00
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-26 17:06:17 +02:00
|
|
|
QString text =
|
2024-01-03 12:24:23 +01:00
|
|
|
QString("%1 turned %2 %3 mode.")
|
2021-07-11 13:33:35 +02:00
|
|
|
.arg(action.source.login)
|
2018-06-26 17:06:17 +02:00
|
|
|
.arg(action.state == ModeChangedAction::State::On ? "on"
|
|
|
|
: "off")
|
|
|
|
.arg(action.getModeName());
|
2018-04-29 13:24:37 +02:00
|
|
|
|
|
|
|
if (action.duration > 0)
|
|
|
|
{
|
2021-07-11 13:33:35 +02:00
|
|
|
text += QString(" (%1 seconds)").arg(action.duration);
|
2018-04-29 13:24:37 +02:00
|
|
|
}
|
|
|
|
|
2018-08-07 01:35:24 +02:00
|
|
|
auto msg = makeSystemMessage(text);
|
2020-11-08 12:02:19 +01:00
|
|
|
postToThread([chan, msg] {
|
|
|
|
chan->addMessage(msg);
|
|
|
|
});
|
2018-04-15 15:09:31 +02:00
|
|
|
});
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.moderationStateChanged.connect(
|
|
|
|
[this](const auto &action) {
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-04-29 13:24:37 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
QString text;
|
2018-04-29 13:24:37 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
text = QString("%1 %2 %3.")
|
|
|
|
.arg(action.source.login,
|
|
|
|
(action.modded ? "modded" : "unmodded"),
|
|
|
|
action.target.login);
|
2018-04-29 13:24:37 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
auto msg = makeSystemMessage(text);
|
|
|
|
postToThread([chan, msg] {
|
|
|
|
chan->addMessage(msg);
|
2020-11-08 12:02:19 +01:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
});
|
2018-04-15 15:09:31 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.userBanned.connect(
|
2018-06-26 17:42:35 +02:00
|
|
|
[&](const auto &action) {
|
2022-03-19 12:02:29 +01:00
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2018-04-22 15:47:39 +02:00
|
|
|
|
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-09 13:58:18 +02:00
|
|
|
postToThread([chan, action] {
|
|
|
|
MessageBuilder msg(action);
|
|
|
|
msg->flags.set(MessageFlag::PubSub);
|
|
|
|
chan->addOrReplaceTimeout(msg.release());
|
2018-08-07 01:35:24 +02:00
|
|
|
});
|
2018-04-15 15:09:31 +02:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.messageDeleted.connect(
|
|
|
|
[&](const auto &action) {
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2021-06-19 13:56:00 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
if (chan->isEmpty() || getSettings()->hideDeletionActions)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-06-19 13:56:00 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
MessageBuilder msg;
|
|
|
|
TwitchMessageBuilder::deletionMessage(action, &msg);
|
|
|
|
msg->flags.set(MessageFlag::PubSub);
|
2021-06-19 13:56:00 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
postToThread([chan, msg = msg.release()] {
|
|
|
|
auto replaced = false;
|
|
|
|
LimitedQueueSnapshot<MessagePtr> snapshot =
|
|
|
|
chan->getMessageSnapshot();
|
|
|
|
int snapshotLength = snapshot.size();
|
2021-06-19 13:56:00 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
// without parens it doesn't build on windows
|
|
|
|
int end = (std::max)(0, snapshotLength - 200);
|
2021-06-19 13:56:00 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
for (int i = snapshotLength - 1; i >= end; --i)
|
|
|
|
{
|
2024-01-14 17:54:52 +01:00
|
|
|
const auto &s = snapshot[i];
|
2024-01-06 13:18:37 +01:00
|
|
|
if (!s->flags.has(MessageFlag::PubSub) &&
|
|
|
|
s->timeoutUser == msg->timeoutUser)
|
2023-09-16 13:52:51 +02:00
|
|
|
{
|
2024-01-06 13:18:37 +01:00
|
|
|
chan->replaceMessage(s, msg);
|
|
|
|
replaced = true;
|
|
|
|
break;
|
2023-09-16 13:52:51 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
}
|
|
|
|
if (!replaced)
|
|
|
|
{
|
|
|
|
chan->addMessage(msg);
|
|
|
|
}
|
2021-06-19 13:56:00 +02:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
});
|
2018-04-15 15:09:31 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.userUnbanned.connect(
|
|
|
|
[&](const auto &action) {
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2018-04-27 18:35:31 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-04-27 18:35:31 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
auto msg = MessageBuilder(action).release();
|
2018-04-27 18:35:31 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
postToThread([chan, msg] {
|
|
|
|
chan->addMessage(msg);
|
2020-11-08 12:02:19 +01:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
});
|
2018-04-15 15:09:31 +02:00
|
|
|
|
2023-12-31 11:44:55 +01:00
|
|
|
std::ignore =
|
2024-01-06 13:18:37 +01:00
|
|
|
this->twitchPubSub->moderation.suspiciousMessageReceived.connect(
|
|
|
|
[&](const auto &action) {
|
2023-12-31 11:44:55 +01:00
|
|
|
if (action.treatment ==
|
|
|
|
PubSubLowTrustUsersMessage::Treatment::INVALID)
|
|
|
|
{
|
|
|
|
qCWarning(chatterinoTwitch)
|
|
|
|
<< "Received suspicious message with unknown "
|
|
|
|
"treatment:"
|
|
|
|
<< action.treatmentString;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// monitored chats are received over irc; in the future, we will use pubsub instead
|
|
|
|
if (action.treatment !=
|
|
|
|
PubSubLowTrustUsersMessage::Treatment::Restricted)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getSettings()->streamerModeHideModActions &&
|
2024-03-01 21:12:02 +01:00
|
|
|
this->getStreamerMode()->isEnabled())
|
2023-12-31 11:44:55 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto chan =
|
|
|
|
this->twitch->getChannelOrEmptyByID(action.channelID);
|
|
|
|
|
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-06 14:22:00 +01:00
|
|
|
auto twitchChannel =
|
|
|
|
std::dynamic_pointer_cast<TwitchChannel>(chan);
|
|
|
|
if (!twitchChannel)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
postToThread([twitchChannel, action] {
|
2023-12-31 11:44:55 +01:00
|
|
|
const auto p =
|
|
|
|
TwitchMessageBuilder::makeLowTrustUserMessage(
|
2024-01-06 14:22:00 +01:00
|
|
|
action, twitchChannel->getName(),
|
|
|
|
twitchChannel.get());
|
|
|
|
twitchChannel->addMessage(p.first);
|
|
|
|
twitchChannel->addMessage(p.second);
|
2023-12-31 11:44:55 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
std::ignore =
|
2024-01-06 13:18:37 +01:00
|
|
|
this->twitchPubSub->moderation.suspiciousTreatmentUpdated.connect(
|
|
|
|
[&](const auto &action) {
|
2023-12-31 11:44:55 +01:00
|
|
|
if (action.treatment ==
|
|
|
|
PubSubLowTrustUsersMessage::Treatment::INVALID)
|
|
|
|
{
|
|
|
|
qCWarning(chatterinoTwitch)
|
|
|
|
<< "Received suspicious user update with unknown "
|
|
|
|
"treatment:"
|
|
|
|
<< action.treatmentString;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action.updatedByUserLogin.isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getSettings()->streamerModeHideModActions &&
|
2024-03-01 21:12:02 +01:00
|
|
|
this->getStreamerMode()->isEnabled())
|
2023-12-31 11:44:55 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto chan =
|
|
|
|
this->twitch->getChannelOrEmptyByID(action.channelID);
|
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
postToThread([chan, action] {
|
|
|
|
auto msg =
|
|
|
|
TwitchMessageBuilder::makeLowTrustUpdateMessage(action);
|
|
|
|
chan->addMessage(msg);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.autoModMessageCaught.connect(
|
|
|
|
[&](const auto &msg, const QString &channelID) {
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(channelID);
|
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2022-05-07 20:48:10 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
switch (msg.type)
|
|
|
|
{
|
|
|
|
case PubSubAutoModQueueMessage::Type::AutoModCaughtMessage: {
|
|
|
|
if (msg.status == "PENDING")
|
|
|
|
{
|
|
|
|
AutomodAction action(msg.data, channelID);
|
|
|
|
action.reason = QString("%1 level %2")
|
|
|
|
.arg(msg.contentCategory)
|
|
|
|
.arg(msg.contentLevel);
|
2022-05-07 17:22:39 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
action.msgID = msg.messageID;
|
|
|
|
action.message = msg.messageText;
|
2022-05-07 17:22:39 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
// this message also contains per-word automod data, which could be implemented
|
2022-05-07 17:22:39 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
// extract sender data manually because Twitch loves not being consistent
|
|
|
|
QString senderDisplayName =
|
|
|
|
msg.senderUserDisplayName; // Might be transformed later
|
|
|
|
bool hasLocalizedName = false;
|
|
|
|
if (!msg.senderUserDisplayName.isEmpty())
|
|
|
|
{
|
|
|
|
// check for non-ascii display names
|
|
|
|
if (QString::compare(msg.senderUserDisplayName,
|
|
|
|
msg.senderUserLogin,
|
|
|
|
Qt::CaseInsensitive) != 0)
|
2022-05-07 17:22:39 +02:00
|
|
|
{
|
2024-01-06 13:18:37 +01:00
|
|
|
hasLocalizedName = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QColor senderColor = msg.senderUserChatColor;
|
|
|
|
QString senderColor_;
|
|
|
|
if (!senderColor.isValid() &&
|
|
|
|
getSettings()->colorizeNicknames)
|
|
|
|
{
|
|
|
|
// color may be not present if user is a grey-name
|
|
|
|
senderColor = getRandomColor(msg.senderUserID);
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle username style based on prefered setting
|
|
|
|
switch (getSettings()->usernameDisplayMode.getValue())
|
|
|
|
{
|
|
|
|
case UsernameDisplayMode::Username: {
|
|
|
|
if (hasLocalizedName)
|
2022-05-07 17:22:39 +02:00
|
|
|
{
|
2024-01-06 13:18:37 +01:00
|
|
|
senderDisplayName = msg.senderUserLogin;
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
break;
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
case UsernameDisplayMode::LocalizedName: {
|
|
|
|
break;
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
case UsernameDisplayMode::
|
|
|
|
UsernameAndLocalizedName: {
|
|
|
|
if (hasLocalizedName)
|
|
|
|
{
|
|
|
|
senderDisplayName = QString("%1(%2)").arg(
|
|
|
|
msg.senderUserLogin,
|
|
|
|
msg.senderUserDisplayName);
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
break;
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
action.target =
|
|
|
|
ActionUser{msg.senderUserID, msg.senderUserLogin,
|
|
|
|
senderDisplayName, senderColor};
|
|
|
|
postToThread([chan, action] {
|
|
|
|
const auto p =
|
|
|
|
TwitchMessageBuilder::makeAutomodMessage(
|
|
|
|
action, chan->getName());
|
|
|
|
chan->addMessage(p.first);
|
|
|
|
chan->addMessage(p.second);
|
|
|
|
|
2024-06-01 14:56:40 +02:00
|
|
|
getIApp()
|
|
|
|
->getTwitch()
|
|
|
|
->getAutomodChannel()
|
|
|
|
->addMessage(p.first);
|
|
|
|
getIApp()
|
|
|
|
->getTwitch()
|
|
|
|
->getAutomodChannel()
|
|
|
|
->addMessage(p.second);
|
2024-03-09 12:03:36 +01:00
|
|
|
|
|
|
|
if (getSettings()->showAutomodInMentions)
|
|
|
|
{
|
2024-06-01 14:56:40 +02:00
|
|
|
getIApp()
|
|
|
|
->getTwitch()
|
|
|
|
->getMentionsChannel()
|
|
|
|
->addMessage(p.first);
|
|
|
|
getIApp()
|
|
|
|
->getTwitch()
|
|
|
|
->getMentionsChannel()
|
|
|
|
->addMessage(p.second);
|
2024-03-09 12:03:36 +01:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
});
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
// "ALLOWED" and "DENIED" statuses remain unimplemented
|
|
|
|
// They are versions of automod_message_(denied|approved) but for mods.
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
break;
|
2019-01-20 01:02:04 +01:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
case PubSubAutoModQueueMessage::Type::INVALID:
|
|
|
|
default: {
|
2022-05-07 17:22:39 +02:00
|
|
|
}
|
2024-01-06 13:18:37 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2022-05-07 20:48:10 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.autoModMessageBlocked.connect(
|
|
|
|
[&](const auto &action) {
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
postToThread([chan, action] {
|
|
|
|
const auto p = TwitchMessageBuilder::makeAutomodMessage(
|
|
|
|
action, chan->getName());
|
|
|
|
chan->addMessage(p.first);
|
|
|
|
chan->addMessage(p.second);
|
2022-05-07 20:48:10 +02:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
});
|
2022-05-07 17:22:39 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.automodUserMessage.connect(
|
|
|
|
[&](const auto &action) {
|
2024-03-01 21:12:02 +01:00
|
|
|
if (getSettings()->streamerModeHideModActions &&
|
|
|
|
this->getStreamerMode()->isEnabled())
|
2024-01-06 13:18:37 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2019-01-21 18:33:57 +01:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2019-01-21 18:33:57 +01:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
auto msg = MessageBuilder(action).release();
|
2019-01-21 18:33:57 +01:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
postToThread([chan, msg] {
|
|
|
|
chan->addMessage(msg);
|
2020-11-08 12:02:19 +01:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
chan->deleteMessage(msg->id);
|
|
|
|
});
|
2019-01-21 18:33:57 +01:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore = this->twitchPubSub->moderation.automodInfoMessage.connect(
|
|
|
|
[&](const auto &action) {
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
2021-05-08 14:49:30 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-05-08 14:49:30 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
postToThread([chan, action] {
|
|
|
|
const auto p =
|
|
|
|
TwitchMessageBuilder::makeAutomodInfoMessage(action);
|
|
|
|
chan->addMessage(p);
|
2021-05-08 14:49:30 +02:00
|
|
|
});
|
2024-01-06 13:18:37 +01:00
|
|
|
});
|
2021-05-08 14:49:30 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
std::ignore =
|
|
|
|
this->twitchPubSub->pointReward.redeemed.connect([&](auto &data) {
|
2022-05-07 17:22:39 +02:00
|
|
|
QString channelId = data.value("channel_id").toString();
|
|
|
|
if (channelId.isEmpty())
|
2022-03-19 12:02:29 +01:00
|
|
|
{
|
|
|
|
qCDebug(chatterinoApp)
|
|
|
|
<< "Couldn't find channel id of point reward";
|
2022-05-07 17:22:39 +02:00
|
|
|
return;
|
2022-03-19 12:02:29 +01:00
|
|
|
}
|
2022-05-07 17:22:39 +02:00
|
|
|
|
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(channelId);
|
|
|
|
|
|
|
|
auto reward = ChannelPointReward(data);
|
|
|
|
|
|
|
|
postToThread([chan, reward] {
|
2024-01-14 17:54:52 +01:00
|
|
|
if (auto *channel = dynamic_cast<TwitchChannel *>(chan.get()))
|
2022-05-07 17:22:39 +02:00
|
|
|
{
|
|
|
|
channel->addChannelPointReward(reward);
|
|
|
|
}
|
|
|
|
});
|
2022-03-19 12:02:29 +01:00
|
|
|
});
|
2020-08-08 15:37:22 +02:00
|
|
|
|
2024-01-06 13:18:37 +01:00
|
|
|
this->twitchPubSub->start();
|
|
|
|
this->twitchPubSub->setAccount(this->accounts->twitch.getCurrent());
|
2018-04-15 15:09:31 +02:00
|
|
|
|
2022-05-07 17:22:39 +02:00
|
|
|
this->accounts->twitch.currentUserChanged.connect(
|
2022-12-24 12:56:11 +01:00
|
|
|
[this] {
|
2024-01-06 13:18:37 +01:00
|
|
|
this->twitchPubSub->unlistenChannelModerationActions();
|
|
|
|
this->twitchPubSub->unlistenAutomod();
|
|
|
|
this->twitchPubSub->unlistenLowTrustUsers();
|
|
|
|
this->twitchPubSub->unlistenChannelPointRewards();
|
|
|
|
|
|
|
|
this->twitchPubSub->setAccount(this->accounts->twitch.getCurrent());
|
2022-05-07 17:22:39 +02:00
|
|
|
},
|
|
|
|
boost::signals2::at_front);
|
2017-06-13 21:13:58 +02:00
|
|
|
}
|
|
|
|
|
2023-01-21 15:06:55 +01:00
|
|
|
void Application::initBttvLiveUpdates()
|
|
|
|
{
|
2024-06-01 14:56:40 +02:00
|
|
|
auto &bttvLiveUpdates = this->twitch->getBTTVLiveUpdates();
|
|
|
|
|
|
|
|
if (!bttvLiveUpdates)
|
2023-01-21 15:06:55 +01:00
|
|
|
{
|
|
|
|
qCDebug(chatterinoBttv)
|
|
|
|
<< "Skipping initialization of Live Updates as it's disabled";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:52:51 +02:00
|
|
|
// We can safely ignore these signal connections since the twitch object will always
|
|
|
|
// be destroyed before the Application
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
bttvLiveUpdates->signals_.emoteAdded.connect([&](const auto &data) {
|
2023-01-21 15:06:55 +01:00
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
|
|
|
|
|
|
|
postToThread([chan, data] {
|
|
|
|
if (auto *channel = dynamic_cast<TwitchChannel *>(chan.get()))
|
|
|
|
{
|
|
|
|
channel->addBttvEmote(data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
bttvLiveUpdates->signals_.emoteUpdated.connect([&](const auto &data) {
|
2023-01-21 15:06:55 +01:00
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
|
|
|
|
|
|
|
postToThread([chan, data] {
|
|
|
|
if (auto *channel = dynamic_cast<TwitchChannel *>(chan.get()))
|
|
|
|
{
|
|
|
|
channel->updateBttvEmote(data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
bttvLiveUpdates->signals_.emoteRemoved.connect([&](const auto &data) {
|
2023-01-21 15:06:55 +01:00
|
|
|
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
|
|
|
|
|
|
|
postToThread([chan, data] {
|
|
|
|
if (auto *channel = dynamic_cast<TwitchChannel *>(chan.get()))
|
|
|
|
{
|
|
|
|
channel->removeBttvEmote(data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2024-06-01 14:56:40 +02:00
|
|
|
bttvLiveUpdates->start();
|
2023-01-21 15:06:55 +01:00
|
|
|
}
|
|
|
|
|
2022-11-13 12:07:41 +01:00
|
|
|
void Application::initSeventvEventAPI()
|
|
|
|
{
|
2024-06-01 14:56:40 +02:00
|
|
|
auto &seventvEventAPI = this->twitch->getSeventvEventAPI();
|
|
|
|
|
|
|
|
if (!seventvEventAPI)
|
2022-11-13 12:07:41 +01:00
|
|
|
{
|
|
|
|
qCDebug(chatterinoSeventvEventAPI)
|
|
|
|
<< "Skipping initialization as the EventAPI is disabled";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:52:51 +02:00
|
|
|
// We can safely ignore these signal connections since the twitch object will always
|
|
|
|
// be destroyed before the Application
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
seventvEventAPI->signals_.emoteAdded.connect([&](const auto &data) {
|
2022-11-13 12:07:41 +01:00
|
|
|
postToThread([this, data] {
|
|
|
|
this->twitch->forEachSeventvEmoteSet(
|
|
|
|
data.emoteSetID, [data](TwitchChannel &chan) {
|
|
|
|
chan.addSeventvEmote(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
seventvEventAPI->signals_.emoteUpdated.connect([&](const auto &data) {
|
2022-11-13 12:07:41 +01:00
|
|
|
postToThread([this, data] {
|
|
|
|
this->twitch->forEachSeventvEmoteSet(
|
|
|
|
data.emoteSetID, [data](TwitchChannel &chan) {
|
|
|
|
chan.updateSeventvEmote(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
seventvEventAPI->signals_.emoteRemoved.connect([&](const auto &data) {
|
2022-11-13 12:07:41 +01:00
|
|
|
postToThread([this, data] {
|
|
|
|
this->twitch->forEachSeventvEmoteSet(
|
|
|
|
data.emoteSetID, [data](TwitchChannel &chan) {
|
|
|
|
chan.removeSeventvEmote(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2024-06-01 14:56:40 +02:00
|
|
|
std::ignore =
|
|
|
|
seventvEventAPI->signals_.userUpdated.connect([&](const auto &data) {
|
2022-11-13 12:07:41 +01:00
|
|
|
this->twitch->forEachSeventvUser(data.userID,
|
|
|
|
[data](TwitchChannel &chan) {
|
|
|
|
chan.updateSeventvUser(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-06-01 14:56:40 +02:00
|
|
|
seventvEventAPI->start();
|
2022-11-13 12:07:41 +01:00
|
|
|
}
|
|
|
|
|
2018-04-27 22:11:19 +02:00
|
|
|
Application *getApp()
|
|
|
|
{
|
2018-08-02 14:23:27 +02:00
|
|
|
assert(Application::instance != nullptr);
|
2018-01-05 02:38:00 +01:00
|
|
|
|
2018-08-02 14:23:27 +02:00
|
|
|
return Application::instance;
|
2017-12-22 14:44:31 +01:00
|
|
|
}
|
|
|
|
|
2022-05-22 15:00:18 +02:00
|
|
|
IApplication *getIApp()
|
|
|
|
{
|
|
|
|
assert(IApplication::instance != nullptr);
|
|
|
|
|
|
|
|
return IApplication::instance;
|
|
|
|
}
|
|
|
|
|
2017-06-13 21:13:58 +02:00
|
|
|
} // namespace chatterino
|