soundcloud.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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
  160. {
  161. $lookup: {
  162. from: "songs", // TODO fix this to support mediasource, so start with youtube:, so add a new pipeline steps
  163. localField: "trackId",
  164. foreignField: "trackId",
  165. as: "song"
  166. }
  167. },
  168. // Turn the array of songs returned in the last step into one object, since only one song should have been returned maximum
  169. {
  170. $unwind: {
  171. path: "$song",
  172. preserveNullAndEmptyArrays: true
  173. }
  174. },
  175. // Add new field songId, which grabs the song object's _id and tries turning it into a string
  176. {
  177. $addFields: {
  178. songId: {
  179. $convert: {
  180. input: "$song._id",
  181. to: "string",
  182. onError: "",
  183. onNull: ""
  184. }
  185. }
  186. }
  187. },
  188. // Cleanup, don't return the song object for any further steps
  189. {
  190. $project: {
  191. song: 0
  192. }
  193. }
  194. ]
  195. },
  196. specialQueries: {},
  197. specialFilters: {
  198. // importJob: importJobId => [
  199. // {
  200. // $lookup: {
  201. // from: "importjobs",
  202. // let: { trackId: "$trackId" },
  203. // pipeline: [
  204. // {
  205. // $match: {
  206. // _id: mongoose.Types.ObjectId(importJobId)
  207. // }
  208. // },
  209. // {
  210. // $addFields: {
  211. // importJob: {
  212. // $in: ["$$trackId", "$response.successfulVideoIds"]
  213. // }
  214. // }
  215. // },
  216. // {
  217. // $project: {
  218. // importJob: 1,
  219. // _id: 0
  220. // }
  221. // }
  222. // ],
  223. // as: "importJob"
  224. // }
  225. // },
  226. // {
  227. // $unwind: "$importJob"
  228. // },
  229. // {
  230. // $set: {
  231. // importJob: "$importJob.importJob"
  232. // }
  233. // }
  234. // ]
  235. }
  236. },
  237. this
  238. )
  239. .then(response => {
  240. next(null, response);
  241. })
  242. .catch(err => {
  243. next(err);
  244. });
  245. }
  246. ],
  247. async (err, response) => {
  248. if (err && err !== true) {
  249. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  250. this.log("ERROR", "SOUNDCLOUD_GET_VIDEOS", `Failed to get SoundCloud tracks. "${err}"`);
  251. return cb({ status: "error", message: err });
  252. }
  253. this.log("SUCCESS", "SOUNDCLOUD_GET_VIDEOS", `Fetched SoundCloud tracks successfully.`);
  254. return cb({
  255. status: "success",
  256. message: "Successfully fetched SoundCloud tracks.",
  257. data: response
  258. });
  259. }
  260. );
  261. }
  262. ),
  263. /**
  264. * Get a SoundCloud track
  265. *
  266. * @returns {{status: string, data: object}}
  267. */
  268. getTrack: isLoginRequired(function getTrack(session, identifier, createMissing, cb) {
  269. return SoundcloudModule.runJob("GET_TRACK", { identifier, createMissing }, this)
  270. .then(res => {
  271. this.log("SUCCESS", "SOUNDCLOUD_GET_VIDEO", `Fetching track was successful.`);
  272. return cb({ status: "success", message: "Successfully fetched SoundCloud video", data: res.track });
  273. })
  274. .catch(async err => {
  275. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  276. this.log("ERROR", "SOUNDCLOUD_GET_VIDEO", `Fetching track failed. "${err}"`);
  277. return cb({ status: "error", message: err });
  278. });
  279. })
  280. };