From fca62f7c1d486019177eb896eb5a0f98cb220a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sat, 9 Jan 2021 22:14:25 +0100 Subject: [PATCH] Added automatic streamer mode detection to Linux (#2316) --- CHANGELOG.md | 2 +- src/common/QLogging.cpp | 2 + src/common/QLogging.hpp | 1 + src/providers/irc/AbstractIrcServer.cpp | 2 +- src/providers/irc/AbstractIrcServer.hpp | 4 +- src/util/StreamerMode.cpp | 131 +++++++++++++++------- src/widgets/settingspages/GeneralPage.cpp | 9 +- 7 files changed, 104 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b45309b..3f26dcf14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unversioned - Major: Added "Channel Filters". See https://wiki.chatterino.com/Filters/ for how they work or how to configure them. (#1748, #2083, #2090, #2200) -- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001) +- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001, #2316) - Major: Color mentions to match the mentioned users. You can disable this by unchecking "Color @usernames" under `Settings -> General -> Advanced (misc.)`. (#1963, #2284) - Minor: Added a button to the split context menu to open the moderation view for a channel when the account selected has moderator permissions. (#2321) - Minor: Made BetterTTV emote tooltips use authors' display name. (#2267) diff --git a/src/common/QLogging.cpp b/src/common/QLogging.cpp index ca54d6980..4a7ca2083 100644 --- a/src/common/QLogging.cpp +++ b/src/common/QLogging.cpp @@ -28,6 +28,8 @@ Q_LOGGING_CATEGORY(chatterinoNuulsuploader, "chatterino.nuulsuploader", logThreshold); Q_LOGGING_CATEGORY(chatterinoPubsub, "chatterino.pubsub", logThreshold); Q_LOGGING_CATEGORY(chatterinoStreamlink, "chatterino.streamlink", logThreshold); +Q_LOGGING_CATEGORY(chatterinoStreamerMode, "chatterino.streamermode", + logThreshold); Q_LOGGING_CATEGORY(chatterinoTokenizer, "chatterino.tokenizer", logThreshold); Q_LOGGING_CATEGORY(chatterinoTwitch, "chatterino.twitch", logThreshold); Q_LOGGING_CATEGORY(chatterinoUpdate, "chatterino.update", logThreshold); diff --git a/src/common/QLogging.hpp b/src/common/QLogging.hpp index 82e0f3e4a..b157d79a6 100644 --- a/src/common/QLogging.hpp +++ b/src/common/QLogging.hpp @@ -21,6 +21,7 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoNotification); Q_DECLARE_LOGGING_CATEGORY(chatterinoNuulsuploader); Q_DECLARE_LOGGING_CATEGORY(chatterinoPubsub); Q_DECLARE_LOGGING_CATEGORY(chatterinoStreamlink); +Q_DECLARE_LOGGING_CATEGORY(chatterinoStreamerMode); Q_DECLARE_LOGGING_CATEGORY(chatterinoTokenizer); Q_DECLARE_LOGGING_CATEGORY(chatterinoTwitch); Q_DECLARE_LOGGING_CATEGORY(chatterinoUpdate); diff --git a/src/providers/irc/AbstractIrcServer.cpp b/src/providers/irc/AbstractIrcServer.cpp index ef4ac09eb..b8396fe26 100644 --- a/src/providers/irc/AbstractIrcServer.cpp +++ b/src/providers/irc/AbstractIrcServer.cpp @@ -137,7 +137,7 @@ void AbstractIrcServer::open(ConnectionType type) } } -void AbstractIrcServer::addGlobalSystemMessage(QString messageText) +void AbstractIrcServer::addGlobalSystemMessage(const QString &messageText) { std::lock_guard lock(this->channelMutex); diff --git a/src/providers/irc/AbstractIrcServer.hpp b/src/providers/irc/AbstractIrcServer.hpp index ece9cfe1b..de3a61ff5 100644 --- a/src/providers/irc/AbstractIrcServer.hpp +++ b/src/providers/irc/AbstractIrcServer.hpp @@ -43,6 +43,8 @@ public: void addFakeMessage(const QString &data); + void addGlobalSystemMessage(const QString &messageText); + // iteration void forEachChannel(std::function func); @@ -78,8 +80,6 @@ protected: void open(ConnectionType type); - void addGlobalSystemMessage(QString messageText); - QMap> channels; std::mutex channelMutex; diff --git a/src/util/StreamerMode.cpp b/src/util/StreamerMode.cpp index 799ae8d41..38d90a79a 100644 --- a/src/util/StreamerMode.cpp +++ b/src/util/StreamerMode.cpp @@ -1,6 +1,15 @@ #include "StreamerMode.hpp" +#include "Application.hpp" +#include "common/QLogging.hpp" +#include "messages/MessageBuilder.hpp" +#include "providers/twitch/TwitchIrcServer.hpp" #include "singletons/Settings.hpp" +#include "singletons/WindowManager.hpp" +#include "widgets/Notebook.hpp" +#include "widgets/Window.hpp" +#include "widgets/helper/NotebookTab.hpp" +#include "widgets/splits/Split.hpp" #ifdef USEWINSDK # include @@ -14,12 +23,14 @@ namespace chatterino { constexpr int cooldownInS = 10; +bool shouldShowWarning = true; + const QStringList &broadcastingBinaries() { #ifdef USEWINSDK static QStringList bins = {"obs.exe", "obs64.exe"}; #else - static QStringList bins = {}; + static QStringList bins = {"obs"}; #endif return bins; } @@ -32,51 +43,93 @@ bool isInStreamerMode() return true; case StreamerModeSetting::Disabled: return false; - } + case StreamerModeSetting::DetectObs: + +#ifdef Q_OS_LINUX + + static bool cache = false; + static QDateTime time = QDateTime(); + + if (time.isValid() && + time.addSecs(cooldownInS) > QDateTime::currentDateTime()) + { + return cache; + } + time = QDateTime::currentDateTime(); + + QProcess p; + p.start("pgrep", {"-x", broadcastingBinaries().join("|")}, + QIODevice::NotOpen); + + if (p.waitForFinished(1000) && + p.exitStatus() == QProcess::NormalExit) + { + cache = (p.exitCode() == 0); + return (p.exitCode() == 0); + } + + // Fallback to false and showing a warning + + if (shouldShowWarning) + { + shouldShowWarning = false; + + getApp()->twitch2->addGlobalSystemMessage( + "Streamer Mode is set to Automatic, but pgrep is missing. " + "Install it to fix the issue or set Streamer Mode to " + "Enabled or Disabled in the Settings."); + } + + qCWarning(chatterinoStreamerMode) << "pgrep execution timed out!"; + + cache = false; + return false; +#endif #ifdef USEWINSDK - if (!IsWindowsVistaOrGreater()) - { - return false; - } - static bool cache = false; - static QDateTime time = QDateTime(); - - if (time.isValid() && - time.addSecs(cooldownInS) > QDateTime::currentDateTime()) - { - return cache; - } - - time = QDateTime::currentDateTime(); - - WTS_PROCESS_INFO *pWPIs = nullptr; - DWORD dwProcCount = 0; - - if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, NULL, 1, &pWPIs, - &dwProcCount)) - { - //Go through all processes retrieved - for (DWORD i = 0; i < dwProcCount; i++) - { - QString processName = QString::fromUtf16( - reinterpret_cast(pWPIs[i].pProcessName)); - - if (broadcastingBinaries().contains(processName)) + if (!IsWindowsVistaOrGreater()) { - cache = true; - return true; + return false; } - } - } + static bool cache = false; + static QDateTime time = QDateTime(); - if (pWPIs) - { - WTSFreeMemory(pWPIs); - } + if (time.isValid() && + time.addSecs(cooldownInS) > QDateTime::currentDateTime()) + { + return cache; + } + time = QDateTime::currentDateTime(); - cache = false; + WTS_PROCESS_INFO *pWPIs = nullptr; + DWORD dwProcCount = 0; + + if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, NULL, 1, + &pWPIs, &dwProcCount)) + { + //Go through all processes retrieved + for (DWORD i = 0; i < dwProcCount; i++) + { + QString processName = QString::fromUtf16( + reinterpret_cast(pWPIs[i].pProcessName)); + + if (broadcastingBinaries().contains(processName)) + { + cache = true; + return true; + } + } + } + + if (pWPIs) + { + WTSFreeMemory(pWPIs); + } + + cache = false; #endif + return false; + } return false; } diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp index c1fb0bf2b..5a7c85d1c 100644 --- a/src/widgets/settingspages/GeneralPage.cpp +++ b/src/widgets/settingspages/GeneralPage.cpp @@ -320,13 +320,14 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addTitle("Streamer Mode"); layout.addDescription( - "Chatterino can automatically change behavior if it " - "detects that \"OBS Studio\" is running.\nSelect which " - "things you want to change while streaming"); + "Chatterino can automatically change behavior if it detects that \"OBS " + "Studio\" is running (Automatic mode works only on Windows and " + "Linux).\nSelect which things you want to change while streaming"); ComboBox *dankDropdown = layout.addDropdown::type>( - "Enable Streamer Mode", {"No", "Yes", "Detect OBS (Windows only)"}, + "Enable Streamer Mode", + {"Disabled", "Enabled", "Automatic (Detect OBS)"}, s.enableStreamerMode, [](int value) { return value;