瀏覽代碼

UI: Add ability to send messages to YouTube chat

gxalpha 3 年之前
父節點
當前提交
3513c78be2
共有 4 個文件被更改,包括 125 次插入10 次删除
  1. 85 3
      UI/auth-youtube.cpp
  2. 23 3
      UI/auth-youtube.hpp
  3. 6 0
      UI/data/locale/en-US.ini
  4. 11 4
      UI/window-youtube-actions.cpp

+ 85 - 3
UI/auth-youtube.cpp

@@ -141,7 +141,7 @@ void YoutubeAuth::LoadUI()
 	QSize size = main->frameSize();
 	QPoint pos = main->pos();
 
-	chat.reset(new BrowserDock());
+	chat.reset(new YoutubeChatDock());
 	chat->setObjectName("ytChat");
 	chat->resize(300, 600);
 	chat->setMinimumSize(200, 300);
@@ -173,16 +173,18 @@ void YoutubeAuth::LoadUI()
 	uiLoaded = true;
 }
 
-void YoutubeAuth::SetChatId(QString &chat_id)
+void YoutubeAuth::SetChatId(const QString &chat_id,
+			    const std::string &api_chat_id)
 {
 #ifdef BROWSER_AVAILABLE
 	QString chat_url = QString(YOUTUBE_CHAT_POPOUT_URL).arg(chat_id);
 
 	if (chat && chat->cefWidget) {
 		chat->cefWidget->setURL(chat_url.toStdString());
+		chat->SetApiChatId(api_chat_id);
 	}
 #else
-	UNUSED_PARAMETER(chat_id);
+	UNUSED_PARAMETER(chat_id, api_chat_id);
 #endif
 }
 
@@ -322,3 +324,83 @@ std::shared_ptr<Auth> YoutubeAuth::Login(QWidget *owner,
 	config_save_safe(config, "tmp", nullptr);
 	return auth;
 }
+
+#ifdef BROWSER_AVAILABLE
+void YoutubeChatDock::SetWidget(QCefWidget *widget_)
+{
+	lineEdit = new LineEditAutoResize();
+	lineEdit->setVisible(false);
+	lineEdit->setMaxLength(200);
+	lineEdit->setPlaceholderText(QTStr("YouTube.Chat.Input.Placeholder"));
+	sendButton = new QPushButton(QTStr("YouTube.Chat.Input.Send"));
+	sendButton->setVisible(false);
+
+	chatLayout = new QHBoxLayout();
+	chatLayout->setMargin(0);
+	chatLayout->addWidget(lineEdit, 1);
+	chatLayout->addWidget(sendButton);
+
+	QVBoxLayout *layout = new QVBoxLayout();
+	layout->setMargin(0);
+	layout->addWidget(widget_, 1);
+	layout->addLayout(chatLayout);
+
+	QWidget *widget = new QWidget();
+	widget->setLayout(layout);
+	setWidget(widget);
+
+	QWidget::connect(lineEdit, SIGNAL(returnPressed()), this,
+			 SLOT(SendChatMessage()));
+	QWidget::connect(sendButton, SIGNAL(pressed()), this,
+			 SLOT(SendChatMessage()));
+
+	cefWidget.reset(widget_);
+}
+
+void YoutubeChatDock::SetApiChatId(const std::string &id)
+{
+	this->apiChatId = id;
+	QMetaObject::invokeMethod(this, "EnableChatInput",
+				  Qt::QueuedConnection);
+}
+
+void YoutubeChatDock::SendChatMessage()
+{
+	const QString message = lineEdit->text();
+	if (message == "")
+		return;
+
+	OBSBasic *main = OBSBasic::Get();
+	YoutubeApiWrappers *apiYouTube(
+		dynamic_cast<YoutubeApiWrappers *>(main->GetAuth()));
+
+	ExecuteFuncSafeBlock([&]() {
+		lineEdit->setText("");
+		lineEdit->setPlaceholderText(
+			QTStr("YouTube.Chat.Input.Sending"));
+		if (apiYouTube->SendChatMessage(apiChatId, message)) {
+			os_sleep_ms(3000);
+		} else {
+			QString error = apiYouTube->GetLastError();
+			apiYouTube->GetTranslatedError(error);
+			QMetaObject::invokeMethod(
+				this, "ShowErrorMessage", Qt::QueuedConnection,
+				Q_ARG(const QString &, error));
+		}
+		lineEdit->setPlaceholderText(
+			QTStr("YouTube.Chat.Input.Placeholder"));
+	});
+}
+
+void YoutubeChatDock::ShowErrorMessage(const QString &error)
+{
+	QMessageBox::warning(this, QTStr("YouTube.Chat.Error.Title"),
+			     QTStr("YouTube.Chat.Error.Text").arg(error));
+}
+
+void YoutubeChatDock::EnableChatInput()
+{
+	lineEdit->setVisible(true);
+	sendButton->setVisible(true);
+}
+#endif

+ 23 - 3
UI/auth-youtube.hpp

@@ -8,7 +8,27 @@
 #include "auth-oauth.hpp"
 
 #ifdef BROWSER_AVAILABLE
-class BrowserDock;
+#include "window-dock-browser.hpp"
+#include "lineedit-autoresize.hpp"
+#include <QHBoxLayout>
+class YoutubeChatDock : public BrowserDock {
+	Q_OBJECT
+
+private:
+	std::string apiChatId;
+	LineEditAutoResize *lineEdit;
+	QPushButton *sendButton;
+	QHBoxLayout *chatLayout;
+
+public:
+	void SetWidget(QCefWidget *widget_);
+	void SetApiChatId(const std::string &id);
+
+private slots:
+	void SendChatMessage();
+	void ShowErrorMessage(const QString &error);
+	void EnableChatInput();
+};
 #endif
 
 inline const std::vector<Auth::Def> youtubeServices = {
@@ -24,7 +44,7 @@ class YoutubeAuth : public OAuthStreamKey {
 	std::string section;
 
 #ifdef BROWSER_AVAILABLE
-	QSharedPointer<BrowserDock> chat;
+	QSharedPointer<YoutubeChatDock> chat;
 	QSharedPointer<QAction> chatMenu;
 #endif
 
@@ -38,7 +58,7 @@ class YoutubeAuth : public OAuthStreamKey {
 public:
 	YoutubeAuth(const Def &d);
 
-	void SetChatId(QString &chat_id);
+	void SetChatId(const QString &chat_id, const std::string &api_chat_id);
 	void ResetChat();
 
 	static std::shared_ptr<Auth> Login(QWidget *parent,

+ 6 - 0
UI/data/locale/en-US.ini

@@ -1320,6 +1320,12 @@ YouTube.Actions.AutoStartStreamingWarning.Title="Manual start required"
 YouTube.Actions.AutoStartStreamingWarning="Auto-start is disabled for this event, click \"Go Live\" to start your broadcast."
 YouTube.Actions.AutoStopStreamingWarning="You will not be able to reconnect.<br>Your stream will stop and you will no longer be live."
 
+YouTube.Chat.Input.Send="Send"
+YouTube.Chat.Input.Placeholder="Enter message here..."
+YouTube.Chat.Input.Sending="Sending..."
+YouTube.Chat.Error.Title="Error while sending message"
+YouTube.Chat.Error.Text="The message couldn't be sent: %1"
+
 # YouTube API errors in format "YouTube.Errors.<error reason>"
 YouTube.Errors.liveStreamingNotEnabled="Live streaming is not enabled on the selected YouTube channel.<br/><br/>See <a href='https://www.youtube.com/features'>youtube.com/features</a> for more information."
 YouTube.Errors.livePermissionBlocked="Live streaming is unavailable on the selected YouTube Channel.<br/>Please note that it may take up to 24 hours for live streaming to become available after enabling it in your channel settings.<br/><br/>See <a href='https://www.youtube.com/features'>youtube.com/features</a> for details."

+ 11 - 4
UI/window-youtube-actions.cpp

@@ -503,10 +503,13 @@ bool OBSYoutubeActions::CreateEventAction(YoutubeApiWrappers *api,
 			return false;
 		}
 
-		if (broadcast.privacy != "private")
-			apiYouTube->SetChatId(broadcast.id);
-		else
+		if (broadcast.privacy != "private") {
+			const std::string apiLiveChatId =
+				json["snippet"]["liveChatId"].string_value();
+			apiYouTube->SetChatId(broadcast.id, apiLiveChatId);
+		} else {
 			apiYouTube->ResetChat();
+		}
 	}
 
 	return true;
@@ -531,6 +534,10 @@ bool OBSYoutubeActions::ChooseAnEventAction(YoutubeApiWrappers *api,
 		json["items"]
 			.array_items()[0]["status"]["privacyStatus"]
 			.string_value();
+	std::string apiLiveChatId =
+		json["items"]
+			.array_items()[0]["snippet"]["liveChatId"]
+			.string_value();
 
 	stream.id = boundStreamId.c_str();
 	if (!stream.id.isEmpty() && apiYouTube->FindStream(stream.id, json)) {
@@ -556,7 +563,7 @@ bool OBSYoutubeActions::ChooseAnEventAction(YoutubeApiWrappers *api,
 	}
 
 	if (broadcastPrivacy != "private")
-		apiYouTube->SetChatId(selectedBroadcast);
+		apiYouTube->SetChatId(selectedBroadcast, apiLiveChatId);
 	else
 		apiYouTube->ResetChat();