goliveapi-network.cpp 4.0 KB

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