« get me outta code hell

Auto-DJ - mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2020-04-06 22:03:17 -0300
committerFlorrie <towerofnix@gmail.com>2020-04-06 22:03:17 -0300
commit0890f592ecdada66e8e264d6201e43ed0c6bf7ac (patch)
treec89cb63cfd5b19d2693b89c1477da925a234dc76
parentef66a8613ddc0584a1f08696261f62c19cd7db6e (diff)
Auto-DJ
-rw-r--r--backend.js8
-rw-r--r--players.js32
-rw-r--r--todo.txt3
-rw-r--r--ui.js28
4 files changed, 66 insertions, 5 deletions
diff --git a/backend.js b/backend.js
index d3ad122..ed1bd08 100644
--- a/backend.js
+++ b/backend.js
@@ -544,6 +544,14 @@ class QueuePlayer extends EventEmitter {
     this.player.setVolume(value)
   }
 
+  setVolumeMultiplier(value) {
+    this.player.setVolumeMultiplier(value);
+  }
+
+  fadeIn() {
+    return this.player.fadeIn();
+  }
+
   setPauseNextTrack(value) {
     this.pauseNextTrack = !!value
   }
diff --git a/players.js b/players.js
index 868129d..5fe4714 100644
--- a/players.js
+++ b/players.js
@@ -19,6 +19,7 @@ class Player extends EventEmitter {
     this.isLooping = false
     this.isPaused = false
     this.volume = 100
+    this.volumeMultiplier = 1.0
   }
 
   set process(newProcess) {
@@ -41,6 +42,8 @@ class Player extends EventEmitter {
   seekBack(secs) {}
   volUp(amount) {}
   volDown(amount) {}
+  setVolume(value) {}
+  updateVolume() {}
   togglePause() {}
   toggleLoop() {}
   setPause() {}
@@ -61,6 +64,25 @@ class Player extends EventEmitter {
       this.emit('printStatusLine', data)
     }
   }
+
+  setVolumeMultiplier(value) {
+    this.volumeMultiplier = value
+    this.updateVolume()
+  }
+
+  fadeIn() {
+    const interval = 50
+    const duration = 1000
+    const delta = 1.0 - this.volumeMultiplier
+    const id = setInterval(() => {
+      this.volumeMultiplier += delta * interval / duration
+      if (this.volumeMultiplier >= 1.0) {
+        this.volumeMultiplier = 1.0
+        clearInterval(id)
+      }
+      this.updateVolume()
+    }, interval)
+  }
 }
 
 module.exports.MPVPlayer = class extends Player {
@@ -72,7 +94,7 @@ module.exports.MPVPlayer = class extends Player {
     if (this.isPaused) {
       opts.unshift('--pause')
     }
-    opts.unshift('--volume=' + this.volume)
+    opts.unshift('--volume=' + this.volume * this.volumeMultiplier)
     return opts
   }
 
@@ -112,6 +134,8 @@ module.exports.MPVPlayer = class extends Player {
 
         this.printStatusLine(getTimeStrings({curHour, curMin, curSec, lenHour, lenMin, lenSec}))
       }
+
+      this.updateVolume();
     })
 
     return new Promise(resolve => {
@@ -177,7 +201,11 @@ module.exports.ControllableMPVPlayer = class extends module.exports.MPVPlayer {
     this.volume = value
     this.volume = Math.max(0, this.volume)
     this.volume = Math.min(100, this.volume)
-    this.sendCommand('set_property', 'volume', this.volume)
+    this.updateVolume()
+  }
+
+  updateVolume() {
+    this.sendCommand('set_property', 'volume', this.volume * this.volumeMultiplier)
   }
 
   togglePause() {
diff --git a/todo.txt b/todo.txt
index e039cc8..35ac635 100644
--- a/todo.txt
+++ b/todo.txt
@@ -487,3 +487,6 @@ TODO: Figure out looping not always working consistently. I've tried to deal
       with this before, but it's been broken since switching to socat. Maybe we
       aren't receiving time data as consistently, or aren't re-applying loop
       when we're supposed to?
+
+TODO: Show how many tracks remain in a queue player's queue, ala "+1" floated
+      to the right, behind the playback position/duration indicator.
diff --git a/ui.js b/ui.js
index f9f066e..f432ebe 100644
--- a/ui.js
+++ b/ui.js
@@ -7,8 +7,10 @@ const processSmartPlaylist = require('./smart-playlist')
 const UndoManager = require('./undo-manager')
 
 const {
-  shuffleArray,
-  getTimeStringsFromSec
+  commandExists,
+  getTimeStringsFromSec,
+  promisifyProcess,
+  shuffleArray
 } = require('./general-util')
 
 const {
@@ -54,6 +56,7 @@ const {
 const TuiTextEditor = require('tui-text-editor')
 
 const { promisify } = require('util')
+const { spawn } = require('child_process')
 const fs = require('fs')
 const open = require('open')
 const path = require('path')
@@ -181,6 +184,7 @@ class AppElement extends FocusElement {
     this.backend = backend
     this.telnetServer = null
     this.isPartyHost = false
+    this.enableAutoDJ = false
 
     this.config = Object.assign({
       canControlPlayback: true,
@@ -330,6 +334,7 @@ class AppElement extends FocusElement {
           playingTrack && {element: this.playingControl},
           {element: this.loopingControl},
           {element: this.pauseNextControl},
+          {element: this.autoDJControl},
           {element: this.volumeSlider},
           {divider: true},
           previous && {label: `Previous (${previous.name})`, action: () => this.SQP.playPrevious(playingTrack)},
@@ -387,6 +392,12 @@ class AppElement extends FocusElement {
       getEnabled: () => this.config.canControlPlayback
     })
 
+    this.autoDJControl = new ToggleControl('Enable Auto-DJ?', {
+      setValue: val => (this.enableAutoDJ = val),
+      getValue: val => this.enableAutoDJ,
+      getEnabled: () => this.config.canControlPlayback
+    })
+
     this.bindListeners()
     this.initialAttachListeners()
 
@@ -491,7 +502,7 @@ class AppElement extends FocusElement {
     this.removeQueuePlayerListenersAndUI(queuePlayer)
   }
 
-  handlePlaying(track, oldTrack, queuePlayer) {
+  async handlePlaying(track, oldTrack, queuePlayer) {
     const PIE = this.getPlaybackInfoElementForQueuePlayer(queuePlayer)
     if (PIE) {
       PIE.updateTrack()
@@ -503,6 +514,17 @@ class AppElement extends FocusElement {
         this.queueListingElement.selectAndShow(track)
       }
     }
+
+    if (track && this.enableAutoDJ) {
+      queuePlayer.setVolumeMultiplier(0.5);
+      const message = 'now playing: ' + getNameWithoutTrackNumber(track);
+      if (await commandExists('espeak')) {
+        await promisifyProcess(spawn('espeak', [message]));
+      } else if (await commandExists('say')) {
+        await promisifyProcess(spawn('espeak', [message]));
+      }
+      queuePlayer.fadeIn();
+    }
   }
 
   handleReceivedTimeData(data, queuePlayer) {