« 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--man/http-music-crawl-http.14
-rw-r--r--man/http-music-crawl-local.121
-rwxr-xr-xsrc/crawl-http.js2
-rwxr-xr-xsrc/crawl-local.js63
-rw-r--r--todo.txt5
5 files changed, 80 insertions, 15 deletions
diff --git a/man/http-music-crawl-http.1 b/man/http-music-crawl-http.1
index 62bbc24..9202c65 100644
--- a/man/http-music-crawl-http.1
+++ b/man/http-music-crawl-http.1
@@ -54,10 +54,10 @@ http://example.com/
   ]},
   {name: 'Bad News', [
     {name: 'Bad News - Single', items: [
-      ['Bad News', 'http://example.com/Bad%20News/Bad%20News%20-%20Single/Bad%20News.mp3']
+      {name: 'Bad News', downloaderArg: 'http://example.com/Bad%20News/Bad%20News%20-%20Single/Bad%20News.mp3'}
     ]},
     {name: 'Irony', items: [
-      ['Rahhhh!!', 'http://example.com/Bad%20News/Irony/Rahhhh!!.mp3']
+      {name: 'Rahhhh!!', downloaderArg: 'http://example.com/Bad%20News/Irony/Rahhhh!!.mp3'}
     ]}
   ]}
 ]}
diff --git a/man/http-music-crawl-local.1 b/man/http-music-crawl-local.1
new file mode 100644
index 0000000..4949d98
--- /dev/null
+++ b/man/http-music-crawl-local.1
@@ -0,0 +1,21 @@
+.TH http-music-crawl-local 1
+
+.SH NAME
+http-music-crawl-local - create a playlist from files on your own computer
+
+.SH SYNOPSIS
+.B http-music-crawl-local
+<path to top music directory>
+[opts...]
+
+.SH DESCRIPTION
+\fBhttp-music-crawl-local\fR is a command line utility which recursively crawls a given directory and creates a playlist from found items (with groups determined by crawled directories).
+It attempts to only add music files (mp3, ogg, etc) to the playlist (see \fB--extensions\fR).
+
+.SH OPTIONS
+.TP
+.BR -e ", " --extensions ", " --exts
+Sets file extensions that are considered music tracks to be added to the result playlist.
+\fB<extensions>\fR is a comma-separated list of extensions, not including the "dots"; e.g. \fR'mp3,wav'\fB.
+A default list of extensions exists but is not *extremely* extensive.
+Use --extensions when needed!
diff --git a/src/crawl-http.js b/src/crawl-http.js
index ad3b776..826e4d5 100755
--- a/src/crawl-http.js
+++ b/src/crawl-http.js
@@ -153,7 +153,7 @@ async function main(args) {
     return
   }
 
-  let url = args[0]
+  const url = args[0]
 
   let maxDownloadAttempts = 5
   let verbose = false
diff --git a/src/crawl-local.js b/src/crawl-local.js
index d4176ed..134a574 100755
--- a/src/crawl-local.js
+++ b/src/crawl-local.js
@@ -5,12 +5,18 @@
 const fs = require('fs')
 const path = require('path')
 const naturalSort = require('node-natural-sort')
+const processArgv = require('./process-argv')
 
 const { promisify } = require('util')
 const readDir = promisify(fs.readdir)
 const stat = promisify(fs.stat)
 
-function crawl(dirPath) {
+function crawl(dirPath, extensions = [
+  // This list isn't very extensive, and can be customized via the
+  // --extensions (or --exts, -e) option.
+  'ogg', 'oga',
+  'wav', 'mp3', 'mp4', 'm4a', 'aac'
+]) {
   return readDir(dirPath).then(items => {
     items.sort(naturalSort())
 
@@ -19,26 +25,59 @@ function crawl(dirPath) {
 
       return stat(itemPath).then(stats => {
         if (stats.isDirectory()) {
-          return crawl(itemPath)
-            .then(group => Object.assign(group, {name: item}))
+          return crawl(itemPath, extensions)
+            .then(group => Object.assign({name: item}, group))
         } else if (stats.isFile()) {
-          const track = {name: item, downloaderArg: itemPath}
-          return track
+          // Extname returns a string starting with a dot; we don't want the
+          // dot, so we slice it off of the front.
+          const ext = path.extname(item).slice(1)
+
+          if (extensions.includes(ext)) {
+            const track = {name: item, downloaderArg: itemPath}
+            return track
+          } else {
+            return null
+          }
         }
       })
     }))
-  }).then(items => ({items}))
+  }).then(items => items.filter(Boolean))
+    .then(filteredItems => ({items: filteredItems}))
 }
 
 async function main(args) {
   if (args.length === 0) {
-    console.log("Usage: crawl-local /example/path")
-  } else {
-    const path = args[0]
-
-    const res = await crawl(path)
-    console.log(JSON.stringify(res, null, 2))
+    console.log("Usage: crawl-local /example/path [opts]")
+    return
   }
+
+  const path = args[0]
+
+  let extensions
+
+  await processArgv(args.slice(1), {
+    '-extensions': function(util) {
+      // --extensions <extensions>  (alias: --exts, -e)
+      // Sets file extensions that are considered music tracks to be added to
+      // the result playlist.
+      // <extensions> is a comma-separated list of extensions, not including
+      // the "dots"; e.g. 'mp3,wav'.
+      // A default list of extensions exists but is not *extremely* extensive.
+      // (Use --extensions when needed!)
+
+      extensions = util.nextArg().split(',')
+
+      // *Somebody*'s going to start the extensions with dots; may as well be
+      // careful for that!
+      extensions = extensions.map(e => e.startsWith('.') ? e.slice(1) : e)
+    },
+
+    '-exts': util => util.alias('-extensions'),
+    'e': util => util.alias('-extensions')
+  })
+
+  const res = await crawl(path, extensions)
+  console.log(JSON.stringify(res, null, 2))
 }
 
 module.exports = {main, crawl}
diff --git a/todo.txt b/todo.txt
index 9239493..d3ddeb1 100644
--- a/todo.txt
+++ b/todo.txt
@@ -255,3 +255,8 @@ TODO: Markdown documentation? Man pages are nice, but aren't really all that
       user-friendly (citation needed); for example you can't easily read them
       online. (Whereas Markdown documents are easily viewed online, and aren't
       hard to read by hand, e.g. with `less doc/foo.md`.)
+
+TODO: Handle avconv failing (probably handle downloader rejections from within
+      DownloadController). Less important now that only music file extensions
+      are loaded, but still relevant (for old playlists which may contain
+      .DS_Stores or album cover arts, etc).