index.js 4.7 KB

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