Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,7 @@ YouTube.Actions.EnableAutoStart="Enable Auto-start"
YouTube.Actions.EnableAutoStop="Enable Auto-stop"
YouTube.Actions.AutoStartStop.TT="Indicates whether this scheduled broadcast should start automatically"
YouTube.Actions.EnableDVR="Enable DVR"
YouTube.Actions.SendLanguage="Set broadcast language from OBS language setting"
YouTube.Actions.360Video="360 video"
YouTube.Actions.360Video.Help="<a href='https://vr.youtube.com/create/360/'>(?)</a>"
YouTube.Actions.ScheduleForLater="Schedule for later"
Expand Down
1 change: 1 addition & 0 deletions frontend/data/locale/ko-KR.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,7 @@ YouTube.Actions.AutoStartStop.TT="예약된 방송이 자동으로 시작될지
YouTube.Actions.EnableDVR="DVR 사용"
YouTube.Actions.360Video="360° 동영상"
YouTube.Actions.ScheduleForLater="나중을 위해 예약하기"
YouTube.Actions.SendLanguage="OBS 언어 설정을 방송 언어로 자동 설정"
YouTube.Actions.RememberSettings="이 설정 기억하기"
YouTube.Actions.Create_Ready="방송 생성"
YouTube.Actions.Create_GoLive="방송 생성 후 생방송 시작하기"
Expand Down
44 changes: 42 additions & 2 deletions frontend/dialogs/OBSYoutubeActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <docks/YouTubeAppDock.hpp>
#include <widgets/OBSBasic.hpp>
#include <OBSApp.hpp>

#include <qt-wrappers.hpp>

Expand Down Expand Up @@ -146,6 +147,32 @@ OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth, bool broadcast
}
}

QVector<I18nLanguageDescription> language_list;
if (apiYouTube->GetI18nLanguagesList(language_list)) {
QString obs_language = QLocale::languageToCode(QLocale(App()->GetLocale()).language());
bool obs_language_found = false;

for (auto &language : language_list) {
ui->languageBox->addItem(language.name, language.id);
if (language.id == obs_language) {
obs_language_found = true;
}
}

if (obs_language_found) {
ui->languageBox->setCurrentIndex(ui->languageBox->findData(obs_language));
} else {
int en_index = ui->languageBox->findData("en");
if (en_index != -1) {
ui->languageBox->setCurrentIndex(en_index);
} else if (ui->languageBox->count() > 0) {
ui->languageBox->setCurrentIndex(0);
}
}
} else {
ui->languageBox->setEnabled(false);
}

connect(ui->okButton, &QPushButton::clicked, this, &OBSYoutubeActions::InitBroadcast);
connect(ui->saveButton, &QPushButton::clicked, this, &OBSYoutubeActions::ReadyBroadcast);
connect(ui->cancelButton, &QPushButton::clicked, this, [&]() {
Expand Down Expand Up @@ -388,8 +415,8 @@ bool OBSYoutubeActions::CreateEventAction(YoutubeApiWrappers *api, BroadcastDesc
blog(LOG_DEBUG, "No broadcast created.");
return false;
}
if (!apiYouTube->SetVideoCategory(broadcast.id, broadcast.title, broadcast.description,
broadcast.category.id)) {
if (!apiYouTube->SetVideoCategory(broadcast.id, broadcast.title, broadcast.description, broadcast.category.id,
broadcast.language)) {
blog(LOG_DEBUG, "No category set.");
return false;
}
Expand Down Expand Up @@ -608,6 +635,9 @@ void OBSYoutubeActions::UiToBroadcast(BroadcastDescription &broadcast)
broadcast.schedul_for_later = ui->checkScheduledLater->isChecked();
broadcast.projection = ui->check360Video->isChecked() ? "360" : "rectangular";

// Send selected language to YouTube API
broadcast.language = ui->languageBox->currentData().toString();

if (ui->checkRememberSettings->isChecked())
SaveSettings(broadcast);
}
Expand All @@ -628,6 +658,7 @@ void OBSYoutubeActions::SaveSettings(BroadcastDescription &broadcast)
config_set_bool(main->activeConfiguration, "YouTube", "ScheduleForLater", broadcast.schedul_for_later);
config_set_string(main->activeConfiguration, "YouTube", "Projection", QT_TO_UTF8(broadcast.projection));
config_set_string(main->activeConfiguration, "YouTube", "ThumbnailFile", QT_TO_UTF8(thumbnailFile));
config_set_string(main->activeConfiguration, "YouTube", "Language", QT_TO_UTF8(broadcast.language));
config_set_bool(main->activeConfiguration, "YouTube", "RememberSettings", true);
}

Expand Down Expand Up @@ -679,6 +710,15 @@ void OBSYoutubeActions::LoadSettings()
ui->check360Video->setChecked(false);
}

// Load language setting
const char *langStr = config_get_string(main->activeConfiguration, "YouTube", "Language");
if (langStr && *langStr) {
int langIndex = ui->languageBox->findData(QT_UTF8(langStr));
if (langIndex != -1) {
ui->languageBox->setCurrentIndex(langIndex);
}
}

const char *thumbFile = config_get_string(main->activeConfiguration, "YouTube", "ThumbnailFile");
if (thumbFile && *thumbFile) {
QFileInfo tFile(thumbFile);
Expand Down
50 changes: 35 additions & 15 deletions frontend/forms/OBSYoutubeActions.ui
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,33 @@
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_language">
<property name="text">
<string>Basic.Settings.General.Language</string>
</property>
<property name="buddy">
<cstring>languageBox</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="languageBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>YouTube.Actions.MadeForKids</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="notMakeForKids">
Expand All @@ -210,21 +230,21 @@
</item>
</layout>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="QRadioButton" name="yesMakeForKids">
<property name="text">
<string>YouTube.Actions.MadeForKids.Yes</string>
</property>
</widget>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>YouTube.Actions.Thumbnail</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="9" column="1">
<widget class="ClickableLabel" name="thumbnailPreview">
<property name="enabled">
<bool>true</bool>
Expand Down Expand Up @@ -258,7 +278,7 @@
</property>
</widget>
</item>
<item row="9" column="1">
<item row="10" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_13">
<property name="rightMargin">
<number>0</number>
Expand All @@ -282,7 +302,7 @@
</item>
</layout>
</item>
<item row="26" column="1">
<item row="27" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
Expand All @@ -295,7 +315,7 @@
</property>
</spacer>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_7">
<property name="font">
<font>
Expand All @@ -307,7 +327,7 @@
</property>
</widget>
</item>
<item row="14" column="1">
<item row="15" column="1">
<widget class="QCheckBox" name="checkScheduledLater">
<property name="enabled">
<bool>true</bool>
Expand All @@ -317,7 +337,7 @@
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QCheckBox" name="check360Video">
Expand Down Expand Up @@ -357,7 +377,7 @@
</item>
</layout>
</item>
<item row="15" column="1">
<item row="16" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QCheckBox" name="checkAutoStart">
Expand Down Expand Up @@ -406,7 +426,7 @@
</item>
</layout>
</item>
<item row="16" column="1">
<item row="17" column="1">
<widget class="QCheckBox" name="checkAutoStop">
<property name="enabled">
<bool>true</bool>
Expand All @@ -419,7 +439,7 @@
</property>
</widget>
</item>
<item row="17" column="1">
<item row="18" column="1">
<widget class="QDateTimeEdit" name="scheduledTime">
<property name="enabled">
<bool>true</bool>
Expand Down Expand Up @@ -448,7 +468,7 @@
</property>
</spacer>
</item>
<item row="12" column="1">
<item row="13" column="1">
<widget class="QCheckBox" name="checkDVR">
<property name="text">
<string>YouTube.Actions.EnableDVR</string>
Expand All @@ -458,7 +478,7 @@
</property>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>YouTube.Actions.Latency</string>
Expand All @@ -468,7 +488,7 @@
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QComboBox" name="latencyBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
Expand Down
48 changes: 41 additions & 7 deletions frontend/utility/YoutubeApiWrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ constexpr auto youtubeLiveBroadcastBindUrl = "https://www.googleapis.com/youtube

constexpr auto youtubeLiveChannelUrl = "https://www.googleapis.com/youtube/v3/channels"sv;
constexpr auto youtubeLiveTokenUrl = "https://oauth2.googleapis.com/token"sv;
constexpr auto youtubeLiveI18nLanguagesUrl = "https://www.googleapis.com/youtube/v3/i18nLanguages"sv;
constexpr auto youtubeLiveVideoCategoriesUrl = "https://www.googleapis.com/youtube/v3/videoCategories"sv;
constexpr auto youtubeLiveVideosUrl = "https://www.googleapis.com/youtube/v3/videos"sv;
constexpr auto youtubeLiveThumbnailUrl = "https://www.googleapis.com/upload/youtube/v3/thumbnails/set"sv;
Expand Down Expand Up @@ -275,6 +276,31 @@ bool YoutubeApiWrappers::GetBroadcastsList(Json &json_out, const QString &page,
return InsertCommand(url.c_str(), "application/json", "", nullptr, json_out);
}

bool YoutubeApiWrappers::GetI18nLanguagesList(QVector<I18nLanguageDescription> &language_list_out)
{
lastErrorMessage.clear();
lastErrorReason.clear();
const QString url_template = QString(youtubeLiveI18nLanguagesUrl.data()) + "?part=snippet&hl=%1";

QString url = url_template.arg(QLocale().name());

Json json_out;
if (!InsertCommand(QT_TO_UTF8(url), "application/json", "", nullptr, json_out)) {
if (lastErrorReason != "unsupportedLanguageCode" && lastErrorReason != "invalidLanguage")
return false;
// Try again with en_US if YouTube error indicates an unsupported locale
url = url_template.arg("en_US");
if (!InsertCommand(QT_TO_UTF8(url), "application/json", "", nullptr, json_out))
return false;
}
language_list_out = {};
for (auto &j : json_out["items"].array_items()) {
language_list_out.push_back(
{j["id"].string_value().c_str(), j["snippet"]["name"].string_value().c_str()});
}
return language_list_out.isEmpty() ? false : true;
}

bool YoutubeApiWrappers::GetVideoCategoriesList(QVector<CategoryDescription> &category_list_out)
{
lastErrorMessage.clear();
Expand Down Expand Up @@ -315,19 +341,27 @@ bool YoutubeApiWrappers::GetVideoCategoriesList(QVector<CategoryDescription> &ca
}

bool YoutubeApiWrappers::SetVideoCategory(const QString &video_id, const QString &video_title,
const QString &video_description, const QString &categorie_id)
const QString &video_description, const QString &categorie_id,
const QString &language)
{
lastErrorMessage.clear();
lastErrorReason.clear();
const std::string url = std::string(youtubeLiveVideosUrl) + "?part=snippet";

Json::object snippet = {
{"title", QT_TO_UTF8(video_title)},
{"description", QT_TO_UTF8(video_description)},
{"categoryId", QT_TO_UTF8(categorie_id)},
};

if (!language.isEmpty()) {
snippet["defaultLanguage"] = QT_TO_UTF8(language);
snippet["defaultAudioLanguage"] = QT_TO_UTF8(language);
}

const Json data = Json::object{
{"id", QT_TO_UTF8(video_id)},
{"snippet",
Json::object{
{"title", QT_TO_UTF8(video_title)},
{"description", QT_TO_UTF8(video_description)},
{"categoryId", QT_TO_UTF8(categorie_id)},
}},
{"snippet", snippet},
};
Json json_out;
return InsertCommand(url.c_str(), "application/json", "PUT", data.dump().c_str(), json_out);
Expand Down
9 changes: 8 additions & 1 deletion frontend/utility/YoutubeApiWrappers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ struct CategoryDescription {
QString title;
};

struct I18nLanguageDescription {
QString id;
QString name;
};

struct BroadcastDescription {
QString id;
QString title;
Expand All @@ -36,6 +41,7 @@ struct BroadcastDescription {
bool schedul_for_later;
QString schedul_date_time;
QString projection;
QString language;
};

bool IsYouTubeService(const std::string &service);
Expand All @@ -59,8 +65,9 @@ class YoutubeApiWrappers : public YoutubeAuth {
bool BindStream(const QString broadcast_id, const QString stream_id);
bool GetBroadcastsList(json11::Json &json_out, const QString &page, const QString &status);
bool GetVideoCategoriesList(QVector<CategoryDescription> &category_list_out);
bool GetI18nLanguagesList(QVector<I18nLanguageDescription> &language_list_out);
bool SetVideoCategory(const QString &video_id, const QString &video_title, const QString &video_description,
const QString &categorie_id);
const QString &categorie_id, const QString &language = "");
bool SetVideoThumbnail(const QString &video_id, const QString &thumbnail_file);
bool StartBroadcast(const QString &broadcast_id);
bool StopBroadcast(const QString &broadcast_id);
Expand Down