2013-11-07 16:45:03 -07:00
|
|
|
/******************************************************************************
|
2023-05-18 17:37:26 -07:00
|
|
|
Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
|
|
|
|
|
Zachary Lund <admin@computerquip.com>
|
|
|
|
|
Philippe Groarke <philippe.groarke@gmail.com>
|
2013-11-07 16:45:03 -07:00
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2013-12-02 22:24:38 -07:00
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
2013-11-07 16:45:03 -07:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
2013-11-09 00:19:38 -07:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2013-11-07 16:45:03 -07:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
#include "OBSBasic.hpp"
|
2019-09-27 15:04:07 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
#ifdef YOUTUBE_ENABLED
|
|
|
|
|
#include <dialogs/OBSYoutubeActions.hpp>
|
|
|
|
|
#include <docks/YouTubeAppDock.hpp>
|
|
|
|
|
#include <utility/YoutubeApiWrappers.hpp>
|
|
|
|
|
#endif
|
2019-12-27 17:12:31 +08:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
#include <qt-wrappers.hpp>
|
2019-12-27 17:12:31 +08:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
using namespace std;
|
2020-09-08 20:29:40 -07:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
extern bool cef_js_avail;
|
2024-03-28 16:43:12 -04:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
#ifdef YOUTUBE_ENABLED
|
|
|
|
|
void OBSBasic::YouTubeActionDialogOk(const QString &broadcast_id, const QString &stream_id, const QString &key,
|
|
|
|
|
bool autostart, bool autostop, bool start_now)
|
2024-03-28 16:43:12 -04:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
//blog(LOG_DEBUG, "Stream key: %s", QT_TO_UTF8(key));
|
|
|
|
|
obs_service_t *service_obj = GetService();
|
|
|
|
|
OBSDataAutoRelease settings = obs_service_get_settings(service_obj);
|
2019-12-27 17:12:31 +08:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
const std::string a_key = QT_TO_UTF8(key);
|
|
|
|
|
obs_data_set_string(settings, "key", a_key.c_str());
|
2019-06-12 04:56:00 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
const std::string b_id = QT_TO_UTF8(broadcast_id);
|
|
|
|
|
obs_data_set_string(settings, "broadcast_id", b_id.c_str());
|
2019-06-12 04:56:00 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
const std::string s_id = QT_TO_UTF8(stream_id);
|
|
|
|
|
obs_data_set_string(settings, "stream_id", s_id.c_str());
|
2019-09-27 15:04:07 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
obs_service_update(service_obj, settings);
|
|
|
|
|
autoStartBroadcast = autostart;
|
|
|
|
|
autoStopBroadcast = autostop;
|
|
|
|
|
broadcastReady = true;
|
2019-06-12 04:56:00 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
emit BroadcastStreamReady(broadcastReady);
|
2019-06-12 04:56:00 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
if (start_now)
|
|
|
|
|
QMetaObject::invokeMethod(this, "StartStreaming");
|
2019-06-12 04:56:00 -05:00
|
|
|
}
|
|
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::YoutubeStreamCheck(const std::string &key)
|
2019-06-12 04:56:00 -05:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
YoutubeApiWrappers *apiYouTube(dynamic_cast<YoutubeApiWrappers *>(GetAuth()));
|
|
|
|
|
if (!apiYouTube) {
|
|
|
|
|
/* technically we should never get here -Lain */
|
|
|
|
|
QMetaObject::invokeMethod(this, "ForceStopStreaming", Qt::QueuedConnection);
|
|
|
|
|
youtubeStreamCheckThread->deleteLater();
|
|
|
|
|
blog(LOG_ERROR, "==========================================");
|
|
|
|
|
blog(LOG_ERROR, "%s: Uh, hey, we got here", __FUNCTION__);
|
|
|
|
|
blog(LOG_ERROR, "==========================================");
|
|
|
|
|
return;
|
2019-06-12 04:56:00 -05:00
|
|
|
}
|
2019-10-10 20:12:20 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
int timeout = 0;
|
|
|
|
|
json11::Json json;
|
|
|
|
|
QString id = key.c_str();
|
2019-10-15 23:20:35 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
while (StreamingActive()) {
|
|
|
|
|
if (timeout == 14) {
|
|
|
|
|
QMetaObject::invokeMethod(this, "ForceStopStreaming", Qt::QueuedConnection);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-02-14 23:30:34 +11:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
if (!apiYouTube->FindStream(id, json)) {
|
|
|
|
|
QMetaObject::invokeMethod(this, "DisplayStreamStartError", Qt::QueuedConnection);
|
|
|
|
|
QMetaObject::invokeMethod(this, "StopStreaming", Qt::QueuedConnection);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-02-22 00:40:17 +11:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
auto item = json["items"][0];
|
|
|
|
|
auto status = item["status"]["streamStatus"].string_value();
|
|
|
|
|
if (status == "active") {
|
|
|
|
|
emit BroadcastStreamActive();
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
QThread::sleep(1);
|
|
|
|
|
timeout++;
|
2022-02-22 00:40:17 +11:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-09 07:20:48 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
youtubeStreamCheckThread->deleteLater();
|
2022-09-09 07:20:48 -05:00
|
|
|
}
|
|
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::ShowYouTubeAutoStartWarning()
|
2021-01-11 23:26:02 -06:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
auto msgBox = []() {
|
|
|
|
|
QMessageBox msgbox(App()->GetMainWindow());
|
|
|
|
|
msgbox.setWindowTitle(QTStr("YouTube.Actions.AutoStartStreamingWarning.Title"));
|
|
|
|
|
msgbox.setText(QTStr("YouTube.Actions.AutoStartStreamingWarning"));
|
|
|
|
|
msgbox.setIcon(QMessageBox::Icon::Information);
|
|
|
|
|
msgbox.addButton(QMessageBox::Ok);
|
2021-02-04 06:01:35 -06:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
QCheckBox *cb = new QCheckBox(QTStr("DoNotShowAgain"));
|
|
|
|
|
msgbox.setCheckBox(cb);
|
2021-08-19 23:56:49 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
msgbox.exec();
|
2020-06-27 02:31:08 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
if (cb->isChecked()) {
|
|
|
|
|
config_set_bool(App()->GetUserConfig(), "General", "WarnedAboutYouTubeAutoStart", true);
|
|
|
|
|
config_save_safe(App()->GetUserConfig(), "tmp", nullptr);
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-02-10 13:27:08 +01:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
bool warned = config_get_bool(App()->GetUserConfig(), "General", "WarnedAboutYouTubeAutoStart");
|
|
|
|
|
if (!warned) {
|
|
|
|
|
QMetaObject::invokeMethod(App(), "Exec", Qt::QueuedConnection, Q_ARG(VoidFunc, msgBox));
|
|
|
|
|
}
|
2023-02-10 13:27:08 +01:00
|
|
|
}
|
2024-12-11 17:43:35 +01:00
|
|
|
#endif
|
2023-02-10 13:27:08 +01:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::BroadcastButtonClicked()
|
2020-06-27 02:31:08 +02:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
if (!broadcastReady || (!broadcastActive && !outputHandler->StreamingActive())) {
|
|
|
|
|
SetupBroadcast();
|
2020-06-27 02:31:08 +02:00
|
|
|
return;
|
2024-12-11 17:43:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!autoStartBroadcast) {
|
|
|
|
|
#ifdef YOUTUBE_ENABLED
|
|
|
|
|
std::shared_ptr<YoutubeApiWrappers> ytAuth = dynamic_pointer_cast<YoutubeApiWrappers>(auth);
|
|
|
|
|
if (ytAuth.get()) {
|
|
|
|
|
if (!ytAuth->StartLatestBroadcast()) {
|
|
|
|
|
auto last_error = ytAuth->GetLastError();
|
|
|
|
|
if (last_error.isEmpty())
|
|
|
|
|
last_error = QTStr("YouTube.Actions.Error.YouTubeApi");
|
|
|
|
|
if (!ytAuth->GetTranslatedError(last_error))
|
|
|
|
|
last_error = QTStr("YouTube.Actions.Error.BroadcastTransitionFailed")
|
|
|
|
|
.arg(last_error, ytAuth->GetBroadcastId());
|
2020-06-27 02:31:08 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
OBSMessageBox::warning(this, QTStr("Output.BroadcastStartFailed"), last_error, true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
broadcastActive = true;
|
|
|
|
|
autoStartBroadcast = true; // and clear the flag
|
2020-06-27 02:31:08 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
emit BroadcastStreamStarted(autoStopBroadcast);
|
|
|
|
|
} else if (!autoStopBroadcast) {
|
|
|
|
|
#ifdef YOUTUBE_ENABLED
|
|
|
|
|
bool confirm = config_get_bool(App()->GetUserConfig(), "BasicWindow", "WarnBeforeStoppingStream");
|
|
|
|
|
if (confirm && isVisible()) {
|
|
|
|
|
QMessageBox::StandardButton button = OBSMessageBox::question(
|
|
|
|
|
this, QTStr("ConfirmStop.Title"), QTStr("YouTube.Actions.AutoStopStreamingWarning"),
|
|
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
2020-06-27 02:31:08 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
if (button == QMessageBox::No)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-27 02:31:08 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
std::shared_ptr<YoutubeApiWrappers> ytAuth = dynamic_pointer_cast<YoutubeApiWrappers>(auth);
|
|
|
|
|
if (ytAuth.get()) {
|
|
|
|
|
if (!ytAuth->StopLatestBroadcast()) {
|
|
|
|
|
auto last_error = ytAuth->GetLastError();
|
|
|
|
|
if (last_error.isEmpty())
|
|
|
|
|
last_error = QTStr("YouTube.Actions.Error.YouTubeApi");
|
|
|
|
|
if (!ytAuth->GetTranslatedError(last_error))
|
|
|
|
|
last_error = QTStr("YouTube.Actions.Error.BroadcastTransitionFailed")
|
|
|
|
|
.arg(last_error, ytAuth->GetBroadcastId());
|
2022-01-27 02:37:32 +01:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
OBSMessageBox::warning(this, QTStr("Output.BroadcastStopFailed"), last_error, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-27 02:31:08 +02:00
|
|
|
#endif
|
2024-12-11 17:43:35 +01:00
|
|
|
broadcastActive = false;
|
|
|
|
|
broadcastReady = false;
|
2021-07-03 17:55:47 +12:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
autoStopBroadcast = true;
|
|
|
|
|
QMetaObject::invokeMethod(this, "StopStreaming");
|
|
|
|
|
emit BroadcastStreamReady(broadcastReady);
|
|
|
|
|
SetBroadcastFlowEnabled(true);
|
2021-07-03 17:55:47 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::SetBroadcastFlowEnabled(bool enabled)
|
2021-07-03 17:55:47 +12:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
emit BroadcastFlowEnabled(enabled);
|
2021-07-03 17:55:47 +12:00
|
|
|
}
|
|
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::SetupBroadcast()
|
2021-07-03 17:55:47 +12:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
#ifdef YOUTUBE_ENABLED
|
|
|
|
|
Auth *const auth = GetAuth();
|
|
|
|
|
if (IsYouTubeService(auth->service())) {
|
|
|
|
|
OBSYoutubeActions dialog(this, auth, broadcastReady);
|
|
|
|
|
connect(&dialog, &OBSYoutubeActions::ok, this, &OBSBasic::YouTubeActionDialogOk);
|
|
|
|
|
dialog.exec();
|
2021-07-03 17:55:47 +12:00
|
|
|
}
|
2024-12-11 17:43:35 +01:00
|
|
|
#endif
|
2021-07-03 17:55:47 +12:00
|
|
|
}
|
2021-11-01 02:16:56 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
#ifdef YOUTUBE_ENABLED
|
|
|
|
|
YouTubeAppDock *OBSBasic::GetYouTubeAppDock()
|
2021-11-01 02:16:56 -05:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
return youtubeAppDock;
|
2021-11-01 02:16:56 -05:00
|
|
|
}
|
2022-07-29 20:31:13 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
#ifndef SEC_TO_NSEC
|
|
|
|
|
#define SEC_TO_NSEC 1000000000
|
|
|
|
|
#endif
|
2024-06-18 14:18:22 -05:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::NewYouTubeAppDock()
|
2024-06-18 14:18:22 -05:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
if (!cef_js_avail)
|
|
|
|
|
return;
|
2024-07-31 10:53:59 -04:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
/* make sure that the youtube app dock can't be immediately recreated.
|
|
|
|
|
* dumb hack. blame chromium. or this particular dock. or both. if CEF
|
|
|
|
|
* creates/destroys/creates a widget too quickly it can lead to a
|
|
|
|
|
* crash. */
|
|
|
|
|
uint64_t ts = os_gettime_ns();
|
|
|
|
|
if ((ts - lastYouTubeAppDockCreationTime) < (5ULL * SEC_TO_NSEC))
|
|
|
|
|
return;
|
2024-07-31 10:53:59 -04:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
lastYouTubeAppDockCreationTime = ts;
|
2024-07-31 10:53:59 -04:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
if (youtubeAppDock)
|
|
|
|
|
RemoveDockWidget(youtubeAppDock->objectName());
|
2024-07-31 10:53:59 -04:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
youtubeAppDock = new YouTubeAppDock("YouTube Live Control Panel");
|
2024-07-31 10:53:59 -04:00
|
|
|
}
|
2024-09-03 16:29:30 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
void OBSBasic::DeleteYouTubeAppDock()
|
2024-09-03 16:29:30 +02:00
|
|
|
{
|
2024-12-11 17:43:35 +01:00
|
|
|
if (!cef_js_avail)
|
|
|
|
|
return;
|
2024-09-03 16:29:30 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
if (youtubeAppDock)
|
|
|
|
|
RemoveDockWidget(youtubeAppDock->objectName());
|
2024-09-03 16:29:30 +02:00
|
|
|
|
2024-12-11 17:43:35 +01:00
|
|
|
youtubeAppDock = nullptr;
|
2024-09-03 16:29:30 +02:00
|
|
|
}
|
2024-12-11 17:43:35 +01:00
|
|
|
#endif
|