Bläddra i källkod

UI: Just use json directly for service lookups

This commit accomplishes three different things:

- Makes it much less difficult to communicate service settings
  between the UI and the plugin.

- Refactors some code and makes it cleaner and easier to modify to our
  needs (although there is still a lot of work to do on that front
  because of heavy code duplication issues between auto-config and the
  stream settings pane).

- Significantly reatly reduces the number of times the json file has to
  be opened and parsed.

This also kind of denotes a bit of a failure on the plugin communication
aspect. The properties system is too limited and jank for a lot of
things we would like to do at times.
jp9000 3 år sedan
förälder
incheckning
2fa5ffe4df

+ 2 - 0
UI/CMakeLists.txt

@@ -140,6 +140,8 @@ target_sources(
           crash-report.cpp
           crash-report.hpp
           display-helpers.hpp
+          streaming-helpers.cpp
+          streaming-helpers.hpp
           platform.hpp
           qt-display.cpp
           qt-display.hpp

+ 67 - 0
UI/streaming-helpers.cpp

@@ -0,0 +1,67 @@
+#include "streaming-helpers.hpp"
+
+#include "../plugins/rtmp-services/rtmp-format-ver.h"
+
+#include <util/platform.h>
+#include <util/util.hpp>
+#include <obs.h>
+
+using namespace json11;
+
+static Json open_json_file(const char *path)
+{
+	BPtr<char> file_data = os_quick_read_utf8_file(path);
+	if (!file_data)
+		return Json();
+
+	std::string err;
+	Json json = Json::parse(file_data, err);
+	if (json["format_version"].int_value() != RTMP_SERVICES_FORMAT_VERSION)
+		return Json();
+	return json;
+}
+
+static inline bool name_matches(const Json &service, const char *name)
+{
+	if (service["name"].string_value() == name)
+		return true;
+
+	auto &alt_names = service["alt_names"].array_items();
+	for (const Json &alt_name : alt_names) {
+		if (alt_name.string_value() == name) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+Json get_services_json()
+{
+	obs_module_t *mod = obs_get_module("rtmp-services");
+	Json root;
+
+	BPtr<char> file = obs_module_get_config_path(mod, "services.json");
+	if (file)
+		root = open_json_file(file);
+
+	if (root.is_null()) {
+		file = obs_find_module_file(mod, "services.json");
+		if (file)
+			root = open_json_file(file);
+	}
+
+	return root;
+}
+
+Json get_service_from_json(Json &root, const char *name)
+{
+	auto &services = root["services"].array_items();
+	for (const Json &service : services) {
+		if (name_matches(service, name)) {
+			return service;
+		}
+	}
+
+	return Json();
+}

+ 6 - 0
UI/streaming-helpers.hpp

@@ -0,0 +1,6 @@
+#pragma once
+
+#include <json11.hpp>
+
+extern json11::Json get_services_json();
+extern json11::Json get_service_from_json(json11::Json &root, const char *name);

+ 10 - 17
UI/window-basic-auto-config-test.cpp

@@ -11,6 +11,7 @@
 
 #include "window-basic-auto-config.hpp"
 #include "window-basic-main.hpp"
+#include "streaming-helpers.hpp"
 #include "qt-wrappers.hpp"
 #include "obs-app.hpp"
 
@@ -19,6 +20,7 @@
 #define wiz reinterpret_cast<AutoConfig *>(wizard())
 
 using namespace std;
+using namespace json11;
 
 /* ------------------------------------------------------------------------- */
 
@@ -119,28 +121,19 @@ void AutoConfigTestPage::StartRecordingEncoderStage()
 
 void AutoConfigTestPage::GetServers(std::vector<ServerInfo> &servers)
 {
-	OBSDataAutoRelease settings = obs_data_create();
-	obs_data_set_string(settings, "service", wiz->serviceName.c_str());
+	Json root = get_services_json();
+	Json service = get_service_from_json(root, wiz->serviceName.c_str());
 
-	obs_properties_t *ppts = obs_get_service_properties("rtmp_common");
-	obs_property_t *p = obs_properties_get(ppts, "service");
-	obs_property_modified(p, settings);
+	auto &json_services = service["servers"].array_items();
+	for (const Json &server : json_services) {
+		const std::string &name = server["name"].string_value();
+		const std::string &url = server["url"].string_value();
 
-	p = obs_properties_get(ppts, "server");
-	size_t count = obs_property_list_item_count(p);
-	servers.reserve(count);
-
-	for (size_t i = 0; i < count; i++) {
-		const char *name = obs_property_list_item_name(p, i);
-		const char *server = obs_property_list_item_string(p, i);
-
-		if (wiz->CanTestServer(name)) {
-			ServerInfo info(name, server);
+		if (wiz->CanTestServer(name.c_str())) {
+			ServerInfo info(name, url);
 			servers.push_back(info);
 		}
 	}
-
-	obs_properties_destroy(ppts);
 }
 
 static inline void string_depad_key(string &key)

+ 41 - 68
UI/window-basic-auto-config.cpp

@@ -8,6 +8,7 @@
 #include "qt-wrappers.hpp"
 #include "obs-app.hpp"
 #include "url-push-button.hpp"
+#include "streaming-helpers.hpp"
 
 #include "ui_AutoConfigStartPage.h"
 #include "ui_AutoConfigVideoPage.h"
@@ -23,6 +24,8 @@
 #include "youtube-api-wrappers.hpp"
 #endif
 
+using namespace json11;
+
 struct QCef;
 struct QCefCookieManager;
 
@@ -672,6 +675,14 @@ void AutoConfigStreamPage::ServiceChanged()
 	UpdateCompleted();
 }
 
+inline void AutoConfigStreamPage::GetServicesJson()
+{
+	if (!servicesLoaded && servicesRoot.is_null()) {
+		servicesRoot = get_services_json();
+		servicesLoaded = true;
+	}
+}
+
 void AutoConfigStreamPage::UpdateMoreInfoLink()
 {
 	if (IsCustomService()) {
@@ -680,42 +691,32 @@ void AutoConfigStreamPage::UpdateMoreInfoLink()
 	}
 
 	QString serviceName = ui->service->currentText();
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_property_t *services = obs_properties_get(props, "service");
-
-	OBSDataAutoRelease settings = obs_data_create();
 
-	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
-	obs_property_modified(services, settings);
+	GetServicesJson();
+	Json service =
+		get_service_from_json(servicesRoot, QT_TO_UTF8(serviceName));
 
-	const char *more_info_link =
-		obs_data_get_string(settings, "more_info_link");
+	const std::string &more_info_link =
+		service["more_info_link"].string_value();
 
-	if (!more_info_link || (*more_info_link == '\0')) {
+	if (more_info_link.empty()) {
 		ui->moreInfoButton->hide();
 	} else {
-		ui->moreInfoButton->setTargetUrl(QUrl(more_info_link));
+		ui->moreInfoButton->setTargetUrl(QUrl(more_info_link.c_str()));
 		ui->moreInfoButton->show();
 	}
-	obs_properties_destroy(props);
 }
 
 void AutoConfigStreamPage::UpdateKeyLink()
 {
 	QString serviceName = ui->service->currentText();
 	QString customServer = ui->customServer->text().trimmed();
-	QString streamKeyLink;
 
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_property_t *services = obs_properties_get(props, "service");
-
-	OBSDataAutoRelease settings = obs_data_create();
-
-	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
-	obs_property_modified(services, settings);
-
-	streamKeyLink = obs_data_get_string(settings, "stream_key_link");
+	GetServicesJson();
+	Json service =
+		get_service_from_json(servicesRoot, QT_TO_UTF8(serviceName));
 
+	std::string streamKeyLink = service["stream_key_link"].string_value();
 	if (customServer.contains("fbcdn.net") && IsCustomService()) {
 		streamKeyLink =
 			"https://www.facebook.com/live/producer?ref=OBS";
@@ -729,37 +730,28 @@ void AutoConfigStreamPage::UpdateKeyLink()
 			QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
 	}
 
-	if (QString(streamKeyLink).isNull() ||
-	    QString(streamKeyLink).isEmpty()) {
+	if (streamKeyLink.empty()) {
 		ui->streamKeyButton->hide();
 	} else {
-		ui->streamKeyButton->setTargetUrl(QUrl(streamKeyLink));
+		ui->streamKeyButton->setTargetUrl(QUrl(streamKeyLink.c_str()));
 		ui->streamKeyButton->show();
 	}
-	obs_properties_destroy(props);
 }
 
 void AutoConfigStreamPage::LoadServices(bool showAll)
 {
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-
-	OBSDataAutoRelease settings = obs_data_create();
-
-	obs_data_set_bool(settings, "show_all", showAll);
-
-	obs_property_t *prop = obs_properties_get(props, "show_all");
-	obs_property_modified(prop, settings);
+	GetServicesJson();
+	auto &services = servicesRoot["services"].array_items();
 
 	ui->service->blockSignals(true);
 	ui->service->clear();
 
 	QStringList names;
 
-	obs_property_t *services = obs_properties_get(props, "service");
-	size_t services_count = obs_property_list_item_count(services);
-	for (size_t i = 0; i < services_count; i++) {
-		const char *name = obs_property_list_item_string(services, i);
-		names.push_back(name);
+	for (const Json &service : services) {
+		if (!showAll && !service["common"].bool_value())
+			continue;
+		names.push_back(service["name"].string_value().c_str());
 	}
 
 	if (showAll)
@@ -784,8 +776,6 @@ void AutoConfigStreamPage::LoadServices(bool showAll)
 			ui->service->setCurrentIndex(idx);
 	}
 
-	obs_properties_destroy(props);
-
 	ui->service->blockSignals(false);
 }
 
@@ -803,26 +793,17 @@ void AutoConfigStreamPage::UpdateServerList()
 		lastService = serviceName;
 	}
 
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_property_t *services = obs_properties_get(props, "service");
-
-	OBSDataAutoRelease settings = obs_data_create();
-
-	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
-	obs_property_modified(services, settings);
-
-	obs_property_t *servers = obs_properties_get(props, "server");
+	GetServicesJson();
+	Json service =
+		get_service_from_json(servicesRoot, QT_TO_UTF8(serviceName));
 
 	ui->server->clear();
 
-	size_t servers_count = obs_property_list_item_count(servers);
-	for (size_t i = 0; i < servers_count; i++) {
-		const char *name = obs_property_list_item_name(servers, i);
-		const char *server = obs_property_list_item_string(servers, i);
-		ui->server->addItem(name, server);
+	auto &servers = service["servers"].array_items();
+	for (const Json &server : servers) {
+		ui->server->addItem(server["name"].string_value().c_str(),
+				    server["url"].string_value().c_str());
 	}
-
-	obs_properties_destroy(props);
 }
 
 void AutoConfigStreamPage::UpdateCompleted()
@@ -886,18 +867,10 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
 	/* ----------------------------------------- */
 	/* check to see if Twitch's "auto" available */
 
-	OBSDataAutoRelease twitchSettings = obs_data_create();
-
-	obs_data_set_string(twitchSettings, "service", "Twitch");
-
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_properties_apply_settings(props, twitchSettings);
-
-	obs_property_t *p = obs_properties_get(props, "server");
-	const char *first = obs_property_list_item_string(p, 0);
-	twitchAuto = strcmp(first, "auto") == 0;
-
-	obs_properties_destroy(props);
+	Json servicesRoot = get_services_json();
+	Json serviceJson = get_service_from_json(servicesRoot, "Twitch");
+	Json servers = serviceJson["servers"];
+	twitchAuto = servers[0]["url"].string_value() == "auto";
 
 	/* ----------------------------------------- */
 	/* load service/servers                      */

+ 8 - 1
UI/window-basic-auto-config.hpp

@@ -13,6 +13,8 @@
 #include <string>
 #include <mutex>
 
+#include <json11.hpp>
+
 class Ui_AutoConfigStartPage;
 class Ui_AutoConfigVideoPage;
 class Ui_AutoConfigStreamPage;
@@ -174,6 +176,10 @@ class AutoConfigStreamPage : public QWizardPage {
 	QString lastService;
 	bool ready = false;
 
+	inline void GetServicesJson();
+	json11::Json servicesRoot;
+	bool servicesLoaded = false;
+
 	void LoadServices(bool showAll);
 	inline bool IsCustomService() const;
 
@@ -248,7 +254,8 @@ class AutoConfigTestPage : public QWizardPage {
 
 		inline ServerInfo() {}
 
-		inline ServerInfo(const char *name_, const char *address_)
+		inline ServerInfo(const std::string &name_,
+				  const std::string &address_)
 			: name(name_), address(address_)
 		{
 		}

+ 38 - 56
UI/window-basic-settings-stream.cpp

@@ -2,6 +2,7 @@
 #include <QUrl>
 
 #include "window-basic-settings.hpp"
+#include "streaming-helpers.hpp"
 #include "obs-frontend-api.h"
 #include "obs-app.hpp"
 #include "window-basic-main.hpp"
@@ -20,6 +21,8 @@
 #include "youtube-api-wrappers.hpp"
 #endif
 
+using namespace json11;
+
 struct QCef;
 struct QCefCookieManager;
 
@@ -246,6 +249,14 @@ void OBSBasicSettings::SaveStream1Settings()
 	SaveCheckBox(ui->ignoreRecommended, "Stream1", "IgnoreRecommended");
 }
 
+inline void OBSBasicSettings::GetServicesJson()
+{
+	if (!servicesLoaded && servicesRoot.is_null()) {
+		servicesRoot = get_services_json();
+		servicesLoaded = true;
+	}
+}
+
 void OBSBasicSettings::UpdateMoreInfoLink()
 {
 	if (IsCustomService()) {
@@ -254,42 +265,32 @@ void OBSBasicSettings::UpdateMoreInfoLink()
 	}
 
 	QString serviceName = ui->service->currentText();
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_property_t *services = obs_properties_get(props, "service");
 
-	OBSDataAutoRelease settings = obs_data_create();
+	GetServicesJson();
+	Json service =
+		get_service_from_json(servicesRoot, QT_TO_UTF8(serviceName));
 
-	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
-	obs_property_modified(services, settings);
+	const std::string &more_info_link =
+		service["more_info_link"].string_value();
 
-	const char *more_info_link =
-		obs_data_get_string(settings, "more_info_link");
-
-	if (!more_info_link || (*more_info_link == '\0')) {
+	if (more_info_link.empty()) {
 		ui->moreInfoButton->hide();
 	} else {
-		ui->moreInfoButton->setTargetUrl(QUrl(more_info_link));
+		ui->moreInfoButton->setTargetUrl(QUrl(more_info_link.c_str()));
 		ui->moreInfoButton->show();
 	}
-	obs_properties_destroy(props);
 }
 
 void OBSBasicSettings::UpdateKeyLink()
 {
 	QString serviceName = ui->service->currentText();
 	QString customServer = ui->customServer->text().trimmed();
-	QString streamKeyLink;
-
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_property_t *services = obs_properties_get(props, "service");
-
-	OBSDataAutoRelease settings = obs_data_create();
-
-	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
-	obs_property_modified(services, settings);
 
-	streamKeyLink = obs_data_get_string(settings, "stream_key_link");
+	GetServicesJson();
+	Json service =
+		get_service_from_json(servicesRoot, QT_TO_UTF8(serviceName));
 
+	std::string streamKeyLink = service["stream_key_link"].string_value();
 	if (customServer.contains("fbcdn.net") && IsCustomService()) {
 		streamKeyLink =
 			"https://www.facebook.com/live/producer?ref=OBS";
@@ -303,37 +304,29 @@ void OBSBasicSettings::UpdateKeyLink()
 			QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
 	}
 
-	if (QString(streamKeyLink).isNull() ||
-	    QString(streamKeyLink).isEmpty()) {
+	if (streamKeyLink.empty()) {
 		ui->getStreamKeyButton->hide();
 	} else {
-		ui->getStreamKeyButton->setTargetUrl(QUrl(streamKeyLink));
+		ui->getStreamKeyButton->setTargetUrl(
+			QUrl(streamKeyLink.c_str()));
 		ui->getStreamKeyButton->show();
 	}
-	obs_properties_destroy(props);
 }
 
 void OBSBasicSettings::LoadServices(bool showAll)
 {
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-
-	OBSDataAutoRelease settings = obs_data_create();
-
-	obs_data_set_bool(settings, "show_all", showAll);
-
-	obs_property_t *prop = obs_properties_get(props, "show_all");
-	obs_property_modified(prop, settings);
+	GetServicesJson();
+	auto &services = servicesRoot["services"].array_items();
 
 	ui->service->blockSignals(true);
 	ui->service->clear();
 
 	QStringList names;
 
-	obs_property_t *services = obs_properties_get(props, "service");
-	size_t services_count = obs_property_list_item_count(services);
-	for (size_t i = 0; i < services_count; i++) {
-		const char *name = obs_property_list_item_string(services, i);
-		names.push_back(name);
+	for (const Json &service : services) {
+		if (!showAll && !service["common"].bool_value())
+			continue;
+		names.push_back(service["name"].string_value().c_str());
 	}
 
 	if (showAll)
@@ -358,8 +351,6 @@ void OBSBasicSettings::LoadServices(bool showAll)
 			ui->service->setCurrentIndex(idx);
 	}
 
-	obs_properties_destroy(props);
-
 	ui->service->blockSignals(false);
 }
 
@@ -498,26 +489,17 @@ void OBSBasicSettings::UpdateServerList()
 		lastService = serviceName;
 	}
 
-	obs_properties_t *props = obs_get_service_properties("rtmp_common");
-	obs_property_t *services = obs_properties_get(props, "service");
-
-	OBSDataAutoRelease settings = obs_data_create();
-
-	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
-	obs_property_modified(services, settings);
-
-	obs_property_t *servers = obs_properties_get(props, "server");
+	GetServicesJson();
+	Json service =
+		get_service_from_json(servicesRoot, QT_TO_UTF8(serviceName));
 
 	ui->server->clear();
 
-	size_t servers_count = obs_property_list_item_count(servers);
-	for (size_t i = 0; i < servers_count; i++) {
-		const char *name = obs_property_list_item_name(servers, i);
-		const char *server = obs_property_list_item_string(servers, i);
-		ui->server->addItem(name, server);
+	auto &servers = service["servers"].array_items();
+	for (const Json &server : servers) {
+		ui->server->addItem(server["name"].string_value().c_str(),
+				    server["url"].string_value().c_str());
 	}
-
-	obs_properties_destroy(props);
 }
 
 void OBSBasicSettings::on_show_clicked()

+ 6 - 0
UI/window-basic-settings.hpp

@@ -41,6 +41,8 @@ class OBSHotkeyWidget;
 
 #include "ui_OBSBasicSettings.h"
 
+#include <json11.hpp>
+
 #define VOLUME_METER_DECAY_FAST 23.53
 #define VOLUME_METER_DECAY_MEDIUM 11.76
 #define VOLUME_METER_DECAY_SLOW 8.57
@@ -107,6 +109,10 @@ private:
 
 	std::shared_ptr<Auth> auth;
 
+	inline void GetServicesJson();
+	json11::Json servicesRoot;
+	bool servicesLoaded = false;
+
 	bool generalChanged = false;
 	bool stream1Changed = false;
 	bool outputsChanged = false;