From d07b5dd2ba1f1f7bc008da9f496c6431a855413f Mon Sep 17 00:00:00 2001 From: Suman Manjunath Date: Mon, 3 Jun 2024 20:16:49 +0000 Subject: [PATCH] UI: Enable first-party YouTube Chat features in OBS Unlock the full feature set of the YouTube Chat dock in OBS by removing custom scripting/CSS logic. Enable the signed-in experience for live streaming content creators (sharing login credentials with the YouTube Control panel dock, see https://github.com/obsproject/obs-studio/pull/10747). This will allow OBS users to utilize features _already_ supported in the YouTube Chat plugin, such as * creating polls * managing Q&A sessions * a rich emoji set in the input panel * emoji fountains * moderation tools and many more. These features are available to users who are logged-in to YouTube Chat and/or the YouTube Control panel. --- UI/auth-youtube.cpp | 52 ++++++++++++++++++++++++++-------- UI/auth-youtube.hpp | 9 +++++- UI/window-dock-youtube-app.hpp | 4 ++- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/UI/auth-youtube.cpp b/UI/auth-youtube.cpp index d9ba1e4c0e93b5..586268df5d589b 100644 --- a/UI/auth-youtube.cpp +++ b/UI/auth-youtube.cpp @@ -26,6 +26,7 @@ #ifdef BROWSER_AVAILABLE #include "window-dock-browser.hpp" +#include #endif using namespace json11; @@ -138,14 +139,6 @@ bool YoutubeAuth::LoadInternal() return implicit ? !token.empty() : !refresh_token.empty(); } -#ifdef BROWSER_AVAILABLE -static const char *ytchat_script = "\ -const obsCSS = document.createElement('style');\ -obsCSS.innerHTML = \"#panel-pages.yt-live-chat-renderer {display: none;}\ -yt-live-chat-viewer-engagement-message-renderer {display: none;}\";\ -document.querySelector('head').appendChild(obsCSS);"; -#endif - void YoutubeAuth::LoadUI() { if (uiLoaded) @@ -171,7 +164,6 @@ void YoutubeAuth::LoadUI() browser = cef->create_widget(chat, YOUTUBE_CHAT_PLACEHOLDER_URL, panel_cookies); - browser->setStartupScript(ytchat_script); chat->SetWidget(browser); main->AddDockWidget(chat, Qt::RightDockWidgetArea); @@ -358,6 +350,38 @@ std::shared_ptr YoutubeAuth::Login(QWidget *owner, } #ifdef BROWSER_AVAILABLE +void YoutubeChatDock::timerEvent(QTimerEvent *event) +{ + if (event->timerId() != awaitLoginTimer) + return; + + QPointer this_ = this; + auto cb = [this_](bool currentlyLoggedIn) { + bool previouslyLoggedIn = this_->isLoggedIn; + this_->isLoggedIn = currentlyLoggedIn; + bool loginStateChanged = + (currentlyLoggedIn && !previouslyLoggedIn) || + (!currentlyLoggedIn && previouslyLoggedIn); + if (loginStateChanged) { + QMetaObject::invokeMethod( + this_, "EnableChatInput", Qt::QueuedConnection, + Q_ARG(bool, !currentlyLoggedIn)); + this_->cefWidget->reloadPage(); + OBSBasic *main = OBSBasic::Get(); + if (main->GetYouTubeAppDock() != nullptr) { + QMetaObject::invokeMethod( + main->GetYouTubeAppDock(), + "SettingsUpdated", Qt::QueuedConnection, + Q_ARG(bool, !currentlyLoggedIn)); + } + } + }; + if (panel_cookies) { + panel_cookies->CheckForCookie("https://www.youtube.com", "SID", + cb); + } +} + YoutubeChatDock::YoutubeChatDock(const QString &title) : BrowserDock(title) { lineEdit = new LineEditAutoResize(); @@ -376,6 +400,9 @@ YoutubeChatDock::YoutubeChatDock(const QString &title) : BrowserDock(title) &YoutubeChatDock::SendChatMessage); QWidget::connect(sendButton, &QPushButton::pressed, this, &YoutubeChatDock::SendChatMessage); + + // Check youtube.com login status periodically + awaitLoginTimer = startTimer(1000); } void YoutubeChatDock::SetWidget(QCefWidget *widget_) @@ -433,9 +460,10 @@ void YoutubeChatDock::ShowErrorMessage(const QString &error) QTStr("YouTube.Chat.Error.Text").arg(error)); } -void YoutubeChatDock::EnableChatInput() +void YoutubeChatDock::EnableChatInput(bool visible) { - lineEdit->setVisible(true); - sendButton->setVisible(true); + bool setVisible = visible && !isLoggedIn; + lineEdit->setVisible(setVisible); + sendButton->setVisible(setVisible); } #endif diff --git a/UI/auth-youtube.hpp b/UI/auth-youtube.hpp index 2e51cb48afdc59..18e797c61a514c 100644 --- a/UI/auth-youtube.hpp +++ b/UI/auth-youtube.hpp @@ -11,15 +11,22 @@ #include "window-dock-browser.hpp" #include "lineedit-autoresize.hpp" #include +#include + class YoutubeChatDock : public BrowserDock { Q_OBJECT private: std::string apiChatId; + int awaitLoginTimer; + bool isLoggedIn; LineEditAutoResize *lineEdit; QPushButton *sendButton; QHBoxLayout *chatLayout; +protected: + void timerEvent(QTimerEvent *event); + public: YoutubeChatDock(const QString &title); void SetWidget(QCefWidget *widget_); @@ -28,7 +35,7 @@ class YoutubeChatDock : public BrowserDock { private slots: void SendChatMessage(); void ShowErrorMessage(const QString &error); - void EnableChatInput(); + void EnableChatInput(bool visible = true); }; #endif diff --git a/UI/window-dock-youtube-app.hpp b/UI/window-dock-youtube-app.hpp index ab47de4a2ddb58..a36d7ca3c47c10 100644 --- a/UI/window-dock-youtube-app.hpp +++ b/UI/window-dock-youtube-app.hpp @@ -16,7 +16,6 @@ class YouTubeAppDock : public BrowserDock { void AccountConnected(); void AccountDisconnected(); - void SettingsUpdated(bool cleanup = false); void Update(); void BroadcastCreated(const char *stream_id); @@ -28,6 +27,9 @@ class YouTubeAppDock : public BrowserDock { static YoutubeApiWrappers *GetYTApi(); static void CleanupYouTubeUrls(); +public slots: + void SettingsUpdated(bool cleanup = false); + protected: void IngestionStarted(const char *stream_id, streaming_mode_t mode); void IngestionStopped(const char *stream_id, streaming_mode_t mode);