twitch.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include <file-updater/file-updater.h>
  2. #include <util/threading.h>
  3. #include <util/platform.h>
  4. #include <obs-module.h>
  5. #include <util/dstr.h>
  6. #include <jansson.h>
  7. #include "twitch.h"
  8. static update_info_t *twitch_update_info = NULL;
  9. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  10. struct ingest {
  11. char *name;
  12. char *url;
  13. };
  14. static DARRAY(struct ingest) cur_ingests;
  15. static void free_ingests(void)
  16. {
  17. for (size_t i = 0; i < cur_ingests.num; i++) {
  18. struct ingest *ingest = cur_ingests.array + i;
  19. bfree(ingest->name);
  20. bfree(ingest->url);
  21. }
  22. da_free(cur_ingests);
  23. }
  24. static inline void init_defaults(void)
  25. {
  26. struct ingest ingest = {0};
  27. ingest.name = bstrdup("Default");
  28. ingest.url = bstrdup("rtmp://live.twitch.tv/app");
  29. da_push_back(cur_ingests, &ingest);
  30. }
  31. static void load_ingests(const char *json, bool write_file)
  32. {
  33. json_t *root;
  34. json_t *ingests;
  35. bool success = false;
  36. char *cache_old;
  37. char *cache_new;
  38. size_t count;
  39. root = json_loads(json, 0, NULL);
  40. if (!root)
  41. goto finish;
  42. ingests = json_object_get(root, "ingests");
  43. if (!ingests)
  44. goto finish;
  45. count = json_array_size(ingests);
  46. if (count <= 1 && cur_ingests.num)
  47. goto finish;
  48. free_ingests();
  49. for (size_t i = 0; i < count; i++) {
  50. json_t *item = json_array_get(ingests, i);
  51. json_t *item_name = json_object_get(item, "name");
  52. json_t *item_url = json_object_get(item, "url_template");
  53. struct ingest ingest = {0};
  54. struct dstr url = {0};
  55. if (!item_name || !item_url)
  56. continue;
  57. const char *url_str = json_string_value(item_url);
  58. const char *name_str = json_string_value(item_name);
  59. /* At the moment they currently mis-spell "deprecated",
  60. * but that may change in the future, so blacklist both */
  61. if (strstr(name_str, "deprecated") != NULL ||
  62. strstr(name_str, "depracated") != NULL)
  63. continue;
  64. dstr_copy(&url, url_str);
  65. dstr_replace(&url, "/{stream_key}", "");
  66. ingest.name = bstrdup(name_str);
  67. ingest.url = url.array;
  68. da_push_back(cur_ingests, &ingest);
  69. }
  70. if (!write_file || !cur_ingests.num)
  71. goto finish;
  72. cache_old = obs_module_config_path("twitch_ingests.json");
  73. cache_new = obs_module_config_path("twitch_ingests.new.json");
  74. os_quick_write_utf8_file(cache_new, json, strlen(json), false);
  75. os_safe_replace(cache_old, cache_new, NULL);
  76. bfree(cache_old);
  77. bfree(cache_new);
  78. finish:
  79. if (!cur_ingests.num)
  80. init_defaults();
  81. if (root)
  82. json_decref(root);
  83. }
  84. static bool twitch_ingest_update(void *param, struct file_download_data *data)
  85. {
  86. pthread_mutex_lock(&mutex);
  87. load_ingests(data->buffer.array, true);
  88. pthread_mutex_unlock(&mutex);
  89. UNUSED_PARAMETER(param);
  90. return true;
  91. }
  92. void twitch_ingests_lock(void)
  93. {
  94. pthread_mutex_lock(&mutex);
  95. }
  96. void twitch_ingests_unlock(void)
  97. {
  98. pthread_mutex_unlock(&mutex);
  99. }
  100. size_t twitch_ingest_count(void)
  101. {
  102. return cur_ingests.num;
  103. }
  104. struct twitch_ingest twitch_ingest(size_t idx)
  105. {
  106. struct twitch_ingest ingest;
  107. if (cur_ingests.num <= idx) {
  108. ingest.name = NULL;
  109. ingest.url = NULL;
  110. } else {
  111. ingest = *(struct twitch_ingest*)(cur_ingests.array + idx);
  112. }
  113. return ingest;
  114. }
  115. void load_twitch_data(const char *module_str)
  116. {
  117. char *twitch_cache = obs_module_config_path("twitch_ingests.json");
  118. if (os_file_exists(twitch_cache)) {
  119. char *data = os_quick_read_utf8_file(twitch_cache);
  120. pthread_mutex_lock(&mutex);
  121. load_ingests(data, false);
  122. pthread_mutex_unlock(&mutex);
  123. bfree(data);
  124. } else {
  125. init_defaults();
  126. }
  127. twitch_update_info = update_info_create_single(
  128. "[twitch ingest update] ",
  129. module_str,
  130. "https://ingest.twitch.tv/api/v2/ingests",
  131. twitch_ingest_update, NULL);
  132. bfree(twitch_cache);
  133. }
  134. void unload_twitch_data(void)
  135. {
  136. update_info_destroy(twitch_update_info);
  137. free_ingests();
  138. }