From b1184c312d3963de5b324777f4a743be057535f1 Mon Sep 17 00:00:00 2001 From: liam4 Date: Sun, 11 Jun 2017 10:52:29 -0300 Subject: Loop-play.js cleanup --- src/loop-play.js | 115 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/loop-play.js b/src/loop-play.js index ff77940..100c14b 100644 --- a/src/loop-play.js +++ b/src/loop-play.js @@ -1,29 +1,20 @@ 'use strict' -const fs = require('fs') -const tempy = require('tempy') - const { spawn } = require('child_process') -const { promisify } = require('util') -const fetch = require('node-fetch') -const path = require('path') const promisifyProcess = require('./promisify-process') const sanitize = require('sanitize-filename') +const tempy = require('tempy') -const writeFile = promisify(fs.writeFile) - -module.exports = 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 - // from one song to the next. Stops when the result of the pick - // function is null (or similar). Optionally takes a second argument - // used as arguments to the `play` process (before the file name). +class DownloadController { + constructor(picker, downloader) { + this.process = null - let playProcess, convertProcess + this.picker = picker + this.downloader = downloader + } - async function downloadNext() { - const picked = picker() + async downloadNext() { + const picked = this.picker() if (picked == null) { return false @@ -32,34 +23,56 @@ module.exports = function loopPlay(picker, downloader, playArgs = []) { const [ title, downloaderArg ] = picked console.log(`Downloading ${title}..\nDownloader arg: ${downloaderArg}`) - const downloadFile = await downloader(downloaderArg) + const from = await this.downloader(downloaderArg) const tempDir = tempy.directory() - const wavFile = tempDir + `/.${sanitize(title)}.wav` + const to = tempDir + `/.${sanitize(title)}.wav` + + // We pass false to promisifyProcess to show we want hte output of avconv + // to be silenced. + const convertProcess = spawn('avconv', ['-y', '-i', from, to]) + const convertPromise = promisifyProcess(convertProcess, false) + + this.wavFile = to + this.process = convertProcess try { - const convertPromise = convert(downloadFile, wavFile) - convertProcess = convertPromise.process await convertPromise } catch(err) { console.warn("Failed to convert " + title) console.warn("Selecting a new track\n") - return await downloadNext() + this.killProcess() + + return await this.downloadNext() } + } - return wavFile + killProcess() { + if (this.process) { + this.process.kill() + } } +} - async function main() { - let wavFile = await downloadNext() +class PlayController { + constructor(downloadController) { + this.playArgs = [] + this.process = null + + this.downloadController = downloadController + } - while (wavFile) { - const nextPromise = downloadNext() + async loopPlay() { + await this.downloadController.downloadNext() - // What a mouthful! - const playPromise = playFile(wavFile, playArgs) - playProcess = playPromise.process + while (this.downloadController.wavFile) { + const nextPromise = this.downloadController.downloadNext() + + const file = this.downloadController.wavFile + const playProcess = spawn('play', [...this.playArgs, file]) + const playPromise = promisifyProcess(playProcess) + this.process = playProcess try { await playPromise @@ -67,32 +80,42 @@ module.exports = function loopPlay(picker, downloader, playArgs = []) { console.warn(err) } - wavFile = await nextPromise + await nextPromise } } - const promise = main() + killProcess() { + if (this.process) { + this.process.kill() + } + } +} + +module.exports = 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 + // from one song to the next. Stops when the result of the pick + // function is null (or similar). Optionally takes a second argument + // used as arguments to the `play` process (before the file name). + + const downloadController = new DownloadController(picker, downloader) + + const playController = new PlayController(downloadController) + playController.playArgs = playArgs + + const promise = playController.loopPlay() return { promise, skip: function() { - if (playProcess) playProcess.kill() + playController.killProcess() }, kill: function() { - if (playProcess) playProcess.kill() - if (convertProcess) convertProcess.kill() + playController.killProcess() + downloadController.killProcess() } } } - -function convert(fromFile, toFile) { - const avconv = spawn('avconv', ['-y', '-i', fromFile, toFile]) - return promisifyProcess(avconv, false) -} - -function playFile(file, opts = []) { - const play = spawn('play', [...opts, file]) - return Object.assign(promisifyProcess(play), {process: play}) -} -- cgit 1.3.0-6-gf8a5