goliveapi-network.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #include "goliveapi-network.hpp"
  2. #include "goliveapi-censoredjson.hpp"
  3. #include <obs.hpp>
  4. #include <obs-app.hpp>
  5. #include <remote-text.hpp>
  6. #include "multitrack-video-error.hpp"
  7. #include <qstring.h>
  8. #include <string>
  9. #include <QMessageBox>
  10. #include <QThreadPool>
  11. #include <nlohmann/json.hpp>
  12. using json = nlohmann::json;
  13. Qt::ConnectionType BlockingConnectionTypeFor(QObject *object);
  14. void HandleGoLiveApiErrors(QWidget *parent, const json &raw_json, const GoLiveApi::Config &config)
  15. {
  16. using GoLiveApi::StatusResult;
  17. if (!config.status)
  18. return;
  19. auto &status = *config.status;
  20. if (status.result == StatusResult::Success)
  21. return;
  22. auto warn_continue = [&](QString message) {
  23. bool ret = false;
  24. QMetaObject::invokeMethod(
  25. parent,
  26. [=] {
  27. QMessageBox mb(parent);
  28. mb.setIcon(QMessageBox::Warning);
  29. mb.setWindowTitle(QTStr("ConfigDownload.WarningMessageTitle"));
  30. mb.setTextFormat(Qt::RichText);
  31. mb.setText(message + QTStr("FailedToStartStream.WarningRetry"));
  32. mb.setStandardButtons(QMessageBox::StandardButton::Yes |
  33. QMessageBox::StandardButton::No);
  34. return mb.exec() == QMessageBox::StandardButton::No;
  35. },
  36. BlockingConnectionTypeFor(parent), &ret);
  37. if (ret)
  38. throw MultitrackVideoError::cancel();
  39. };
  40. auto missing_html = [] {
  41. return QTStr("FailedToStartStream.StatusMissingHTML").toStdString();
  42. };
  43. if (status.result == StatusResult::Unknown) {
  44. return warn_continue(QTStr("FailedToStartStream.WarningUnknownStatus")
  45. .arg(raw_json["status"]["result"].dump().c_str()));
  46. } else if (status.result == StatusResult::Warning) {
  47. if (config.encoder_configurations.empty()) {
  48. throw MultitrackVideoError::warning(status.html_en_us.value_or(missing_html()).c_str());
  49. }
  50. return warn_continue(status.html_en_us.value_or(missing_html()).c_str());
  51. } else if (status.result == StatusResult::Error) {
  52. throw MultitrackVideoError::critical(status.html_en_us.value_or(missing_html()).c_str());
  53. }
  54. }
  55. GoLiveApi::Config DownloadGoLiveConfig(QWidget *parent, QString url, const GoLiveApi::PostData &post_data,
  56. const QString &multitrack_video_name)
  57. {
  58. json post_data_json = post_data;
  59. blog(LOG_INFO, "Go live POST data: %s", censoredJson(post_data_json).toUtf8().constData());
  60. if (url.isEmpty())
  61. throw MultitrackVideoError::critical(QTStr("FailedToStartStream.MissingConfigURL"));
  62. std::string encodeConfigText;
  63. std::string libraryError;
  64. std::vector<std::string> headers;
  65. headers.push_back("Content-Type: application/json");
  66. bool encodeConfigDownloadedOk = GetRemoteFile(url.toLocal8Bit(), encodeConfigText,
  67. libraryError, // out params
  68. nullptr,
  69. nullptr, // out params (response code and content type)
  70. "POST", post_data_json.dump().c_str(), headers,
  71. nullptr, // signature
  72. 5); // timeout in seconds
  73. if (!encodeConfigDownloadedOk)
  74. throw MultitrackVideoError::warning(
  75. QTStr("FailedToStartStream.ConfigRequestFailed").arg(url, libraryError.c_str()));
  76. try {
  77. auto data = json::parse(encodeConfigText);
  78. blog(LOG_INFO, "Go live response data: %s", censoredJson(data, true).toUtf8().constData());
  79. GoLiveApi::Config config = data;
  80. HandleGoLiveApiErrors(parent, data, config);
  81. return config;
  82. } catch (const json::exception &e) {
  83. blog(LOG_INFO, "Failed to parse go live config: %s", e.what());
  84. throw MultitrackVideoError::warning(
  85. QTStr("FailedToStartStream.FallbackToDefault").arg(multitrack_video_name));
  86. }
  87. }
  88. QString MultitrackVideoAutoConfigURL(obs_service_t *service)
  89. {
  90. static const std::optional<QString> cli_url = []() -> std::optional<QString> {
  91. auto args = qApp->arguments();
  92. for (int i = 0; i < args.length() - 1; i++) {
  93. if (args[i] == "--config-url" && args.length() > (i + 1)) {
  94. return args[i + 1];
  95. }
  96. }
  97. return std::nullopt;
  98. }();
  99. QString url;
  100. if (cli_url.has_value()) {
  101. url = *cli_url;
  102. } else {
  103. OBSDataAutoRelease settings = obs_service_get_settings(service);
  104. url = obs_data_get_string(settings, "multitrack_video_configuration_url");
  105. }
  106. blog(LOG_INFO, "Go live URL: %s", url.toUtf8().constData());
  107. return url;
  108. }