diff --git a/UI/auth-base.cpp b/UI/auth-base.cpp index 8ffc68c53..b1a4315fd 100644 --- a/UI/auth-base.cpp +++ b/UI/auth-base.cpp @@ -61,7 +61,11 @@ void Auth::Load() if (main->auth) { if (main->auth->LoadInternal()) { main->auth->LoadUI(); + main->SetBroadcastFlowEnabled( + main->auth->broadcastFlow()); } + } else { + main->SetBroadcastFlowEnabled(false); } } diff --git a/UI/auth-base.hpp b/UI/auth-base.hpp index e42d66863..a29d642c1 100644 --- a/UI/auth-base.hpp +++ b/UI/auth-base.hpp @@ -34,6 +34,7 @@ public: std::string service; Type type; bool externalOAuth; + bool usesBroadcastFlow; }; typedef std::function()> create_cb; @@ -44,6 +45,7 @@ public: inline Type type() const { return def.type; } inline const char *service() const { return def.service.c_str(); } inline bool external() const { return def.externalOAuth; } + inline bool broadcastFlow() const { return def.usesBroadcastFlow; } virtual void LoadUI() {} diff --git a/UI/auth-youtube.hpp b/UI/auth-youtube.hpp index 9b52a0ae7..31b2ca583 100644 --- a/UI/auth-youtube.hpp +++ b/UI/auth-youtube.hpp @@ -12,9 +12,9 @@ class BrowserDock; #endif inline const std::vector youtubeServices = { - {"YouTube - RTMP", Auth::Type::OAuth_LinkedAccount, true}, - {"YouTube - RTMPS", Auth::Type::OAuth_LinkedAccount, true}, - {"YouTube - HLS", Auth::Type::OAuth_LinkedAccount, true}}; + {"YouTube - RTMP", Auth::Type::OAuth_LinkedAccount, true, true}, + {"YouTube - RTMPS", Auth::Type::OAuth_LinkedAccount, true, true}, + {"YouTube - HLS", Auth::Type::OAuth_LinkedAccount, true, true}}; class YoutubeAuth : public OAuthStreamKey { Q_OBJECT diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 4db53ec32..de9065e07 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -391,6 +391,10 @@ Output.RecordError.EncodeErrorMsg="An encoder error occurred while recording." Output.BadPath.Title="Bad File Path" Output.BadPath.Text="The configured file output path is invalid. Please check your settings to confirm that a valid file path has been set." +# broadcast setup messages +Output.NoBroadcast.Title="No Broadcast Configured" +Output.NoBroadcast.Text="You need to set up a broadcast before you can start streaming." + # log upload dialog text and messages LogReturnDialog="Log Upload Successful" LogReturnDialog.Description="Your log file has been uploaded. You can now share the URL for debugging or support purposes." @@ -642,8 +646,10 @@ Basic.Main.UnpauseRecording="Unpause Recording" Basic.Main.StoppingRecording="Stopping Recording..." Basic.Main.StopReplayBuffer="Stop Replay Buffer" Basic.Main.StoppingReplayBuffer="Stopping Replay Buffer..." +Basic.Main.SetupBroadcast="Manage Broadcast" Basic.Main.StopStreaming="Stop Streaming" Basic.Main.StopBroadcast="End Broadcast" +Basic.Main.AutoStopEnabled="(Auto Stop)" Basic.Main.StoppingStreaming="Stopping Stream..." Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)" Basic.Main.ShowContextBar="Show Source Toolbar" @@ -1187,7 +1193,8 @@ YouTube.Auth.WaitingAuth.Title="YouTube User Authorization" YouTube.Auth.WaitingAuth.Text="Please complete the authorization in your external browser.
If the external browser does not open, follow this link and complete the authorization:
%1" YouTube.AuthError.Text="Failed to get channel information: %1." -YouTube.Actions.CreateNewEvent="Create New Event" +YouTube.Actions.CreateNewEvent="Create New Broadcast" +YouTube.Actions.ChooseEvent="Select Existing Broadcast" YouTube.Actions.Title="Title*" YouTube.Actions.MyBroadcast="My Broadcast" YouTube.Actions.Description="Description" @@ -1213,10 +1220,13 @@ YouTube.Actions.EnableDVR="Enable DVR" YouTube.Actions.360Video="360 video" YouTube.Actions.360Video.Help="(?)" YouTube.Actions.ScheduleForLater="Schedule for later" -YouTube.Actions.Create_GoLive="Create event and go live" -YouTube.Actions.Choose_GoLive="Go live with selected event" -YouTube.Actions.Create_Save="Schedule event with above settings" -YouTube.Actions.Dashboard="YouTube Studio..." +YouTube.Actions.Create_Ready="Create broadcast" +YouTube.Actions.Create_GoLive="Create broadcast and start streaming" +YouTube.Actions.Choose_Ready="Select broadcast" +YouTube.Actions.Choose_GoLive="Select broadcast and start streaming" +YouTube.Actions.Create_Schedule="Schedule broadcast" +YouTube.Actions.Create_Schedule_Ready="Schedule and select broadcast" +YouTube.Actions.Dashboard="Open YouTube Studio" YouTube.Actions.Error.Title="Live broadcast creation error" YouTube.Actions.Error.Text="YouTube access error '%1'.
A detailed error description can be found at https://developers.google.com/youtube/v3/live/docs/errors" @@ -1230,7 +1240,6 @@ YouTube.Actions.EventsLoading="Loading list of events..." YouTube.Actions.EventCreated.Title="Event Created" YouTube.Actions.EventCreated.Text="Event created successfully." -YouTube.Actions.ChooseEvent="Select Existing Event" YouTube.Actions.Stream="Stream" YouTube.Actions.Stream.ScheduledFor="Scheduled for %1" YouTube.Actions.Stream.Resume="Resume interrupted stream" diff --git a/UI/forms/OBSYoutubeActions.ui b/UI/forms/OBSYoutubeActions.ui index 0ca0c3244..29f8c1724 100644 --- a/UI/forms/OBSYoutubeActions.ui +++ b/UI/forms/OBSYoutubeActions.ui @@ -6,7 +6,7 @@ 0 0 - 583 + 584 510 @@ -480,7 +480,7 @@ 0 0 - 522 + 179 192 @@ -576,7 +576,7 @@ - + @@ -591,6 +591,13 @@ + + + + YouTube.Actions.Create_Ready + + + diff --git a/UI/window-basic-auto-config.cpp b/UI/window-basic-auto-config.cpp index d2b5fe57a..4a16012ab 100644 --- a/UI/window-basic-auto-config.cpp +++ b/UI/window-basic-auto-config.cpp @@ -1083,8 +1083,12 @@ void AutoConfig::SaveStreamSettings() main->SetService(newService); main->SaveService(); main->auth = streamPage->auth; - if (!!main->auth) + if (!!main->auth) { main->auth->LoadUI(); + main->SetBroadcastFlowEnabled(main->auth->broadcastFlow()); + } else { + main->SetBroadcastFlowEnabled(false); + } /* ---------------------------------- */ /* save stream settings */ diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 6bf3e9934..91d15960b 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -6155,7 +6155,8 @@ void OBSBasic::DisplayStreamStartError() #if YOUTUBE_ENABLED void OBSBasic::YouTubeActionDialogOk(const QString &id, const QString &key, - bool autostart, bool autostop) + bool autostart, bool autostop, + bool start_now) { //blog(LOG_DEBUG, "Stream key: %s", QT_TO_UTF8(key)); obs_service_t *service_obj = GetService(); @@ -6170,8 +6171,12 @@ void OBSBasic::YouTubeActionDialogOk(const QString &id, const QString &key, obs_service_update(service_obj, settings); autoStartBroadcast = autostart; autoStopBroadcast = autostop; + broadcastReady = true; obs_data_release(settings); + + if (start_now) + QMetaObject::invokeMethod(this, "StartStreaming"); } void OBSBasic::YoutubeStreamCheck(const std::string &key) @@ -6264,33 +6269,28 @@ void OBSBasic::StartStreaming() if (disableOutputsRef) return; - Auth *auth = GetAuth(); - if (auth) { - auth->OnStreamConfig(); -#if YOUTUBE_ENABLED - if (!broadcastActive && autoStartBroadcast && - IsYouTubeService(auth->service())) { - OBSYoutubeActions *dialog; - dialog = new OBSYoutubeActions(this, auth); - connect(dialog, &OBSYoutubeActions::ok, this, - &OBSBasic::YouTubeActionDialogOk); - int result = dialog->Valid() ? dialog->exec() - : QDialog::Rejected; - if (result != QDialog::Accepted) { - ui->streamButton->setText( - QTStr("Basic.Main.StartStreaming")); - ui->streamButton->setEnabled(true); - ui->streamButton->setChecked(false); + if (auth && auth->broadcastFlow()) { + if (!broadcastActive && !broadcastReady) { + ui->streamButton->setChecked(false); - if (sysTrayStream) { - sysTrayStream->setText( - ui->streamButton->text()); - sysTrayStream->setEnabled(true); - } - return; - } + QMessageBox no_broadcast(this); + no_broadcast.setText(QTStr("Output.NoBroadcast.Text")); + QPushButton *SetupBroadcast = no_broadcast.addButton( + QTStr("Basic.Main.SetupBroadcast"), + QMessageBox::YesRole); + no_broadcast.setDefaultButton(SetupBroadcast); + no_broadcast.addButton(QTStr("Close"), + QMessageBox::NoRole); + no_broadcast.setIcon(QMessageBox::Information); + no_broadcast.setWindowTitle( + QTStr("Output.NoBroadcast.Title")); + no_broadcast.exec(); + + if (no_broadcast.clickedButton() == SetupBroadcast) + QMetaObject::invokeMethod(this, + "SetupBroadcast"); + return; } -#endif } if (!outputHandler->SetupStreaming(service)) { @@ -6306,6 +6306,7 @@ void OBSBasic::StartStreaming() ui->streamButton->setEnabled(false); ui->streamButton->setChecked(false); ui->streamButton->setText(QTStr("Basic.Main.Connecting")); + ui->broadcastButton->setChecked(false); if (sysTrayStream) { sysTrayStream->setEnabled(false); @@ -6318,7 +6319,6 @@ void OBSBasic::StartStreaming() } if (!autoStartBroadcast) { - ui->broadcastButton->setVisible(true); ui->broadcastButton->setText( QTStr("Basic.Main.StartBroadcast")); ui->broadcastButton->setProperty("broadcastState", "ready"); @@ -6328,11 +6328,12 @@ void OBSBasic::StartStreaming() ui->broadcastButton->setEnabled(false); } else if (!autoStopBroadcast) { broadcastActive = true; - ui->broadcastButton->setVisible(true); ui->broadcastButton->setText(QTStr("Basic.Main.StopBroadcast")); ui->broadcastButton->setProperty("broadcastState", "active"); ui->broadcastButton->style()->unpolish(ui->broadcastButton); ui->broadcastButton->style()->polish(ui->broadcastButton); + } else { + ui->broadcastButton->setEnabled(false); } bool recordWhenStreaming = config_get_bool( @@ -6353,6 +6354,14 @@ void OBSBasic::StartStreaming() void OBSBasic::BroadcastButtonClicked() { + if (!broadcastReady || + !broadcastActive && !outputHandler->StreamingActive()) { + SetupBroadcast(); + if (broadcastReady) + ui->broadcastButton->setChecked(true); + return; + } + if (!autoStartBroadcast) { #if YOUTUBE_ENABLED std::shared_ptr ytAuth = @@ -6362,20 +6371,20 @@ void OBSBasic::BroadcastButtonClicked() } #endif broadcastActive = true; - autoStartBroadcast = true; // and clear the flag + if (!autoStopBroadcast) { ui->broadcastButton->setText( QTStr("Basic.Main.StopBroadcast")); - ui->broadcastButton->setProperty("broadcastState", - "active"); - ui->broadcastButton->style()->unpolish( - ui->broadcastButton); - ui->broadcastButton->style()->polish( - ui->broadcastButton); } else { - ui->broadcastButton->setVisible(false); + ui->broadcastButton->setText( + QTStr("Basic.Main.AutoStopEnabled")); + ui->broadcastButton->setEnabled(false); } + + ui->broadcastButton->setProperty("broadcastState", "active"); + ui->broadcastButton->style()->unpolish(ui->broadcastButton); + ui->broadcastButton->style()->polish(ui->broadcastButton); } else if (!autoStopBroadcast) { #if YOUTUBE_ENABLED bool confirm = config_get_bool(GetGlobalConfig(), "BasicWindow", @@ -6388,6 +6397,7 @@ void OBSBasic::BroadcastButtonClicked() QMessageBox::No); if (button == QMessageBox::No) { + ui->broadcastButton->setChecked(true); return; } } @@ -6399,14 +6409,44 @@ void OBSBasic::BroadcastButtonClicked() } #endif broadcastActive = false; + broadcastReady = false; autoStopBroadcast = true; - ui->broadcastButton->setVisible(false); - QMetaObject::invokeMethod(this, "StopStreaming"); + SetBroadcastFlowEnabled(true); } } +void OBSBasic::SetBroadcastFlowEnabled(bool enabled) +{ + ui->broadcastButton->setEnabled(enabled); + ui->broadcastButton->setVisible(enabled); + ui->broadcastButton->setChecked(broadcastReady); + ui->broadcastButton->setProperty("broadcastState", "idle"); + ui->broadcastButton->style()->unpolish(ui->broadcastButton); + ui->broadcastButton->style()->polish(ui->broadcastButton); + ui->broadcastButton->setText(QTStr("Basic.Main.SetupBroadcast")); +} + +void OBSBasic::SetupBroadcast() +{ + Auth *auth = GetAuth(); +#if YOUTUBE_ENABLED + if (IsYouTubeService(auth->service())) { + OBSYoutubeActions *dialog; + dialog = new OBSYoutubeActions(this, auth, broadcastReady); + connect(dialog, &OBSYoutubeActions::ok, this, + &OBSBasic::YouTubeActionDialogOk); + int result = dialog->Valid() ? dialog->exec() + : QDialog::Rejected; + if (result != QDialog::Accepted) { + if (!broadcastReady) + ui->broadcastButton->setChecked(false); + } + } +#endif +} + #ifdef _WIN32 static inline void UpdateProcessPriority() { @@ -6519,11 +6559,13 @@ void OBSBasic::StopStreaming() broadcastActive = false; autoStartBroadcast = true; autoStopBroadcast = true; - ui->broadcastButton->setVisible(false); + broadcastReady = false; } - if (autoStopBroadcast) + if (autoStopBroadcast) { broadcastActive = false; + broadcastReady = false; + } OnDeactivate(); @@ -6557,11 +6599,13 @@ void OBSBasic::ForceStopStreaming() broadcastActive = false; autoStartBroadcast = true; autoStopBroadcast = true; - ui->broadcastButton->setVisible(false); + broadcastReady = false; } - if (autoStopBroadcast) + if (autoStopBroadcast) { broadcastActive = false; + broadcastReady = false; + } OnDeactivate(); @@ -6766,6 +6810,10 @@ void OBSBasic::StreamingStop(int code, QString last_error) startStreamMenu->deleteLater(); startStreamMenu = nullptr; } + + // Reset broadcast button state/text + if (!broadcastActive) + SetBroadcastFlowEnabled(auth && auth->broadcastFlow()); } void OBSBasic::AutoRemux(QString input) @@ -7281,6 +7329,10 @@ void OBSBasic::on_streamButton_clicked() obs_service_get_settings(service); bwtest = obs_data_get_bool(settings, "bwtest"); obs_data_release(settings); + // Disable confirmation if this is going to open broadcast setup + if (auth && auth->broadcastFlow() && !broadcastReady && + !broadcastActive) + confirm = false; } if (bwtest && isVisible()) { diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 3114a515f..3f8530852 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -567,14 +567,17 @@ private: bool autoStartBroadcast = true; bool autoStopBroadcast = true; bool broadcastActive = false; + bool broadcastReady = false; QPointer youtubeStreamCheckThread; #if YOUTUBE_ENABLED void YoutubeStreamCheck(const std::string &key); void ShowYouTubeAutoStartWarning(); void YouTubeActionDialogOk(const QString &id, const QString &key, - bool autostart, bool autostop); + bool autostart, bool autostop, + bool start_now); #endif void BroadcastButtonClicked(); + void SetBroadcastFlowEnabled(bool enabled); void UpdatePreviewSafeAreas(); bool drawSafeAreas = false; @@ -585,6 +588,8 @@ public slots: void DisplayStreamStartError(); + void SetupBroadcast(); + void StartStreaming(); void StopStreaming(); void ForceStopStreaming(); diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp index 3ee091909..9c5224a7b 100644 --- a/UI/window-basic-settings-stream.cpp +++ b/UI/window-basic-settings-stream.cpp @@ -243,8 +243,12 @@ void OBSBasicSettings::SaveStream1Settings() main->SetService(newService); main->SaveService(); main->auth = auth; - if (!!main->auth) + if (!!main->auth) { main->auth->LoadUI(); + main->SetBroadcastFlowEnabled(main->auth->broadcastFlow()); + } else { + main->SetBroadcastFlowEnabled(false); + } SaveCheckBox(ui->ignoreRecommended, "Stream1", "IgnoreRecommended"); } @@ -667,6 +671,7 @@ void OBSBasicSettings::on_disconnectAccount_clicked() main->auth.reset(); auth.reset(); + main->SetBroadcastFlowEnabled(false); std::string service = QT_TO_UTF8(ui->service->currentText()); diff --git a/UI/window-youtube-actions.cpp b/UI/window-youtube-actions.cpp index e10ce2ecb..309ad80e7 100644 --- a/UI/window-youtube-actions.cpp +++ b/UI/window-youtube-actions.cpp @@ -13,11 +13,13 @@ const QString SchedulDateAndTimeFormat = "yyyy-MM-dd'T'hh:mm:ss'Z'"; const QString RepresentSchedulDateAndTimeFormat = "dddd, MMMM d, yyyy h:m"; const QString IndexOfGamingCategory = "20"; -OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth) +OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth, + bool broadcastReady) : QDialog(parent), ui(new Ui::OBSYoutubeActions), apiYouTube(dynamic_cast(auth)), - workerThread(new WorkerThread(apiYouTube)) + workerThread(new WorkerThread(apiYouTube)), + broadcastReady(broadcastReady) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); ui->setupUi(this); @@ -128,6 +130,8 @@ OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth) connect(ui->okButton, &QPushButton::clicked, this, &OBSYoutubeActions::InitBroadcast); + connect(ui->saveButton, &QPushButton::clicked, this, + &OBSYoutubeActions::ReadyBroadcast); connect(ui->cancelButton, &QPushButton::clicked, this, [&]() { blog(LOG_DEBUG, "YouTube live broadcast creation cancelled."); // Close the dialog. @@ -249,9 +253,9 @@ void WorkerThread::run() return; json11::Json broadcasts; - for (QString broacastStatus : {"active", "upcoming"}) { + for (QString broadcastStatus : {"active", "upcoming"}) { if (!apiYouTube->GetBroadcastsList(broadcasts, "", - broacastStatus)) { + broadcastStatus)) { emit failed(); return; } @@ -290,11 +294,9 @@ void WorkerThread::run() // Treat already started streams as autostart for UI purposes bool astart = - status == "live" - ? true - : item["contentDetails"] - ["enableAutoStart"] - .bool_value(); + status == "live" || + item["contentDetails"]["enableAutoStart"] + .bool_value(); bool astop = item["contentDetails"]["enableAutoStop"] .bool_value(); @@ -329,7 +331,7 @@ void WorkerThread::run() broadcasts, QString::fromStdString( nextPageToken), - broacastStatus)) { + broadcastStatus)) { emit failed(); return; } @@ -342,80 +344,64 @@ void WorkerThread::run() void OBSYoutubeActions::UpdateOkButtonStatus() { + bool enable = false; + if (ui->tabWidget->currentIndex() == 0) { - ui->okButton->setEnabled( - !ui->title->text().isEmpty() && - !ui->privacyBox->currentText().isEmpty() && - (ui->yesMakeForKids->isChecked() || - ui->notMakeForKids->isChecked())); + enable = !ui->title->text().isEmpty() && + !ui->privacyBox->currentText().isEmpty() && + (ui->yesMakeForKids->isChecked() || + ui->notMakeForKids->isChecked()); + ui->okButton->setEnabled(enable); + ui->saveButton->setEnabled(enable); + if (ui->checkScheduledLater->checkState() == Qt::Checked) { ui->okButton->setText( - QTStr("YouTube.Actions.Create_Save")); + QTStr("YouTube.Actions.Create_Schedule")); + ui->saveButton->setText( + QTStr("YouTube.Actions.Create_Schedule_Ready")); } else { ui->okButton->setText( QTStr("YouTube.Actions.Create_GoLive")); + ui->saveButton->setText( + QTStr("YouTube.Actions.Create_Ready")); } - ui->pushButton->setVisible(false); } else { - ui->okButton->setEnabled(!selectedBroadcast.isEmpty()); + enable = !selectedBroadcast.isEmpty(); + ui->okButton->setEnabled(enable); + ui->saveButton->setEnabled(enable); ui->okButton->setText(QTStr("YouTube.Actions.Choose_GoLive")); + ui->saveButton->setText(QTStr("YouTube.Actions.Choose_Ready")); ui->pushButton->setVisible(true); } } - -bool OBSYoutubeActions::StreamNowAction(YoutubeApiWrappers *api, - StreamDescription &stream) -{ - YoutubeApiWrappers *apiYouTube = api; - BroadcastDescription broadcast = {}; - UiToBroadcast(broadcast); - // stream now is always autostart/autostop - broadcast.auto_start = true; - broadcast.auto_stop = true; - - blog(LOG_DEBUG, "Scheduled date and time: %s", - broadcast.schedul_date_time.toStdString().c_str()); - if (!apiYouTube->InsertBroadcast(broadcast)) { - blog(LOG_DEBUG, "No broadcast created."); - return false; - } - stream = {"", "", "OBS Studio Video Stream"}; - if (!apiYouTube->InsertStream(stream)) { - blog(LOG_DEBUG, "No stream created."); - return false; - } - if (!apiYouTube->BindStream(broadcast.id, stream.id)) { - blog(LOG_DEBUG, "No stream binded."); - return false; - } - if (!apiYouTube->SetVideoCategory(broadcast.id, broadcast.title, - broadcast.description, - broadcast.category.id)) { - blog(LOG_DEBUG, "No category set."); - return false; - } - - if (broadcast.privacy != "private") - apiYouTube->SetChatId(broadcast.id); - else - apiYouTube->ResetChat(); - - return true; -} - -bool OBSYoutubeActions::StreamLaterAction(YoutubeApiWrappers *api) +bool OBSYoutubeActions::CreateEventAction(YoutubeApiWrappers *api, + StreamDescription &stream, + bool stream_later, + bool ready_broadcast) { YoutubeApiWrappers *apiYouTube = api; BroadcastDescription broadcast = {}; UiToBroadcast(broadcast); - // DateTime parser means that input datetime is a local, so we need to move it - auto dateTime = ui->scheduledTime->dateTime(); - auto utcDTime = dateTime.addSecs(-dateTime.offsetFromUtc()); - broadcast.schedul_date_time = - utcDTime.toString(SchedulDateAndTimeFormat); + if (stream_later) { + // DateTime parser means that input datetime is a local, so we need to move it + auto dateTime = ui->scheduledTime->dateTime(); + auto utcDTime = dateTime.addSecs(-dateTime.offsetFromUtc()); + broadcast.schedul_date_time = + utcDTime.toString(SchedulDateAndTimeFormat); + } else { + // stream now is always autostart/autostop + broadcast.auto_start = true; + broadcast.auto_stop = true; + broadcast.schedul_date_time = + QDateTime::currentDateTimeUtc().toString( + SchedulDateAndTimeFormat); + } + + autostart = broadcast.auto_start; + autostop = broadcast.auto_stop; blog(LOG_DEBUG, "Scheduled date and time: %s", broadcast.schedul_date_time.toStdString().c_str()); @@ -430,10 +416,22 @@ bool OBSYoutubeActions::StreamLaterAction(YoutubeApiWrappers *api) return false; } - if (broadcast.privacy != "private") - apiYouTube->SetChatId(broadcast.id); - else - apiYouTube->ResetChat(); + if (!stream_later || ready_broadcast) { + stream = {"", "", "OBS Studio Video Stream"}; + if (!apiYouTube->InsertStream(stream)) { + blog(LOG_DEBUG, "No stream created."); + return false; + } + if (!apiYouTube->BindStream(broadcast.id, stream.id)) { + blog(LOG_DEBUG, "No stream binded."); + return false; + } + + if (broadcast.privacy != "private") + apiYouTube->SetChatId(broadcast.id); + else + apiYouTube->ResetChat(); + } return true; } @@ -513,12 +511,9 @@ void OBSYoutubeActions::InitBroadcast() bool success = false; auto action = [&]() { if (ui->tabWidget->currentIndex() == 0) { - if (ui->checkScheduledLater->isChecked()) { - success = this->StreamLaterAction(apiYouTube); - } else { - success = this->StreamNowAction(apiYouTube, - stream); - } + success = this->CreateEventAction( + apiYouTube, stream, + ui->checkScheduledLater->isChecked()); } else { success = this->ChooseAnEventAction(apiYouTube, stream); }; @@ -548,13 +543,14 @@ void OBSYoutubeActions::InitBroadcast() blog(LOG_DEBUG, "New valid stream: %s", QT_TO_UTF8(stream.name)); emit ok(QT_TO_UTF8(stream.id), - QT_TO_UTF8(stream.name), true, true); + QT_TO_UTF8(stream.name), true, true, + true); Accept(); } } else { // Stream to precreated broadcast usecase. emit ok(QT_TO_UTF8(stream.id), QT_TO_UTF8(stream.name), - autostart, autostop); + autostart, autostop, true); Accept(); } } else { @@ -571,6 +567,51 @@ void OBSYoutubeActions::InitBroadcast() } } +void OBSYoutubeActions::ReadyBroadcast() +{ + StreamDescription stream; + QMessageBox msgBox(this); + msgBox.setWindowFlags(msgBox.windowFlags() & + ~Qt::WindowCloseButtonHint); + msgBox.setWindowTitle(QTStr("YouTube.Actions.Notify.Title")); + msgBox.setText(QTStr("YouTube.Actions.Notify.CreatingBroadcast")); + msgBox.setStandardButtons(QMessageBox::StandardButtons()); + + bool success = false; + auto action = [&]() { + if (ui->tabWidget->currentIndex() == 0) { + success = this->CreateEventAction( + apiYouTube, stream, + ui->checkScheduledLater->isChecked(), true); + } else { + success = this->ChooseAnEventAction(apiYouTube, stream); + }; + QMetaObject::invokeMethod(&msgBox, "accept", + Qt::QueuedConnection); + }; + QScopedPointer thread(CreateQThread(action)); + thread->start(); + msgBox.exec(); + thread->wait(); + + if (success) { + emit ok(QT_TO_UTF8(stream.id), QT_TO_UTF8(stream.name), + autostart, autostop, false); + Accept(); + } else { + // Fail. + auto last_error = apiYouTube->GetLastError(); + if (last_error.isEmpty()) + last_error = QTStr("YouTube.Actions.Error.YouTubeApi"); + if (!apiYouTube->GetTranslatedError(last_error)) + last_error = + QTStr("YouTube.Actions.Error.NoBroadcastCreated") + .arg(last_error); + + ShowErrorDialog(this, last_error); + } +} + void OBSYoutubeActions::UiToBroadcast(BroadcastDescription &broadcast) { broadcast.title = ui->title->text(); @@ -587,9 +628,6 @@ void OBSYoutubeActions::UiToBroadcast(BroadcastDescription &broadcast) broadcast.schedul_for_later = ui->checkScheduledLater->isChecked(); broadcast.projection = ui->check360Video->isChecked() ? "360" : "rectangular"; - // Current time by default. - broadcast.schedul_date_time = QDateTime::currentDateTimeUtc().toString( - SchedulDateAndTimeFormat); } void OBSYoutubeActions::OpenYouTubeDashboard() diff --git a/UI/window-youtube-actions.hpp b/UI/window-youtube-actions.hpp index 689854e93..c81b3496b 100644 --- a/UI/window-youtube-actions.hpp +++ b/UI/window-youtube-actions.hpp @@ -35,27 +35,29 @@ class OBSYoutubeActions : public QDialog { signals: void ok(const QString &id, const QString &key, bool autostart, - bool autostop); + bool autostop, bool start_now); protected: void UpdateOkButtonStatus(); - bool StreamNowAction(YoutubeApiWrappers *api, - StreamDescription &stream); - bool StreamLaterAction(YoutubeApiWrappers *api); + bool CreateEventAction(YoutubeApiWrappers *api, + StreamDescription &stream, bool stream_later, + bool ready_broadcast = false); bool ChooseAnEventAction(YoutubeApiWrappers *api, StreamDescription &stream); void ShowErrorDialog(QWidget *parent, QString text); public: - explicit OBSYoutubeActions(QWidget *parent, Auth *auth); + explicit OBSYoutubeActions(QWidget *parent, Auth *auth, + bool broadcastReady); virtual ~OBSYoutubeActions() override; bool Valid() { return valid; }; private: void InitBroadcast(); + void ReadyBroadcast(); void UiToBroadcast(BroadcastDescription &broadcast); void OpenYouTubeDashboard(); void Cancel(); @@ -64,6 +66,7 @@ private: QString selectedBroadcast; bool autostart, autostop; bool valid = false; + bool broadcastReady = false; YoutubeApiWrappers *apiYouTube; WorkerThread *workerThread; };