123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- /******************************************************************************
- Copyright (C) 2023 by Lain Bailey <[email protected]>
- Zachary Lund <[email protected]>
- Philippe Groarke <[email protected]>
- 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
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- 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/>.
- ******************************************************************************/
- #include "OBSBasic.hpp"
- #ifdef YOUTUBE_ENABLED
- #include <dialogs/OBSYoutubeActions.hpp>
- #include <docks/YouTubeAppDock.hpp>
- #include <utility/YoutubeApiWrappers.hpp>
- #endif
- #include <qt-wrappers.hpp>
- using namespace std;
- extern bool cef_js_avail;
- #ifdef YOUTUBE_ENABLED
- void OBSBasic::YouTubeActionDialogOk(const QString &broadcast_id, const QString &stream_id, const QString &key,
- bool autostart, bool autostop, bool start_now)
- {
- //blog(LOG_DEBUG, "Stream key: %s", QT_TO_UTF8(key));
- obs_service_t *service_obj = GetService();
- OBSDataAutoRelease settings = obs_service_get_settings(service_obj);
- const std::string a_key = QT_TO_UTF8(key);
- obs_data_set_string(settings, "key", a_key.c_str());
- const std::string b_id = QT_TO_UTF8(broadcast_id);
- obs_data_set_string(settings, "broadcast_id", b_id.c_str());
- const std::string s_id = QT_TO_UTF8(stream_id);
- obs_data_set_string(settings, "stream_id", s_id.c_str());
- obs_service_update(service_obj, settings);
- autoStartBroadcast = autostart;
- autoStopBroadcast = autostop;
- broadcastReady = true;
- emit BroadcastStreamReady(broadcastReady);
- if (start_now)
- QMetaObject::invokeMethod(this, "StartStreaming");
- }
- void OBSBasic::YoutubeStreamCheck(const std::string &key)
- {
- 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;
- }
- int timeout = 0;
- json11::Json json;
- QString id = key.c_str();
- while (StreamingActive()) {
- if (timeout == 14) {
- QMetaObject::invokeMethod(this, "ForceStopStreaming", Qt::QueuedConnection);
- break;
- }
- if (!apiYouTube->FindStream(id, json)) {
- QMetaObject::invokeMethod(this, "DisplayStreamStartError", Qt::QueuedConnection);
- QMetaObject::invokeMethod(this, "StopStreaming", Qt::QueuedConnection);
- break;
- }
- auto item = json["items"][0];
- auto status = item["status"]["streamStatus"].string_value();
- if (status == "active") {
- emit BroadcastStreamActive();
- break;
- } else {
- QThread::sleep(1);
- timeout++;
- }
- }
- youtubeStreamCheckThread->deleteLater();
- }
- void OBSBasic::ShowYouTubeAutoStartWarning()
- {
- 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);
- QCheckBox *cb = new QCheckBox(QTStr("DoNotShowAgain"));
- msgbox.setCheckBox(cb);
- msgbox.exec();
- if (cb->isChecked()) {
- config_set_bool(App()->GetUserConfig(), "General", "WarnedAboutYouTubeAutoStart", true);
- config_save_safe(App()->GetUserConfig(), "tmp", nullptr);
- }
- };
- bool warned = config_get_bool(App()->GetUserConfig(), "General", "WarnedAboutYouTubeAutoStart");
- if (!warned) {
- QMetaObject::invokeMethod(App(), "Exec", Qt::QueuedConnection, Q_ARG(VoidFunc, msgBox));
- }
- }
- #endif
- void OBSBasic::BroadcastButtonClicked()
- {
- if (!broadcastReady || (!broadcastActive && !outputHandler->StreamingActive())) {
- SetupBroadcast();
- return;
- }
- 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());
- OBSMessageBox::warning(this, QTStr("Output.BroadcastStartFailed"), last_error, true);
- return;
- }
- }
- #endif
- broadcastActive = true;
- autoStartBroadcast = true; // and clear the flag
- 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);
- if (button == QMessageBox::No)
- return;
- }
- 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());
- OBSMessageBox::warning(this, QTStr("Output.BroadcastStopFailed"), last_error, true);
- }
- }
- #endif
- broadcastActive = false;
- broadcastReady = false;
- autoStopBroadcast = true;
- QMetaObject::invokeMethod(this, "StopStreaming");
- emit BroadcastStreamReady(broadcastReady);
- SetBroadcastFlowEnabled(true);
- }
- }
- void OBSBasic::SetBroadcastFlowEnabled(bool enabled)
- {
- emit BroadcastFlowEnabled(enabled);
- }
- void OBSBasic::SetupBroadcast()
- {
- #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();
- }
- #endif
- }
- #ifdef YOUTUBE_ENABLED
- YouTubeAppDock *OBSBasic::GetYouTubeAppDock()
- {
- return youtubeAppDock;
- }
- #ifndef SEC_TO_NSEC
- #define SEC_TO_NSEC 1000000000
- #endif
- void OBSBasic::NewYouTubeAppDock()
- {
- if (!cef_js_avail)
- return;
- /* 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;
- lastYouTubeAppDockCreationTime = ts;
- if (youtubeAppDock)
- RemoveDockWidget(youtubeAppDock->objectName());
- youtubeAppDock = new YouTubeAppDock("YouTube Live Control Panel");
- }
- void OBSBasic::DeleteYouTubeAppDock()
- {
- if (!cef_js_avail)
- return;
- if (youtubeAppDock)
- RemoveDockWidget(youtubeAppDock->objectName());
- youtubeAppDock = nullptr;
- }
- #endif
|