« get me outta code hell

mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--giii.json256
-rw-r--r--index.js9
-rw-r--r--todo.txt3
-rw-r--r--ui.js49
4 files changed, 305 insertions, 12 deletions
diff --git a/giii.json b/giii.json
new file mode 100644
index 0000000..c2b3f4b
--- /dev/null
+++ b/giii.json
@@ -0,0 +1,256 @@
+{
+  "items": [
+    {
+      "name": "Grandia III ost - The Legendary Pilot King",
+      "downloaderArg": "https://youtube.com/watch?v=mXj_PRy3mIQ"
+    },
+    {
+      "name": "Grandia III ost - Anfog",
+      "downloaderArg": "https://youtube.com/watch?v=2UVrf2mzf0s"
+    },
+    {
+      "name": "Grandia III ost - Miranda's Theme",
+      "downloaderArg": "https://youtube.com/watch?v=O0TL0R0XvAY"
+    },
+    {
+      "name": "Grandia III ost - Yuki & Rotts",
+      "downloaderArg": "https://youtube.com/watch?v=_9RfmMdqkIU"
+    },
+    {
+      "name": "Grandia III ost - Tension 1",
+      "downloaderArg": "https://youtube.com/watch?v=8BDXTAo9Yc8"
+    },
+    {
+      "name": "Grandia III ost - A Trap Lurking in the Darkness",
+      "downloaderArg": "https://youtube.com/watch?v=Co8N9ySUkvI"
+    },
+    {
+      "name": "Grandia III ost  - GR-Turbo",
+      "downloaderArg": "https://youtube.com/watch?v=wfiqIKvt8mo"
+    },
+    {
+      "name": "Grandia III ost - Yes! We Broke Through One More Barrier!",
+      "downloaderArg": "https://youtube.com/watch?v=0rAg9kB-4rU"
+    },
+    {
+      "name": "Grandia III ost - PEACEFUL",
+      "downloaderArg": "https://youtube.com/watch?v=eLanK9Tj6e4"
+    },
+    {
+      "name": "Grandia III ost  - Happy Mushrooming",
+      "downloaderArg": "https://youtube.com/watch?v=uHIfJTwf8WU"
+    },
+    {
+      "name": "Grandia III ost - Sabatal",
+      "downloaderArg": "https://youtube.com/watch?v=EnBGlElHeNY"
+    },
+    {
+      "name": "Grandia III ost - Theme of Alonso",
+      "downloaderArg": "https://youtube.com/watch?v=i24Bc6qT_xc"
+    },
+    {
+      "name": "Grandia III ost - The Gambler",
+      "downloaderArg": "https://youtube.com/watch?v=U44_DhixrI0"
+    },
+    {
+      "name": "Grandia III ost - Gambling House",
+      "downloaderArg": "https://youtube.com/watch?v=s4v6O2TuZqk"
+    },
+    {
+      "name": "Grandia III ost - Sailor's Spirit",
+      "downloaderArg": "https://youtube.com/watch?v=_sr0L9bDbE4"
+    },
+    {
+      "name": "Grandia III ost - Theme of Bianca",
+      "downloaderArg": "https://youtube.com/watch?v=7QUCVSraOA4"
+    },
+    {
+      "name": "Grandia III ost - Mendy",
+      "downloaderArg": "https://youtube.com/watch?v=YwEuVznql0A"
+    },
+    {
+      "name": "Grandia III ost - A HOT CRASH!!",
+      "downloaderArg": "https://youtube.com/watch?v=gFZfs6ydxAY"
+    },
+    {
+      "name": "Grandia III ost - Requiem of Birth",
+      "downloaderArg": "https://youtube.com/watch?v=2pX85EIPLn0"
+    },
+    {
+      "name": "Grandia III ost - Theme Arrangement 1",
+      "downloaderArg": "https://youtube.com/watch?v=IilSsDUJEVI"
+    },
+    {
+      "name": "Grandia III ost - Morning of Departure -Piano-",
+      "downloaderArg": "https://youtube.com/watch?v=_HdGqevLj-s"
+    },
+    {
+      "name": "Grandia III ost - Where is the Right Way",
+      "downloaderArg": "https://youtube.com/watch?v=jJR6TQ21oqg"
+    },
+    {
+      "name": "Grandia III ost - Morning of Departure -Euph-",
+      "downloaderArg": "https://youtube.com/watch?v=qhDTCI8ST1w"
+    },
+    {
+      "name": "Grandia III ost - Spread the Wings, to the Sky!!",
+      "downloaderArg": "https://youtube.com/watch?v=DXiYScqgDX4"
+    },
+    {
+      "name": "Grandia III ost - Believe in the Future",
+      "downloaderArg": "https://youtube.com/watch?v=cUiNtjxDNYc"
+    },
+    {
+      "name": "Grandia III ost - Tension 4",
+      "downloaderArg": "https://youtube.com/watch?v=vsklG-OGwzg"
+    },
+    {
+      "name": "Grandia III ost - Forest of Arcliff",
+      "downloaderArg": "https://youtube.com/watch?v=NGlvRKU7B30"
+    },
+    {
+      "name": "Grandia III ost - Sacred Soul",
+      "downloaderArg": "https://youtube.com/watch?v=VAfe5fYAqC4"
+    },
+    {
+      "name": "Grandia III ost - Theme of Beast Saint Griffon",
+      "downloaderArg": "https://youtube.com/watch?v=f_TAnGMwNMs"
+    },
+    {
+      "name": "Grandia III ost - Forest of a Fantasy",
+      "downloaderArg": "https://youtube.com/watch?v=tDDbFDE_k18"
+    },
+    {
+      "name": "Grandia III ost - Tension 3  Theme of Emelious",
+      "downloaderArg": "https://youtube.com/watch?v=2C2U1apFA44"
+    },
+    {
+      "name": "Grandia III ost - Baccla",
+      "downloaderArg": "https://youtube.com/watch?v=KKqfJgUGUVc"
+    },
+    {
+      "name": "Games Ost Emotional - To the Moon  ~Grandia III~",
+      "downloaderArg": "https://youtube.com/watch?v=FhqVIxkiYAY"
+    },
+    {
+      "name": "Grandia III ost - Alfina's Theme",
+      "downloaderArg": "https://youtube.com/watch?v=Rl3SyIO3sv4"
+    },
+    {
+      "name": "Grandia III ost - Alfina's Sorrow",
+      "downloaderArg": "https://youtube.com/watch?v=k07XaqVvHhM"
+    },
+    {
+      "name": "Grandia III ost - Attack With Conviction!!",
+      "downloaderArg": "https://youtube.com/watch?v=FOtHK7axaOk"
+    },
+    {
+      "name": "Grandia III ost - Will the Airplane Fall and Crash On the Ground",
+      "downloaderArg": "https://youtube.com/watch?v=quBSzk6icJE"
+    },
+    {
+      "name": "Grandia III ost - Proprietress of the Inn",
+      "downloaderArg": "https://youtube.com/watch?v=sNjNhTID7cU"
+    },
+    {
+      "name": "Grandia III ost - Raflid -Crowded City-",
+      "downloaderArg": "https://youtube.com/watch?v=73J3k_2GviM"
+    },
+    {
+      "name": "Grandia III ost - What Do You Fight For",
+      "downloaderArg": "https://youtube.com/watch?v=SCQVOzjbAHo"
+    },
+    {
+      "name": "Grandia III ost - Caravans",
+      "downloaderArg": "https://youtube.com/watch?v=ouLijSrqt1o"
+    },
+    {
+      "name": "Grandia III ost - Terrarium",
+      "downloaderArg": "https://youtube.com/watch?v=Qs5wV81gkqo"
+    },
+    {
+      "name": "Grandia III ost - ZETEC",
+      "downloaderArg": "https://youtube.com/watch?v=LJ2nNxu5-mI"
+    },
+    {
+      "name": "Grandia III ost - Requiem of a Birth (Reverse)",
+      "downloaderArg": "https://youtube.com/watch?v=FhILyonXI-U"
+    },
+    {
+      "name": "Grandia III ost - ATTACK OF A FLASH -Synth-",
+      "downloaderArg": "https://youtube.com/watch?v=8xF-bhPOaW4"
+    },
+    {
+      "name": "Grandia III ost - Hey!, Was That Just Real!",
+      "downloaderArg": "https://youtube.com/watch?v=Qin4Rkj-BPo"
+    },
+    {
+      "name": "Grandia III ost - Tensions 2  Theme of Emelious 1",
+      "downloaderArg": "https://youtube.com/watch?v=Zxxx0xErnYw"
+    },
+    {
+      "name": "Grandia III ost - An Elder Brother and a Younger Sister",
+      "downloaderArg": "https://youtube.com/watch?v=h2nUk6GGS0w"
+    },
+    {
+      "name": "Grandia III ost - Surumania",
+      "downloaderArg": "https://youtube.com/watch?v=EPoL2QvLiKw"
+    },
+    {
+      "name": "Grandia III ost - E vs. D",
+      "downloaderArg": "https://youtube.com/watch?v=E9BQ8aRcEBo"
+    },
+    {
+      "name": "Grandia III ost - Decision of Moonlight",
+      "downloaderArg": "https://youtube.com/watch?v=5Mu5Y043z0w"
+    },
+    {
+      "name": "Grandia III ost - Feel the Love of Eternity..",
+      "downloaderArg": "https://youtube.com/watch?v=xPj7tULZIqQ"
+    },
+    {
+      "name": "Grandia III ost - ATTACK OF A FLASH -Orchestral-",
+      "downloaderArg": "https://youtube.com/watch?v=zil2JsduVXg"
+    },
+    {
+      "name": "Grandia III ost - SORROW",
+      "downloaderArg": "https://youtube.com/watch?v=gn3oSRQ4ntc"
+    },
+    {
+      "name": "Grandia III ost - Raflid -Defeated Hope-",
+      "downloaderArg": "https://youtube.com/watch?v=fX19yi1vJLc"
+    },
+    {
+      "name": "Grandia III ost - Theme Arrangement 2",
+      "downloaderArg": "https://youtube.com/watch?v=NKADNL2EUHQ"
+    },
+    {
+      "name": "Grandia III ost - Pilot King",
+      "downloaderArg": "https://youtube.com/watch?v=wkRjTb6TYuc"
+    },
+    {
+      "name": "Grandia III ost - Zone Revival",
+      "downloaderArg": "https://youtube.com/watch?v=HFyPnZXnroI"
+    },
+    {
+      "name": "Grandia III ost - Great Man Schmitt",
+      "downloaderArg": "https://youtube.com/watch?v=Wz9DaBlA9CE"
+    },
+    {
+      "name": "Grandia III ost - GREAT ASSIZE",
+      "downloaderArg": "https://youtube.com/watch?v=1zUED9kLS7E"
+    },
+    {
+      "name": "Grandia III ost - Theme Arrangement 3",
+      "downloaderArg": "https://youtube.com/watch?v=r-g5Ap8ZaK0"
+    },
+    {
+      "name": "Grandia III ost - Thank You..",
+      "downloaderArg": "https://youtube.com/watch?v=4wyI-Qc3bQ8"
+    },
+    {
+      "name": "Grandia III ost - Theme of GRANDIA III",
+      "downloaderArg": "https://youtube.com/watch?v=22BxmpZh-qs"
+    }
+  ]
+}
diff --git a/index.js b/index.js
index a345301..ca62f17 100644
--- a/index.js
+++ b/index.js
@@ -1,7 +1,5 @@
 // omg I am tired of code
 
-const { getPlayer } = require('./players')
-const { getDownloaderFor } = require('./downloaders')
 const { AppElement } = require('./ui')
 const { updatePlaylistFormat } = require('./playlist-utils')
 const ansi = require('./tui-lib/util/ansi')
@@ -10,6 +8,11 @@ const EventEmitter = require('events')
 const Flushable = require('./tui-lib/util/Flushable')
 const Root = require('./tui-lib/ui/Root')
 
+// Hack to get around errors when piping many things to stdout/err
+// (from general-util promisifyProcess)
+process.stdout.setMaxListeners(Infinity)
+process.stderr.setMaxListeners(Infinity)
+
 process.on('unhandledRejection', error => {
   console.error(error.stack)
   process.exit(1)
@@ -55,7 +58,7 @@ async function main() {
     ]
   }
 
-  grouplike = require('./library.json')
+  grouplike = require(process.argv[2] || './library.json')
 
   grouplike = updatePlaylistFormat(grouplike)
 
diff --git a/todo.txt b/todo.txt
index ca43148..1023eff 100644
--- a/todo.txt
+++ b/todo.txt
@@ -8,3 +8,6 @@ TODO: A "clear queue" button.
 
 TODO: A way to jump to an item with a particular name. Probably press "/".
       It'd be nice if the closest match got highlighted while you were typing.
+
+TODO: "Queue to play next"... maybe also a cursor in the queue list, which
+      would tell after what track to place newly-queued items?
diff --git a/ui.js b/ui.js
index 189aa85..1a583ab 100644
--- a/ui.js
+++ b/ui.js
@@ -18,6 +18,8 @@ class AppElement extends FocusElement {
 
     this.player = null
     this.recordStore = new RecordStore()
+    this.queueGrouplike = {isTheQueue: true, items: []}
+
 
     this.form = new Form()
     this.addChild(this.form)
@@ -32,24 +34,28 @@ class AppElement extends FocusElement {
     this.paneLeft.addChild(this.grouplikeListingElement)
     this.form.addInput(this.grouplikeListingElement, false)
 
-    this.grouplikeListingElement.on('download', item => this.downloadGrouplikeItem(item))
-    this.grouplikeListingElement.on('select', item => {
+    const handleSelectFromMain = item => {
       if (isGroup(item)) {
         this.grouplikeListingElement.loadGrouplike(item)
       } else {
         this.playGrouplikeItem(item)
       }
-    })
-    this.grouplikeListingElement.on('queue', item => this.queueGrouplikeItem(item))
+    }
 
-    this.queueGrouplike = {isTheQueue: true, items: []}
+    this.grouplikeListingElement.on('download', item => this.downloadGrouplikeItem(item))
+    this.grouplikeListingElement.on('select (enter)', item => handleSelectFromMain(item))
+    this.grouplikeListingElement.on('select (space)', item => this.handleSpacePressed(
+      () => handleSelectFromMain(item)))
+    this.grouplikeListingElement.on('queue', item => this.queueGrouplikeItem(item))
 
     this.queueListingElement = new GrouplikeListingElement(this.recordStore)
     this.queueListingElement.loadGrouplike(this.queueGrouplike)
     this.paneRight.addChild(this.queueListingElement)
     this.form.addInput(this.queueListingElement, false)
 
-    this.queueListingElement.on('select', item => this.playGrouplikeItem(item))
+    this.queueListingElement.on('select (enter)', item => this.playGrouplikeItem(item))
+    this.queueListingElement.on('select (space)', item => this.handleSpacePressed(
+      () => this.playGrouplikeItem(item)))
 
     this.playbackPane = new Pane()
     this.addChild(this.playbackPane)
@@ -105,6 +111,17 @@ class AppElement extends FocusElement {
     }
   }
 
+  handleSpacePressed(callback) {
+    // Pauses/resumes if a track is currently playing; otherwise, calls the
+    // callback function.
+
+    if (this.playingTrack) {
+      this.togglePause()
+    } else {
+      return callback()
+    }
+  }
+
   seekAhead(seconds) {
     this.player.seekAhead(seconds)
   }
@@ -192,7 +209,18 @@ class AppElement extends FocusElement {
 
     // TODO: Check if it's an item or a group
 
+    // If, by the time the track is downloaded, we're playing something
+    // different from when the download started, assume that we just want to
+    // keep listening to whatever new thing we started.
+
+    const oldTrack = this.playingTrack
+
     const downloadFile = await this.downloadGrouplikeItem(item)
+
+    if (this.playingTrack !== oldTrack) {
+      return
+    }
+
     await this.player.kill()
     this.recordStore.getRecord(item).playing = true
     this.playingTrack = item
@@ -284,7 +312,8 @@ class GrouplikeListingElement extends ListScrollForm {
       for (const item of this.grouplike.items) {
         const itemElement = new GrouplikeItemElement(item, this.recordStore)
         itemElement.on('download', () => this.emit('download', item))
-        itemElement.on('select', () => this.emit('select', item))
+        itemElement.on('select (space)', () => this.emit('select (space)', item))
+        itemElement.on('select (enter)', () => this.emit('select (enter)', item))
         itemElement.on('queue', () => this.emit('queue', item))
         this.addInput(itemElement)
       }
@@ -370,8 +399,10 @@ class GrouplikeItemElement extends Button {
       this.emit('download')
     } else if (telc.isCaselessLetter(keyBuf, 'q')) {
       this.emit('queue')
-    } else if (telc.isSelect(keyBuf)) {
-      this.emit('select')
+    } else if (telc.isSpace(keyBuf)) {
+      this.emit('select (space)')
+    } else if (telc.isEnter(keyBuf)) {
+      this.emit('select (enter)')
     }
   }
 }