queueSongs.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. 'use strict';
  2. const db = require('../db');
  3. const utils = require('../utils');
  4. const logger = require('../logger');
  5. const notifications = require('../notifications');
  6. const cache = require('../cache');
  7. const async = require('async');
  8. const config = require('config');
  9. const request = require('request');
  10. const hooks = require('./hooks');
  11. cache.sub('queue.newSong', songId => {
  12. db.models.queueSong.findOne({_id: songId}, (err, song) => {
  13. utils.emitToRoom('admin.queue', 'event:admin.queueSong.added', song);
  14. });
  15. });
  16. cache.sub('queue.removedSong', songId => {
  17. utils.emitToRoom('admin.queue', 'event:admin.queueSong.removed', songId);
  18. });
  19. cache.sub('queue.update', songId => {
  20. db.models.queueSong.findOne({_id: songId}, (err, song) => {
  21. utils.emitToRoom('admin.queue', 'event:admin.queueSong.updated', song);
  22. });
  23. });
  24. module.exports = {
  25. /**
  26. * Gets all queuesongs
  27. *
  28. * @param {Object} session - the session object automatically added by socket.io
  29. * @param {Function} cb - gets called with the result
  30. */
  31. index: hooks.adminRequired((session, cb) => {
  32. async.waterfall([
  33. (next) => {
  34. db.models.queueSong.find({}, next);
  35. }
  36. ], (err, songs) => {
  37. if (err) {
  38. logger.error("QUEUE_INDEX", `Indexing queuesongs failed. "${err.message}"`);
  39. return cb({status: 'failure', message: 'Something went wrong.'});
  40. } else {
  41. module.exports.getSet(session, 1, result => {
  42. logger.success("QUEUE_INDEX", `Indexing queuesongs successful.`);
  43. return cb({
  44. songs: result,
  45. maxLength: songs.length
  46. });
  47. });
  48. }
  49. });
  50. }),
  51. getSet: hooks.adminRequired((session, set, cb) => {
  52. db.models.queueSong.find({}).limit(50 * set).exec((err, songs) => {
  53. if (err) throw err;
  54. cb(songs.splice(Math.max(songs.length - 50, 0)));
  55. });
  56. }),
  57. /**
  58. * Updates a queuesong
  59. *
  60. * @param {Object} session - the session object automatically added by socket.io
  61. * @param {String} songId - the id of the queuesong that gets updated
  62. * @param {Object} updatedSong - the object of the updated queueSong
  63. * @param {Function} cb - gets called with the result
  64. * @param {String} userId - the userId automatically added by hooks
  65. */
  66. update: hooks.adminRequired((session, songId, updatedSong, cb, userId) => {
  67. async.waterfall([
  68. (next) => {
  69. db.models.queueSong.findOne({ _id: songId }, next);
  70. },
  71. (song, next) => {
  72. if(!song) return next('Song not found');
  73. let updated = false;
  74. let $set = {};
  75. for (let prop in updatedSong) if (updatedSong[prop] !== song[prop]) $set[prop] = updatedSong[prop]; updated = true;
  76. if (!updated) return next('No properties changed');
  77. db.models.queueSong.update({ _id: songId }, {$set}, next);
  78. }
  79. ], (err) => {
  80. if (err) {
  81. let error = 'An error occurred.';
  82. if (typeof err === "string") error = err;
  83. else if (err.message) error = err.message;
  84. logger.error("QUEUE_UPDATE", `Updating queuesong "${songId}" failed for user ${userId}. "${err.message}"`);
  85. return cb({status: 'failure', message: error});
  86. }
  87. cache.pub('queue.update', songId);
  88. logger.success("QUEUE_UPDATE", `User "${userId}" successfully update queuesong "${songId}".`);
  89. return cb({status: 'success', message: 'Successfully updated song.'});
  90. });
  91. }),
  92. /**
  93. * Removes a queuesong
  94. *
  95. * @param {Object} session - the session object automatically added by socket.io
  96. * @param {String} songId - the id of the queuesong that gets removed
  97. * @param {Function} cb - gets called with the result
  98. * @param {String} userId - the userId automatically added by hooks
  99. */
  100. remove: hooks.adminRequired((session, songId, cb, userId) => {
  101. async.waterfall([
  102. (next) => {
  103. db.models.queueSong.remove({ _id: songId }, next);
  104. }
  105. ], (err) => {
  106. if (err) {
  107. let error = 'An error occurred.';
  108. if (typeof err === "string") error = err;
  109. else if (err.message) error = err.message;
  110. logger.error("QUEUE_REMOVE", `Removing queuesong "${songId}" failed for user ${userId}. "${err.message}"`);
  111. return cb({status: 'failure', message: error});
  112. }
  113. cache.pub('queue.removedSong', songId);
  114. logger.success("QUEUE_REMOVE", `User "${userId}" successfully removed queuesong "${songId}".`);
  115. return cb({status: 'success', message: 'Successfully updated song.'});
  116. });
  117. }),
  118. /**
  119. * Creates a queuesong
  120. *
  121. * @param {Object} session - the session object automatically added by socket.io
  122. * @param {String} songId - the id of the song that gets added
  123. * @param {Function} cb - gets called with the result
  124. * @param {String} userId - the userId automatically added by hooks
  125. */
  126. add: hooks.loginRequired((session, songId, cb, userId) => {
  127. let requestedAt = Date.now();
  128. async.waterfall([
  129. (next) => {
  130. db.models.queueSong.findOne({_id: songId}, next);
  131. },
  132. (song, next) => {
  133. if (song) return next('This song is already in the queue.');
  134. db.models.song.findOne({_id: songId}, next);
  135. },
  136. // Get YouTube data from id
  137. (song, next) => {
  138. if (song) return next('This song has already been added.');
  139. //TODO Add err object as first param of callback
  140. utils.getSongFromYouTube(songId, (song) => {
  141. song.artists = [];
  142. song.genres = [];
  143. song.skipDuration = 0;
  144. song.thumbnail = 'empty';
  145. song.explicit = false;
  146. song.requestedBy = userId;
  147. song.requestedAt = requestedAt;
  148. next(null, song);
  149. });
  150. },
  151. (newSong, next) => {
  152. //TODO Add err object as first param of callback
  153. utils.getSongFromSpotify(newSong, (song) => {
  154. next(null, song);
  155. });
  156. },
  157. (newSong, next) => {
  158. const song = new db.models.queueSong(newSong);
  159. song.save(err => {
  160. if (err) return next(err);
  161. next(null, newSong);
  162. });
  163. },
  164. (newSong, next) => {
  165. db.models.user.findOne({ _id: userId }, (err, user) => {
  166. if (err) next(err, newSong);
  167. else {
  168. user.statistics.songsRequested = user.statistics.songsRequested + 1;
  169. user.save(err => {
  170. if (err) return next(err, newSong);
  171. else next(null, newSong);
  172. });
  173. }
  174. });
  175. }
  176. ], (err, newSong) => {
  177. if (err) {
  178. let error = 'An error occurred.';
  179. if (typeof err === "string") error = err;
  180. else if (err.message) error = err.message;
  181. return cb({status: 'failure', message: error});
  182. }
  183. cache.pub('queue.newSong', newSong._id);
  184. return cb({ status: 'success', message: 'Successfully added that song to the queue' });
  185. });
  186. })
  187. };