apis.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  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 ISRC - the ISRC
  118. // * @param {Function} cb
  119. // */
  120. // searchMusicBrainzISRC: useHasPermission("admin.view.spotify", function searchMusicBrainzISRC(session, ISRC, cb) {
  121. // async.waterfall(
  122. // [
  123. // next => {
  124. // if (!ISRC) {
  125. // next("Invalid ISRC provided.");
  126. // return;
  127. // }
  128. // CacheModule.runJob("HGET", { table: "musicbrainz-isrc-2", key: ISRC })
  129. // .then(response => {
  130. // if (response) next(null, response);
  131. // else next(null, null);
  132. // })
  133. // .catch(err => {
  134. // next(err);
  135. // });
  136. // },
  137. // (body, next) => {
  138. // if (body) {
  139. // next(null, body);
  140. // return;
  141. // }
  142. // const options = {
  143. // params: { fmt: "json", inc: "url-rels+work-rels" },
  144. // headers: {
  145. // "User-Agent": "Musare/3.9.0-fork ( https://git.kvos.dev/kris/MusareFork )" // TODO set this in accordance to https://musicbrainz.org/doc/MusicBrainz_API/Rate_Limiting
  146. // }
  147. // };
  148. // console.log("KRIS101", options, `https://musicbrainz.org/ws/2/isrc/${ISRC}`);
  149. // axios
  150. // .get(`https://musicbrainz.org/ws/2/isrc/${ISRC}`, options)
  151. // .then(res => next(null, res.data))
  152. // .catch(err => next(err));
  153. // },
  154. // (body, next) => {
  155. // console.log("KRIS222", body);
  156. // CacheModule.runJob("HSET", { table: "musicbrainz-isrc-2", key: ISRC, value: body })
  157. // .then(() => {})
  158. // .catch(() => {});
  159. // next(null, body);
  160. // },
  161. // (body, next) => {
  162. // const response = {};
  163. // const recordingUrls = Array.from(
  164. // new Set(
  165. // body.recordings
  166. // .map(recording =>
  167. // recording.relations
  168. // .filter(
  169. // relation =>
  170. // relation["target-type"] === "url" &&
  171. // relation.url &&
  172. // // relation["type-id"] === "7e41ef12-a124-4324-afdb-fdbae687a89c" &&
  173. // (relation.url.resource.indexOf("youtu.be") !== -1 ||
  174. // relation.url.resource.indexOf("youtube.com") !== -1 ||
  175. // relation.url.resource.indexOf("soundcloud.com") !== -1)
  176. // )
  177. // .map(relation => relation.url.resource)
  178. // )
  179. // .flat()
  180. // )
  181. // );
  182. // const workIds = Array.from(
  183. // new Set(
  184. // body.recordings
  185. // .map(recording =>
  186. // recording.relations
  187. // .filter(relation => relation["target-type"] === "work" && relation.work)
  188. // .map(relation => relation.work.id)
  189. // )
  190. // .flat()
  191. // )
  192. // );
  193. // response.recordingUrls = recordingUrls;
  194. // response.workIds = workIds;
  195. // response.raw = body;
  196. // next(null, response);
  197. // }
  198. // ],
  199. // async (err, response) => {
  200. // if (err && err !== true) {
  201. // err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  202. // this.log(
  203. // "ERROR",
  204. // "APIS_SEARCH_MUSICBRAINZ_ISRC",
  205. // `Searching MusicBrainz ISRC failed with ISRC "${ISRC}". "${err}"`
  206. // );
  207. // return cb({ status: "error", message: err });
  208. // }
  209. // this.log(
  210. // "SUCCESS",
  211. // "APIS_SEARCH_MUSICBRAINZ_ISRC",
  212. // `User "${session.userId}" searched MusicBrainz ISRC succesfully for ISRC "${ISRC}".`
  213. // );
  214. // return cb({
  215. // status: "success",
  216. // data: {
  217. // response
  218. // }
  219. // });
  220. // }
  221. // );
  222. // }),
  223. // /**
  224. // *
  225. // *
  226. // * @param session
  227. // * @param trackId - the trackId
  228. // * @param {Function} cb
  229. // */
  230. // searchWikidataBySpotifyTrackId: useHasPermission(
  231. // "admin.view.spotify",
  232. // function searchWikidataBySpotifyTrackId(session, trackId, cb) {
  233. // async.waterfall(
  234. // [
  235. // next => {
  236. // if (!trackId) {
  237. // next("Invalid trackId provided.");
  238. // return;
  239. // }
  240. // CacheModule.runJob("HGET", { table: "wikidata-spotify-track", key: trackId })
  241. // .then(response => {
  242. // if (response) next(null, response);
  243. // else next(null, null);
  244. // })
  245. // .catch(err => {
  246. // console.log("WOW", err);
  247. // next(err);
  248. // });
  249. // },
  250. // (body, next) => {
  251. // if (body) {
  252. // next(null, body);
  253. // return;
  254. // }
  255. // // const options = {
  256. // // params: { fmt: "json", inc: "url-rels" },
  257. // // headers: {
  258. // // "User-Agent": "Musare/3.9.0-fork ( https://git.kvos.dev/kris/MusareFork )" // TODO set this in accordance to https://musicbrainz.org/doc/MusicBrainz_API/Rate_Limiting
  259. // // }
  260. // // };
  261. // // axios
  262. // // .get(`https://musicbrainz.org/ws/2/isrc/${ISRC}`, options)
  263. // // .then(res => next(null, res.data))
  264. // // .catch(err => next(err));
  265. // },
  266. // (body, next) => {
  267. // CacheModule.runJob("HSET", { table: "musicbrainz-isrc", key: ISRC, value: body })
  268. // .then(() => {})
  269. // .catch(() => {});
  270. // next(null, body);
  271. // },
  272. // (body, next) => {
  273. // const response = {};
  274. // const recordingUrls = Array.from(
  275. // new Set(
  276. // body.recordings
  277. // .map(recording =>
  278. // recording.relations
  279. // .filter(
  280. // relation =>
  281. // relation["target-type"] === "url" &&
  282. // relation.url &&
  283. // // relation["type-id"] === "7e41ef12-a124-4324-afdb-fdbae687a89c" &&
  284. // (relation.url.resource.indexOf("youtu.be") !== -1 ||
  285. // relation.url.resource.indexOf("youtube.com") !== -1 ||
  286. // relation.url.resource.indexOf("soundcloud.com") !== -1)
  287. // )
  288. // .map(relation => relation.url.resource)
  289. // )
  290. // .flat()
  291. // )
  292. // );
  293. // response.recordingUrls = recordingUrls;
  294. // response.raw = body;
  295. // next(null, response);
  296. // }
  297. // ],
  298. // async (err, response) => {
  299. // if (err && err !== true) {
  300. // err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  301. // this.log(
  302. // "ERROR",
  303. // "APIS_SEARCH_TODO",
  304. // `Searching MusicBrainz ISRC failed with ISRC "${ISRC}". "${err}"`
  305. // );
  306. // return cb({ status: "error", message: err });
  307. // }
  308. // this.log(
  309. // "SUCCESS",
  310. // "APIS_SEARCH_TODO",
  311. // `User "${session.userId}" searched MusicBrainz ISRC succesfully for ISRC "${ISRC}".`
  312. // );
  313. // return cb({
  314. // status: "success",
  315. // data: {
  316. // response
  317. // }
  318. // });
  319. // }
  320. // );
  321. // }
  322. // ),
  323. // /**
  324. // *
  325. // *
  326. // * @param session
  327. // * @param trackId - the trackId
  328. // * @param {Function} cb
  329. // */
  330. // searchWikidataByMusicBrainzWorkId: useHasPermission(
  331. // "admin.view.spotify",
  332. // function searchWikidataByMusicBrainzWorkId(session, workId, cb) {
  333. // async.waterfall(
  334. // [
  335. // next => {
  336. // if (!workId) {
  337. // next("Invalid workId provided.");
  338. // return;
  339. // }
  340. // CacheModule.runJob("HGET", { table: "wikidata-musicbrainz-work", key: workId })
  341. // .then(response => {
  342. // if (response) next(null, response);
  343. // else next(null, null);
  344. // })
  345. // .catch(err => {
  346. // next(err);
  347. // });
  348. // },
  349. // (body, next) => {
  350. // if (body) {
  351. // next(null, body);
  352. // return;
  353. // }
  354. // const endpointUrl = "https://query.wikidata.org/sparql";
  355. // const sparqlQuery = `SELECT DISTINCT ?item ?itemLabel ?YouTube_video_ID WHERE {
  356. // SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
  357. // {
  358. // SELECT DISTINCT ?item WHERE {
  359. // ?item p:P435 ?statement0.
  360. // ?statement0 ps:P435 "${workId}".
  361. // }
  362. // LIMIT 100
  363. // }
  364. // OPTIONAL { ?item wdt:P1651 ?YouTube_video_ID. }
  365. // }`;
  366. // // OPTIONAL { ?item wdt:P3040 ?SoundCloud_track_ID. }
  367. // const options = {
  368. // params: { query: sparqlQuery },
  369. // headers: {
  370. // Accept: "application/sparql-results+json"
  371. // }
  372. // };
  373. // axios
  374. // .get(endpointUrl, options)
  375. // .then(res => next(null, res.data))
  376. // .catch(err => next(err));
  377. // },
  378. // (body, next) => {
  379. // CacheModule.runJob("HSET", { table: "wikidata-musicbrainz-work", key: workId, value: body })
  380. // .then(() => {})
  381. // .catch(() => {});
  382. // next(null, body);
  383. // },
  384. // (body, next) => {
  385. // const response = {};
  386. // const youtubeIds = Array.from(
  387. // new Set(
  388. // body.results.bindings
  389. // .filter(binding => !!binding.YouTube_video_ID)
  390. // .map(binding => binding.YouTube_video_ID.value)
  391. // )
  392. // );
  393. // // const soundcloudIds = Array.from(new Set(body.results.bindings.filter(binding => !!binding["SoundCloud_track_ID"]).map(binding => binding["SoundCloud_track_ID"].value)))
  394. // response.youtubeIds = youtubeIds;
  395. // response.raw = body;
  396. // next(null, response);
  397. // }
  398. // ],
  399. // async (err, response) => {
  400. // if (err && err !== true) {
  401. // err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  402. // this.log(
  403. // "ERROR",
  404. // "APIS_SEARCH_TODO",
  405. // `Searching MusicBrainz ISRC failed with ISRC "${workId}". "${err}"`
  406. // );
  407. // return cb({ status: "error", message: err });
  408. // }
  409. // this.log(
  410. // "SUCCESS",
  411. // "APIS_SEARCH_TODO",
  412. // `User "${session.userId}" searched MusicBrainz ISRC succesfully for ISRC "${workId}".`
  413. // );
  414. // return cb({
  415. // status: "success",
  416. // data: {
  417. // response
  418. // }
  419. // });
  420. // }
  421. // );
  422. // }
  423. // ),
  424. /**
  425. *
  426. *
  427. * @param session
  428. * @param trackId - the trackId
  429. * @param {Function} cb
  430. */
  431. getAlternativeMediaSourcesForTracks: useHasPermission(
  432. "admin.view.spotify",
  433. function getAlternativeMediaSourcesForTracks(session, mediaSources, collectAlternativeMediaSourcesOrigins, cb) {
  434. async.waterfall(
  435. [
  436. next => {
  437. if (!mediaSources) {
  438. next("Invalid mediaSources provided.");
  439. return;
  440. }
  441. next();
  442. },
  443. async () => {
  444. this.keepLongJob();
  445. this.publishProgress({
  446. status: "started",
  447. title: "Getting alternative media sources for Spotify tracks",
  448. message: "Starting up",
  449. id: this.toString()
  450. });
  451. console.log("KRIS@4", this.toString());
  452. // await CacheModule.runJob(
  453. // "RPUSH",
  454. // { key: `longJobs.${session.userId}`, value: this.toString() },
  455. // this
  456. // );
  457. SpotifyModule.runJob(
  458. "GET_ALTERNATIVE_MEDIA_SOURCES_FOR_TRACKS",
  459. { mediaSources, collectAlternativeMediaSourcesOrigins },
  460. this
  461. );
  462. }
  463. ],
  464. async err => {
  465. if (err) {
  466. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  467. this.log(
  468. "ERROR",
  469. "APIS_GET_ALTERNATIVE_SOURCES",
  470. `Getting alternative sources failed for "${mediaSources.join(", ")}". "${err}"`
  471. );
  472. return cb({ status: "error", message: err });
  473. }
  474. this.log(
  475. "SUCCESS",
  476. "APIS_GET_ALTERNATIVE_SOURCES",
  477. `User "${session.userId}" started getting alternatives for "${mediaSources.join(", ")}".`
  478. );
  479. return cb({
  480. status: "success"
  481. });
  482. }
  483. );
  484. }
  485. ),
  486. /**
  487. *
  488. *
  489. * @param session
  490. * @param trackId - the trackId
  491. * @param {Function} cb
  492. */
  493. getAlternativeAlbumSourcesForAlbums: useHasPermission(
  494. "admin.view.spotify",
  495. function getAlternativeAlbumSourcesForAlbums(session, albumIds, collectAlternativeAlbumSourcesOrigins, cb) {
  496. async.waterfall(
  497. [
  498. next => {
  499. if (!albumIds) {
  500. next("Invalid albumIds provided.");
  501. return;
  502. }
  503. next();
  504. },
  505. async () => {
  506. this.keepLongJob();
  507. this.publishProgress({
  508. status: "started",
  509. title: "Getting alternative album sources for Spotify albums",
  510. message: "Starting up",
  511. id: this.toString()
  512. });
  513. console.log("KRIS@4", this.toString());
  514. // await CacheModule.runJob(
  515. // "RPUSH",
  516. // { key: `longJobs.${session.userId}`, value: this.toString() },
  517. // this
  518. // );
  519. SpotifyModule.runJob(
  520. "GET_ALTERNATIVE_ALBUM_SOURCES_FOR_ALBUMS",
  521. { albumIds, collectAlternativeAlbumSourcesOrigins },
  522. this
  523. );
  524. }
  525. ],
  526. async err => {
  527. if (err) {
  528. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  529. this.log(
  530. "ERROR",
  531. "APIS_GET_ALTERNATIVE_ALBUM_SOURCES",
  532. `Getting alternative album sources failed for "${albumIds.join(", ")}". "${err}"`
  533. );
  534. return cb({ status: "error", message: err });
  535. }
  536. this.log(
  537. "SUCCESS",
  538. "APIS_GET_ALTERNATIVE_ALBUM_SOURCES",
  539. `User "${session.userId}" started getting alternative album spirces for "${albumIds.join(
  540. ", "
  541. )}".`
  542. );
  543. return cb({
  544. status: "success"
  545. });
  546. }
  547. );
  548. }
  549. ),
  550. /**
  551. *
  552. *
  553. * @param session
  554. * @param trackId - the trackId
  555. * @param {Function} cb
  556. */
  557. getAlternativeArtistSourcesForArtists: useHasPermission(
  558. "admin.view.spotify",
  559. function getAlternativeArtistSourcesForArtists(session, artistIds, collectAlternativeArtistSourcesOrigins, cb) {
  560. async.waterfall(
  561. [
  562. next => {
  563. if (!artistIds) {
  564. next("Invalid artistIds provided.");
  565. return;
  566. }
  567. next();
  568. },
  569. async () => {
  570. this.keepLongJob();
  571. this.publishProgress({
  572. status: "started",
  573. title: "Getting alternative artist sources for Spotify artists",
  574. message: "Starting up",
  575. id: this.toString()
  576. });
  577. console.log("KRIS@4", this.toString());
  578. // await CacheModule.runJob(
  579. // "RPUSH",
  580. // { key: `longJobs.${session.userId}`, value: this.toString() },
  581. // this
  582. // );
  583. SpotifyModule.runJob(
  584. "GET_ALTERNATIVE_ARTIST_SOURCES_FOR_ARTISTS",
  585. { artistIds, collectAlternativeArtistSourcesOrigins },
  586. this
  587. );
  588. }
  589. ],
  590. async err => {
  591. if (err) {
  592. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  593. this.log(
  594. "ERROR",
  595. "APIS_GET_ALTERNATIVE_ARTIST_SOURCES",
  596. `Getting alternative artist sources failed for "${artistIds.join(", ")}". "${err}"`
  597. );
  598. return cb({ status: "error", message: err });
  599. }
  600. this.log(
  601. "SUCCESS",
  602. "APIS_GET_ALTERNATIVE_ARTIST_SOURCES",
  603. `User "${session.userId}" started getting alternative artist spirces for "${artistIds.join(
  604. ", "
  605. )}".`
  606. );
  607. return cb({
  608. status: "success"
  609. });
  610. }
  611. );
  612. }
  613. ),
  614. /**
  615. * Joins a room
  616. *
  617. * @param {object} session - user session
  618. * @param {string} room - the room to join
  619. * @param {Function} cb - callback
  620. */
  621. joinRoom(session, room, cb) {
  622. const roomName = room.split(".")[0];
  623. // const roomId = room.split(".")[1];
  624. const rooms = {
  625. home: null,
  626. news: null,
  627. profile: null,
  628. "view-youtube-video": null,
  629. "manage-station": null,
  630. // "manage-station": "stations.view",
  631. "edit-song": "songs.update",
  632. "edit-songs": "songs.update",
  633. "import-album": "songs.update",
  634. // "edit-playlist": "playlists.update",
  635. "view-report": "reports.get",
  636. "edit-user": "users.update",
  637. "view-api-request": "youtube.getApiRequest",
  638. "view-punishment": "punishments.get"
  639. };
  640. const join = (status, error) => {
  641. if (status === "success")
  642. WSModule.runJob("SOCKET_JOIN_ROOM", {
  643. socketId: session.socketId,
  644. room
  645. })
  646. .then(() => cb({ status: "success", message: "Successfully joined room." }))
  647. .catch(err => join("error", err.message));
  648. else {
  649. this.log("ERROR", `Joining room failed: ${error}`);
  650. cb({ status: "error", message: error });
  651. }
  652. };
  653. if (rooms[roomName] === null) join("success");
  654. else if (rooms[roomName])
  655. hasPermission(rooms[roomName], session)
  656. .then(() => join("success"))
  657. .catch(err => join("error", err));
  658. else join("error", "Room not found");
  659. },
  660. /**
  661. * Leaves a room
  662. *
  663. * @param {object} session - user session
  664. * @param {string} room - the room to leave
  665. * @param {Function} cb - callback
  666. */
  667. leaveRoom(session, room, cb) {
  668. if (
  669. room === "home" ||
  670. room.startsWith("profile.") ||
  671. room.startsWith("manage-station.") ||
  672. room.startsWith("edit-song.") ||
  673. room.startsWith("view-report.") ||
  674. room === "import-album" ||
  675. room === "edit-songs"
  676. ) {
  677. WSModule.runJob("SOCKET_LEAVE_ROOM", {
  678. socketId: session.socketId,
  679. room
  680. })
  681. .then(() => {})
  682. .catch(err => {
  683. this.log("ERROR", `Leaving room failed: ${err.message}`);
  684. });
  685. }
  686. cb({ status: "success", message: "Successfully left room." });
  687. },
  688. /**
  689. * Joins an admin room
  690. *
  691. * @param {object} session - user session
  692. * @param {string} page - the admin room to join
  693. * @param {Function} cb - callback
  694. */
  695. joinAdminRoom(session, page, cb) {
  696. if (
  697. page === "songs" ||
  698. page === "stations" ||
  699. page === "reports" ||
  700. page === "news" ||
  701. page === "playlists" ||
  702. page === "users" ||
  703. page === "statistics" ||
  704. page === "punishments" ||
  705. page === "youtube" ||
  706. page === "youtubeVideos" ||
  707. page === "youtubeChannels" ||
  708. (config.get("experimental.soundcloud") && (page === "soundcloud" || page === "soundcloudTracks")) ||
  709. page === "import" ||
  710. page === "dataRequests"
  711. ) {
  712. hasPermission(`admin.view.${page}`, session.userId)
  713. .then(() =>
  714. WSModule.runJob("SOCKET_LEAVE_ROOMS", { socketId: session.socketId }).then(() => {
  715. WSModule.runJob(
  716. "SOCKET_JOIN_ROOM",
  717. {
  718. socketId: session.socketId,
  719. room: `admin.${page}`
  720. },
  721. this
  722. ).then(() => cb({ status: "success", message: "Successfully joined admin room." }));
  723. })
  724. )
  725. .catch(() => cb({ status: "error", message: "Failed to join admin room." }));
  726. }
  727. },
  728. /**
  729. * Leaves all rooms
  730. *
  731. * @param {object} session - user session
  732. * @param {Function} cb - callback
  733. */
  734. leaveRooms(session, cb) {
  735. WSModule.runJob("SOCKET_LEAVE_ROOMS", { socketId: session.socketId });
  736. cb({ status: "success", message: "Successfully left all rooms." });
  737. },
  738. /**
  739. * Returns current date
  740. *
  741. * @param {object} session - user session
  742. * @param {Function} cb - callback
  743. */
  744. ping(session, cb) {
  745. cb({ status: "success", message: "Successfully pinged.", data: { date: Date.now() } });
  746. }
  747. };