index.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. module.exports = function (io) {
  2. var app = require('express')();
  3. // Body parsing
  4. var bodyParser = require('body-parser');
  5. app.use(bodyParser.urlencoded({extended: true}));
  6. app.use(bodyParser.json());
  7. // Validation
  8. var expressValidator = require('express-validator');
  9. app.use(expressValidator());
  10. // Child process, for spawning youtube-dl
  11. var child_process = require('child_process');
  12. // The location of the youtube-dl executable
  13. var YOUTUBE_DL_LOC = '/usr/bin/youtube-dl'
  14. // Keep track of music to play, playing, and played
  15. var playlist = [];
  16. var playing = 'None';
  17. var played = [];
  18. var Player = require('player');
  19. io.on('connection', function (socket) {
  20. console.log('a user connected');
  21. });
  22. // Create a player with the proper error handling.
  23. function playerCreator(song) {
  24. if (song)
  25. return new Player(song)
  26. .on('error', function(err) {playerHandleError(playlist, played)})
  27. return new Player()
  28. .on('error', function(err) {playerHandleError(playlist, played)})
  29. }
  30. player = playerCreator();
  31. // Player functionality
  32. // Songs move from playlist (if nothing is playing presently), to playing, to played.
  33. // TODO check if song already exists in played.
  34. // event: on error (No next song was found).
  35. function playerHandleError(playlist, played) {
  36. // TODO Workaround for a bug in player: wait a couple seconds so the
  37. // songs don't overlap.
  38. // Move the recently playing song to played.
  39. played.push(playing);
  40. if (playlist.length != 0) {
  41. // Play the next song.
  42. player = playerCreator(playlist[0]);
  43. player.play();
  44. // Remove the added song.
  45. playing = playlist[0];
  46. playlist.shift();
  47. } else {
  48. // Reset the object, resetting its playlist.
  49. player = playerCreator();
  50. playing = 'None';
  51. }
  52. }
  53. // Add a song and start the playlist, if it's empty.
  54. function playerAddSong(song) {
  55. if (player.list.length == 0) {
  56. // If this is the player's first song, start it.
  57. player = playerCreator(song);
  58. player.play();
  59. playing = song;
  60. } else {
  61. // Otherwise add it to the queue
  62. playlist.push(song);
  63. }
  64. }
  65. /* GET home page. */
  66. app.get('/', function(req, res, next) {
  67. var playlist_view;
  68. if(playlist.length) {
  69. playlist_view = '<p>Playlist:</p><ul>';
  70. for(var i=0; i < playlist.length; i++) {
  71. playlist_view +=
  72. '<li>' +
  73. playlist[i].replace(/^\.\/downloads\//, '') .replace(/\.mp3$/, '') +
  74. '</li>';
  75. }
  76. playlist_view += '</ul>';
  77. } else {
  78. playlist_view = '<p>No songs in playlist.</p>';
  79. }
  80. var playing_view = '<p>Now playing: ' + playing.replace(/^\.\/downloads\//, '') .replace(/\.mp3$/, '') + '</p>';
  81. var played_view;
  82. if(played.length) {
  83. played_view = '<p>Played:</p><ul>';
  84. for(var i=0; i < played.length; i++) {
  85. played_view +=
  86. '<li>' +
  87. played[i].replace(/^\.\/downloads\//, '') .replace(/\.mp3$/, '') +
  88. '</li>';
  89. }
  90. played_view += '</ul>';
  91. } else {
  92. played_view = '<p>No played songs.</p>';
  93. }
  94. res.render('index', { playlist_view: playlist_view,
  95. playing_view: playing_view,
  96. played_view: played_view });
  97. });
  98. app.get('/youtube', function(req, res, next) {
  99. res.render('youtube');
  100. });
  101. app.use(expressValidator({
  102. customValidators: {
  103. dlSuccess: function(video) {
  104. // Test if the requested video is available.
  105. // TODO make this non-blocking so music doesn't stop
  106. var youtube_dl = child_process.spawnSync(YOUTUBE_DL_LOC, ['-s', video]);
  107. // DEBUG: for when I forget to change the var
  108. if(youtube_dl.stderr == null) {
  109. console.log("Your youtube-dl location is probably invalid.");
  110. }
  111. if (youtube_dl.stderr.toString()) {
  112. return false;
  113. }
  114. return true;
  115. }
  116. }
  117. }
  118. ));
  119. app.post('/youtube', function(req, res) {
  120. var video = req.body.video;
  121. req.checkBody('video', 'URL is not valid.').dlSuccess();
  122. var errors = req.validationErrors();
  123. if(errors){
  124. res.render('youtube', {
  125. errors:errors
  126. });
  127. } else {
  128. var youtube_dl = child_process.spawn(YOUTUBE_DL_LOC, ['-x', '--audio-format', 'mp3', '-o', 'downloads/%(title)s.%(ext)s', video]);
  129. youtube_dl.on('close', (code) => {
  130. console.log("Done getting " + video);
  131. var error;
  132. youtube_dl.stderr.on('data', (data) => {
  133. error = data;
  134. console.log(`Error getting video: ${data}`);
  135. // TODO give error to user when they return to /
  136. });
  137. if(!error) {
  138. var youtube_dl_get_title = child_process.spawnSync(YOUTUBE_DL_LOC, ['--get-title', video]);
  139. console.log(youtube_dl_get_title.stdout.toString());
  140. playerAddSong('./downloads/' + youtube_dl_get_title.stdout.toString()
  141. .replace('\n', '')
  142. .replace(new RegExp('"', 'g'), '\'')
  143. + ".mp3");
  144. }
  145. res.redirect('/');
  146. });
  147. }
  148. });
  149. app.get('/file', function(req, res, next) {
  150. res.render('file');
  151. });
  152. // Return the router.
  153. return app;
  154. // module.exports = app;
  155. };