« get me outta code hell

http-music - Command-line music player + utils (not a server!)
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/downloaders.js36
-rw-r--r--src/loop-play.js14
-rwxr-xr-xsrc/play.js31
3 files changed, 69 insertions, 12 deletions
diff --git a/src/downloaders.js b/src/downloaders.js
new file mode 100644
index 0000000..527f67d
--- /dev/null
+++ b/src/downloaders.js
@@ -0,0 +1,36 @@
+const fs = require('fs')
+const fetch = require('node-fetch')
+const promisifyProcess = require('./promisify-process')
+const tempy = require('tempy')
+
+const { spawn } = require('child_process')
+const { promisify } = require('util')
+
+const writeFile = promisify(fs.writeFile)
+const rename = promisify(fs.rename)
+
+function makeHTTPDownloader() {
+  return function(arg, out) {
+    return fetch(arg)
+      .then(response => response.buffer())
+      .then(buffer => writeFile(out, buffer))
+  }
+}
+
+function makeYouTubeDownloader() {
+  return function(arg, out) {
+    const tempDir = tempy.directory()
+
+    const opts = [
+      '--extract-audio',
+      '--audio-format', 'wav',
+      '--output', tempDir + '/dl.%(ext)s',
+      arg
+    ]
+
+    return promisifyProcess(spawn('youtube-dl', opts), false)
+      .then(() => rename(tempDir + '/dl.wav', out))
+  }
+}
+
+module.exports = {makeHTTPDownloader, makeYouTubeDownloader}
diff --git a/src/loop-play.js b/src/loop-play.js
index 560ac63..50bca80 100644
--- a/src/loop-play.js
+++ b/src/loop-play.js
@@ -12,7 +12,7 @@ const sanitize = require('sanitize-filename')
 
 const writeFile = promisify(fs.writeFile)
 
-module.exports = async function loopPlay(fn, playArgs = []) {
+module.exports = async function loopPlay(picker, downloader, playArgs = []) {
   // Looping play function. Takes one argument, the "pick" function,
   // which returns a track to play. Preemptively downloads the next
   // track while the current one is playing for seamless continuation
@@ -21,22 +21,20 @@ module.exports = async function loopPlay(fn, playArgs = []) {
   // used as arguments to the `play` process (before the file name).
 
   async function downloadNext() {
-    const picked = fn()
+    const picked = picker()
 
     if (picked == null) {
       return false
     }
 
-    const [ title, href ] = picked
-    console.log(`Downloading ${title}..\n${href}`)
+    const [ title, downloaderArg ] = picked
+    console.log(`Downloading ${title}..\nDownloader arg: ${downloaderArg}`)
 
     const tempDir = tempy.directory()
     const wavFile = tempDir + `/.${sanitize(title)}.wav`
-    const downloadFile = tempDir + '/.dl-' + path.basename(href)
+    const downloadFile = tempDir + '/.dl-' + path.basename(downloaderArg)
 
-    const res = await fetch(href)
-    const buffer = await res.buffer()
-    await writeFile(downloadFile, buffer)
+    await downloader(downloaderArg, downloadFile)
 
     try {
       await convert(downloadFile, wavFile)
diff --git a/src/play.js b/src/play.js
index 0ffe996..38b05d5 100755
--- a/src/play.js
+++ b/src/play.js
@@ -7,6 +7,8 @@ const fs = require('fs')
 const { promisify } = require('util')
 const loopPlay = require('./loop-play')
 const processArgv = require('./process-argv')
+
+const downloaders = require('./downloaders')
 const pickers = require('./pickers')
 
 const {
@@ -22,6 +24,7 @@ readFile('./playlist.json', 'utf-8')
     let curPlaylist = playlist
 
     let pickerType = 'shuffle'
+    let downloaderType = 'http'
     let playOpts = []
 
     // WILL play says whether the user has forced playback via an argument.
@@ -132,14 +135,21 @@ readFile('./playlist.json', 'utf-8')
       'np': util => util.alias('-no-play'),
 
       '-picker': function(util) {
-        // --picker <shuffle|ordered>
+        // --picker <picker type>
         // Selects the mode that the song to play is picked.
-        // This should be used after finishing modifying the active
-        // playlist.
+        // See pickers.js.
 
         pickerType = util.nextArg()
       },
 
+      '-downloader': function(util) {
+        // --downloader <downloader type>
+        // Selects the mode that songs will be downloaded with.
+        // See downloaders.js.
+
+        downloaderType = util.nextArg()
+      },
+
       '-play-opts': function(util) {
         // --play-opts <opts>
         // Sets command line options passed to the `play` command.
@@ -165,9 +175,22 @@ readFile('./playlist.json', 'utf-8')
         picker = pickers.makeOrderedPlaylistPicker(curPlaylist)
       } else {
         console.error("Invalid picker type: " + pickerType)
+        return
+      }
+
+      let downloader
+      if (downloaderType === 'http') {
+        console.log("Using HTTP downloader.")
+        downloader = downloaders.makeHTTPDownloader()
+      } else if (downloaderType === 'youtube') {
+        console.log("Using YouTube downloader.")
+        downloader = downloaders.makeYouTubeDownloader()
+      } else {
+        console.error("Invalid downloader type: " + downloaderType)
+        return
       }
 
-      return loopPlay(picker, playOpts)
+      return loopPlay(picker, downloader, playOpts)
     } else {
       return curPlaylist
     }