soundcloud.js 7.9 KB

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