soundcloud.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import async from "async";
  2. import isLoginRequired from "../hooks/loginRequired";
  3. import { useHasPermission } from "../hooks/hasPermission";
  4. // eslint-disable-next-line
  5. import moduleManager from "../../index";
  6. const DBModule = moduleManager.modules.db;
  7. const UtilsModule = moduleManager.modules.utils;
  8. const SoundcloudModule = moduleManager.modules.soundcloud;
  9. const CacheModule = moduleManager.modules.cache;
  10. export default {
  11. /**
  12. * Fetches new SoundCloud API key
  13. *
  14. * @returns {{status: string, data: object}}
  15. */
  16. fetchNewApiKey: useHasPermission("soundcloud.fetchNewApiKey", async function fetchNewApiKey(session, cb) {
  17. this.keepLongJob();
  18. this.publishProgress({
  19. status: "started",
  20. title: "Fetch new SoundCloud API key",
  21. message: "Fetching new SoundCloud API key.",
  22. id: this.toString()
  23. });
  24. await CacheModule.runJob("RPUSH", { key: `longJobs.${session.userId}`, value: this.toString() }, this);
  25. await CacheModule.runJob(
  26. "PUB",
  27. {
  28. channel: "longJob.added",
  29. value: { jobId: this.toString(), userId: session.userId }
  30. },
  31. this
  32. );
  33. SoundcloudModule.runJob("GENERATE_SOUNDCLOUD_API_KEY", {}, this)
  34. .then(response => {
  35. this.log("SUCCESS", "SOUNDCLOUD_FETCH_NEW_API_KEY", `Fetching new API key was successful.`);
  36. this.publishProgress({
  37. status: "success",
  38. message: "Successfully fetched new SoundCloud API key."
  39. });
  40. return cb({
  41. status: "success",
  42. data: { response }
  43. });
  44. })
  45. .catch(async err => {
  46. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  47. this.log("ERROR", "SOUNDCLOUD_FETCH_NEW_API_KEY", `Fetching new API key failed. "${err}"`);
  48. this.publishProgress({
  49. status: "error",
  50. message: err
  51. });
  52. return cb({ status: "error", message: err });
  53. });
  54. }),
  55. /**
  56. * Tests SoundCloud API key
  57. *
  58. * @returns {{status: string, data: object}}
  59. */
  60. testApiKey: useHasPermission("soundcloud.testApiKey", async function testApiKey(session, cb) {
  61. this.keepLongJob();
  62. this.publishProgress({
  63. status: "started",
  64. title: "Test SoundCloud API key",
  65. message: "Testing SoundCloud API key.",
  66. id: this.toString()
  67. });
  68. await CacheModule.runJob("RPUSH", { key: `longJobs.${session.userId}`, value: this.toString() }, this);
  69. await CacheModule.runJob(
  70. "PUB",
  71. {
  72. channel: "longJob.added",
  73. value: { jobId: this.toString(), userId: session.userId }
  74. },
  75. this
  76. );
  77. SoundcloudModule.runJob("TEST_SOUNDCLOUD_API_KEY", {}, this)
  78. .then(response => {
  79. this.log(
  80. "SUCCESS",
  81. "SOUNDCLOUD_TEST_API_KEY",
  82. `Testing API key was successful. Response: ${response}.`
  83. );
  84. this.publishProgress({
  85. status: "success",
  86. message: "Successfully tested SoundCloud API key."
  87. });
  88. return cb({
  89. status: "success",
  90. data: { status: response.status }
  91. });
  92. })
  93. .catch(async err => {
  94. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  95. this.log("ERROR", "SOUNDCLOUD_TEST_API_KEY", `Testing API key failed. "${err}"`);
  96. this.publishProgress({
  97. status: "error",
  98. message: err
  99. });
  100. return cb({ status: "error", message: err });
  101. });
  102. }),
  103. /**
  104. * Get a Soundcloud artist from ID
  105. *
  106. * @returns {{status: string, data: object}}
  107. */
  108. getArtist: useHasPermission("soundcloud.getArtist", function getArtist(session, userPermalink, cb) {
  109. return SoundcloudModule.runJob("GET_ARTISTS_FROM_PERMALINKS", { userPermalinks: [userPermalink] }, this)
  110. .then(res => {
  111. if (res.artists.length === 0) {
  112. this.log("ERROR", "SOUNDCLOUD_GET_ARTISTS_FROM_PERMALINKS", `Fetching artist failed.`);
  113. return cb({ status: "error", message: "Failed to get artist" });
  114. }
  115. this.log("SUCCESS", "SOUNDCLOUD_GET_ARTISTS_FROM_PERMALINKS", `Fetching artist was successful.`);
  116. return cb({
  117. status: "success",
  118. message: "Successfully fetched Soundcloud artist",
  119. data: res.artists[0]
  120. });
  121. })
  122. .catch(async err => {
  123. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  124. this.log("ERROR", "SOUNDCLOUD_GET_ARTISTS_FROM_PERMALINKS", `Fetching artist failed. "${err}"`);
  125. return cb({ status: "error", message: err });
  126. });
  127. }),
  128. /**
  129. * Gets videos, used in the admin youtube page by the AdvancedTable component
  130. *
  131. * @param {object} session - the session object automatically added by the websocket
  132. * @param page - the page
  133. * @param pageSize - the size per page
  134. * @param properties - the properties to return for each news item
  135. * @param sort - the sort object
  136. * @param queries - the queries array
  137. * @param operator - the operator for queries
  138. * @param cb
  139. */
  140. getTracks: useHasPermission(
  141. "admin.view.soundcloudTracks",
  142. async function getTracks(session, page, pageSize, properties, sort, queries, operator, cb) {
  143. async.waterfall(
  144. [
  145. next => {
  146. DBModule.runJob(
  147. "GET_DATA",
  148. {
  149. page,
  150. pageSize,
  151. properties,
  152. sort,
  153. queries,
  154. operator,
  155. modelName: "soundcloudTrack",
  156. blacklistedProperties: [],
  157. specialProperties: {
  158. songId: [
  159. // Fetch songs from songs collection with a matching mediaSource, which we first need to assemble
  160. {
  161. $lookup: {
  162. from: "songs",
  163. let: {
  164. mediaSource: { $concat: ["soundcloud:", { $toString: "$trackId" }] }
  165. },
  166. pipeline: [
  167. {
  168. $match: {
  169. $expr: { $eq: ["$mediaSource", "$$mediaSource"] }
  170. }
  171. }
  172. ],
  173. as: "song"
  174. }
  175. },
  176. // Turn the array of songs returned in the last step into one object, since only one song should have been returned maximum
  177. {
  178. $unwind: {
  179. path: "$song",
  180. preserveNullAndEmptyArrays: true
  181. }
  182. },
  183. // Add new field songId, which grabs the song object's _id and tries turning it into a string
  184. {
  185. $addFields: {
  186. songId: {
  187. $convert: {
  188. input: "$song._id",
  189. to: "string",
  190. onError: "",
  191. onNull: ""
  192. }
  193. }
  194. }
  195. },
  196. // Cleanup, don't return the song object for any further steps
  197. {
  198. $project: {
  199. song: 0
  200. }
  201. }
  202. ]
  203. },
  204. specialQueries: {},
  205. specialFilters: {
  206. // importJob: importJobId => [
  207. // {
  208. // $lookup: {
  209. // from: "importjobs",
  210. // let: { trackId: "$trackId" },
  211. // pipeline: [
  212. // {
  213. // $match: {
  214. // _id: mongoose.Types.ObjectId(importJobId)
  215. // }
  216. // },
  217. // {
  218. // $addFields: {
  219. // importJob: {
  220. // $in: ["$$trackId", "$response.successfulVideoIds"]
  221. // }
  222. // }
  223. // },
  224. // {
  225. // $project: {
  226. // importJob: 1,
  227. // _id: 0
  228. // }
  229. // }
  230. // ],
  231. // as: "importJob"
  232. // }
  233. // },
  234. // {
  235. // $unwind: "$importJob"
  236. // },
  237. // {
  238. // $set: {
  239. // importJob: "$importJob.importJob"
  240. // }
  241. // }
  242. // ]
  243. }
  244. },
  245. this
  246. )
  247. .then(response => {
  248. next(null, response);
  249. })
  250. .catch(err => {
  251. next(err);
  252. });
  253. }
  254. ],
  255. async (err, response) => {
  256. if (err && err !== true) {
  257. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  258. this.log("ERROR", "SOUNDCLOUD_GET_VIDEOS", `Failed to get SoundCloud tracks. "${err}"`);
  259. return cb({ status: "error", message: err });
  260. }
  261. this.log("SUCCESS", "SOUNDCLOUD_GET_VIDEOS", `Fetched SoundCloud tracks successfully.`);
  262. return cb({
  263. status: "success",
  264. message: "Successfully fetched SoundCloud tracks.",
  265. data: response
  266. });
  267. }
  268. );
  269. }
  270. ),
  271. /**
  272. * Get a SoundCloud track
  273. *
  274. * @returns {{status: string, data: object}}
  275. */
  276. getTrack: isLoginRequired(function getTrack(session, identifier, createMissing, cb) {
  277. return SoundcloudModule.runJob("GET_TRACK", { identifier, createMissing }, this)
  278. .then(res => {
  279. this.log("SUCCESS", "SOUNDCLOUD_GET_VIDEO", `Fetching track was successful.`);
  280. return cb({ status: "success", message: "Successfully fetched SoundCloud video", data: res.track });
  281. })
  282. .catch(async err => {
  283. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  284. this.log("ERROR", "SOUNDCLOUD_GET_VIDEO", `Fetching track failed. "${err}"`);
  285. return cb({ status: "error", message: err });
  286. });
  287. })
  288. };