apis.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. import config from "config";
  2. import async from "async";
  3. import axios from "axios";
  4. import isLoginRequired from "../hooks/loginRequired";
  5. import { hasPermission, useHasPermission } from "../hooks/hasPermission";
  6. // eslint-disable-next-line
  7. import moduleManager from "../../index";
  8. const UtilsModule = moduleManager.modules.utils;
  9. const WSModule = moduleManager.modules.ws;
  10. const YouTubeModule = moduleManager.modules.youtube;
  11. const SpotifyModule = moduleManager.modules.spotify;
  12. export default {
  13. /**
  14. * Fetches a list of songs from Youtube's API
  15. *
  16. * @param {object} session - user session
  17. * @param {string} query - the query we'll pass to youtubes api
  18. * @param {Function} cb - callback
  19. * @returns {{status: string, data: object}} - returns an object
  20. */
  21. searchYoutube: isLoginRequired(function searchYoutube(session, query, cb) {
  22. return YouTubeModule.runJob("SEARCH", { query }, this)
  23. .then(data => {
  24. this.log("SUCCESS", "APIS_SEARCH_YOUTUBE", `Searching YouTube successful with query "${query}".`);
  25. return cb({ status: "success", data });
  26. })
  27. .catch(async err => {
  28. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  29. this.log("ERROR", "APIS_SEARCH_YOUTUBE", `Searching youtube failed with query "${query}". "${err}"`);
  30. return cb({ status: "error", message: err });
  31. });
  32. }),
  33. /**
  34. * Fetches a specific page of search results from Youtube's API
  35. *
  36. * @param {object} session - user session
  37. * @param {string} query - the query we'll pass to youtubes api
  38. * @param {string} pageToken - identifies a specific page in the result set that should be retrieved
  39. * @param {Function} cb - callback
  40. * @returns {{status: string, data: object}} - returns an object
  41. */
  42. searchYoutubeForPage: isLoginRequired(function searchYoutubeForPage(session, query, pageToken, cb) {
  43. return YouTubeModule.runJob("SEARCH", { query, pageToken }, this)
  44. .then(data => {
  45. this.log(
  46. "SUCCESS",
  47. "APIS_SEARCH_YOUTUBE_FOR_PAGE",
  48. `Searching YouTube successful with query "${query}".`
  49. );
  50. return cb({ status: "success", data });
  51. })
  52. .catch(async err => {
  53. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  54. this.log(
  55. "ERROR",
  56. "APIS_SEARCH_YOUTUBE_FOR_PAGE",
  57. `Searching youtube failed with query "${query}". "${err}"`
  58. );
  59. return cb({ status: "error", message: err });
  60. });
  61. }),
  62. /**
  63. * Gets Discogs data
  64. *
  65. * @param session
  66. * @param query - the query
  67. * @param {Function} cb
  68. */
  69. searchDiscogs: useHasPermission("apis.searchDiscogs", function searchDiscogs(session, query, page, cb) {
  70. async.waterfall(
  71. [
  72. next => {
  73. const options = {
  74. params: { q: query, per_page: 20, page },
  75. headers: {
  76. "User-Agent": "Request",
  77. Authorization: `Discogs key=${config.get("apis.discogs.client")}, secret=${config.get(
  78. "apis.discogs.secret"
  79. )}`
  80. }
  81. };
  82. axios
  83. .get("https://api.discogs.com/database/search", options)
  84. .then(res => next(null, res.data))
  85. .catch(err => next(err));
  86. }
  87. ],
  88. async (err, body) => {
  89. if (err) {
  90. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  91. this.log(
  92. "ERROR",
  93. "APIS_SEARCH_DISCOGS",
  94. `Searching discogs failed with query "${query}". "${err}"`
  95. );
  96. return cb({ status: "error", message: err });
  97. }
  98. this.log(
  99. "SUCCESS",
  100. "APIS_SEARCH_DISCOGS",
  101. `User "${session.userId}" searched Discogs succesfully for query "${query}".`
  102. );
  103. return cb({
  104. status: "success",
  105. data: {
  106. results: body.results,
  107. pages: body.pagination.pages
  108. }
  109. });
  110. }
  111. );
  112. }),
  113. /**
  114. *
  115. *
  116. * @param session
  117. * @param trackId - the trackId
  118. * @param {Function} cb
  119. */
  120. getAlternativeMediaSourcesForTracks: useHasPermission(
  121. "spotify.getAlternativeMediaSourcesForTracks",
  122. function getAlternativeMediaSourcesForTracks(session, mediaSources, collectAlternativeMediaSourcesOrigins, cb) {
  123. async.waterfall(
  124. [
  125. next => {
  126. if (!mediaSources) {
  127. next("Invalid mediaSources provided.");
  128. return;
  129. }
  130. next();
  131. },
  132. async () => {
  133. this.keepLongJob();
  134. this.publishProgress({
  135. status: "started",
  136. title: "Getting alternative media sources for Spotify tracks",
  137. message: "Starting up",
  138. id: this.toString()
  139. });
  140. console.log("KRIS@4", this.toString());
  141. // await CacheModule.runJob(
  142. // "RPUSH",
  143. // { key: `longJobs.${session.userId}`, value: this.toString() },
  144. // this
  145. // );
  146. SpotifyModule.runJob(
  147. "GET_ALTERNATIVE_MEDIA_SOURCES_FOR_TRACKS",
  148. { mediaSources, collectAlternativeMediaSourcesOrigins },
  149. this
  150. );
  151. }
  152. ],
  153. async err => {
  154. if (err) {
  155. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  156. this.log(
  157. "ERROR",
  158. "APIS_GET_ALTERNATIVE_SOURCES",
  159. `Getting alternative sources failed for "${mediaSources.join(", ")}". "${err}"`
  160. );
  161. return cb({ status: "error", message: err });
  162. }
  163. this.log(
  164. "SUCCESS",
  165. "APIS_GET_ALTERNATIVE_SOURCES",
  166. `User "${session.userId}" started getting alternatives for "${mediaSources.join(", ")}".`
  167. );
  168. return cb({
  169. status: "success"
  170. });
  171. }
  172. );
  173. }
  174. ),
  175. /**
  176. *
  177. *
  178. * @param session
  179. * @param trackId - the trackId
  180. * @param {Function} cb
  181. */
  182. getAlternativeAlbumSourcesForAlbums: useHasPermission(
  183. "spotify.getAlternativeAlbumSourcesForAlbums",
  184. function getAlternativeAlbumSourcesForAlbums(session, albumIds, collectAlternativeAlbumSourcesOrigins, cb) {
  185. async.waterfall(
  186. [
  187. next => {
  188. if (!albumIds) {
  189. next("Invalid albumIds provided.");
  190. return;
  191. }
  192. next();
  193. },
  194. async () => {
  195. this.keepLongJob();
  196. this.publishProgress({
  197. status: "started",
  198. title: "Getting alternative album sources for Spotify albums",
  199. message: "Starting up",
  200. id: this.toString()
  201. });
  202. console.log("KRIS@4", this.toString());
  203. // await CacheModule.runJob(
  204. // "RPUSH",
  205. // { key: `longJobs.${session.userId}`, value: this.toString() },
  206. // this
  207. // );
  208. SpotifyModule.runJob(
  209. "GET_ALTERNATIVE_ALBUM_SOURCES_FOR_ALBUMS",
  210. { albumIds, collectAlternativeAlbumSourcesOrigins },
  211. this
  212. );
  213. }
  214. ],
  215. async err => {
  216. if (err) {
  217. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  218. this.log(
  219. "ERROR",
  220. "APIS_GET_ALTERNATIVE_ALBUM_SOURCES",
  221. `Getting alternative album sources failed for "${albumIds.join(", ")}". "${err}"`
  222. );
  223. return cb({ status: "error", message: err });
  224. }
  225. this.log(
  226. "SUCCESS",
  227. "APIS_GET_ALTERNATIVE_ALBUM_SOURCES",
  228. `User "${session.userId}" started getting alternative album spirces for "${albumIds.join(
  229. ", "
  230. )}".`
  231. );
  232. return cb({
  233. status: "success"
  234. });
  235. }
  236. );
  237. }
  238. ),
  239. /**
  240. *
  241. *
  242. * @param session
  243. * @param trackId - the trackId
  244. * @param {Function} cb
  245. */
  246. getAlternativeArtistSourcesForArtists: useHasPermission(
  247. "spotify.getAlternativeArtistSourcesForArtists",
  248. function getAlternativeArtistSourcesForArtists(session, artistIds, collectAlternativeArtistSourcesOrigins, cb) {
  249. async.waterfall(
  250. [
  251. next => {
  252. if (!artistIds) {
  253. next("Invalid artistIds provided.");
  254. return;
  255. }
  256. next();
  257. },
  258. async () => {
  259. this.keepLongJob();
  260. this.publishProgress({
  261. status: "started",
  262. title: "Getting alternative artist sources for Spotify artists",
  263. message: "Starting up",
  264. id: this.toString()
  265. });
  266. console.log("KRIS@4", this.toString());
  267. // await CacheModule.runJob(
  268. // "RPUSH",
  269. // { key: `longJobs.${session.userId}`, value: this.toString() },
  270. // this
  271. // );
  272. SpotifyModule.runJob(
  273. "GET_ALTERNATIVE_ARTIST_SOURCES_FOR_ARTISTS",
  274. { artistIds, collectAlternativeArtistSourcesOrigins },
  275. this
  276. );
  277. }
  278. ],
  279. async err => {
  280. if (err) {
  281. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  282. this.log(
  283. "ERROR",
  284. "APIS_GET_ALTERNATIVE_ARTIST_SOURCES",
  285. `Getting alternative artist sources failed for "${artistIds.join(", ")}". "${err}"`
  286. );
  287. return cb({ status: "error", message: err });
  288. }
  289. this.log(
  290. "SUCCESS",
  291. "APIS_GET_ALTERNATIVE_ARTIST_SOURCES",
  292. `User "${session.userId}" started getting alternative artist spirces for "${artistIds.join(
  293. ", "
  294. )}".`
  295. );
  296. return cb({
  297. status: "success"
  298. });
  299. }
  300. );
  301. }
  302. ),
  303. /**
  304. * Joins a room
  305. *
  306. * @param {object} session - user session
  307. * @param {string} room - the room to join
  308. * @param {Function} cb - callback
  309. */
  310. joinRoom(session, room, cb) {
  311. const roomName = room.split(".")[0];
  312. // const roomId = room.split(".")[1];
  313. const rooms = {
  314. home: null,
  315. news: null,
  316. profile: null,
  317. "view-media": null,
  318. "manage-station": null,
  319. // "manage-station": "stations.view",
  320. "edit-song": "songs.update",
  321. "edit-songs": "songs.update",
  322. "import-album": "songs.update",
  323. // "edit-playlist": "playlists.update",
  324. "view-report": "reports.get",
  325. "edit-user": "users.update",
  326. "view-api-request": "youtube.getApiRequest",
  327. "view-punishment": "punishments.get"
  328. };
  329. const join = (status, error) => {
  330. if (status === "success")
  331. WSModule.runJob("SOCKET_JOIN_ROOM", {
  332. socketId: session.socketId,
  333. room
  334. })
  335. .then(() => cb({ status: "success", message: "Successfully joined room." }))
  336. .catch(err => join("error", err.message));
  337. else {
  338. this.log("ERROR", `Joining room failed: ${error}`);
  339. cb({ status: "error", message: error });
  340. }
  341. };
  342. if (rooms[roomName] === null) join("success");
  343. else if (rooms[roomName])
  344. hasPermission(rooms[roomName], session)
  345. .then(() => join("success"))
  346. .catch(err => join("error", err));
  347. else join("error", "Room not found");
  348. },
  349. /**
  350. * Leaves a room
  351. *
  352. * @param {object} session - user session
  353. * @param {string} room - the room to leave
  354. * @param {Function} cb - callback
  355. */
  356. leaveRoom(session, room, cb) {
  357. if (
  358. room === "home" ||
  359. room.startsWith("profile.") ||
  360. room.startsWith("manage-station.") ||
  361. room.startsWith("edit-song.") ||
  362. room.startsWith("view-report.") ||
  363. room === "import-album" ||
  364. room === "edit-songs"
  365. ) {
  366. WSModule.runJob("SOCKET_LEAVE_ROOM", {
  367. socketId: session.socketId,
  368. room
  369. })
  370. .then(() => {})
  371. .catch(err => {
  372. this.log("ERROR", `Leaving room failed: ${err.message}`);
  373. });
  374. }
  375. cb({ status: "success", message: "Successfully left room." });
  376. },
  377. /**
  378. * Joins an admin room
  379. *
  380. * @param {object} session - user session
  381. * @param {string} page - the admin room to join
  382. * @param {Function} cb - callback
  383. */
  384. joinAdminRoom(session, page, cb) {
  385. if (
  386. page === "songs" ||
  387. page === "stations" ||
  388. page === "reports" ||
  389. page === "news" ||
  390. page === "playlists" ||
  391. page === "users" ||
  392. page === "statistics" ||
  393. page === "punishments" ||
  394. page === "youtube" ||
  395. page === "youtubeVideos" ||
  396. page === "youtubeChannels" ||
  397. (config.get("experimental.soundcloud") && (page === "soundcloud" || page === "soundcloudTracks")) ||
  398. page === "import" ||
  399. page === "dataRequests"
  400. ) {
  401. hasPermission(`admin.view.${page}`, session.userId)
  402. .then(() =>
  403. WSModule.runJob("SOCKET_LEAVE_ROOMS", { socketId: session.socketId }).then(() => {
  404. WSModule.runJob(
  405. "SOCKET_JOIN_ROOM",
  406. {
  407. socketId: session.socketId,
  408. room: `admin.${page}`
  409. },
  410. this
  411. ).then(() => cb({ status: "success", message: "Successfully joined admin room." }));
  412. })
  413. )
  414. .catch(() => cb({ status: "error", message: "Failed to join admin room." }));
  415. }
  416. },
  417. /**
  418. * Leaves all rooms
  419. *
  420. * @param {object} session - user session
  421. * @param {Function} cb - callback
  422. */
  423. leaveRooms(session, cb) {
  424. WSModule.runJob("SOCKET_LEAVE_ROOMS", { socketId: session.socketId });
  425. cb({ status: "success", message: "Successfully left all rooms." });
  426. },
  427. /**
  428. * Returns current date
  429. *
  430. * @param {object} session - user session
  431. * @param {Function} cb - callback
  432. */
  433. ping(session, cb) {
  434. cb({ status: "success", message: "Successfully pinged.", data: { date: Date.now() } });
  435. }
  436. };