refactor cast module

* refactor cast module

* fix standard

* remove debug dependency
This commit is contained in:
grunjol
2016-04-04 05:22:02 -03:00
committed by DC
parent 5d5a32858d
commit 4ee8a883bf
2 changed files with 167 additions and 96 deletions

View File

@@ -242,10 +242,10 @@ function dispatch (action, ...args) {
openTorrentContextMenu(args[0] /* infoHash */) openTorrentContextMenu(args[0] /* infoHash */)
} }
if (action === 'openChromecast') { if (action === 'openChromecast') {
lazyLoadCast().openChromecast() lazyLoadCast().open('chromecast')
} }
if (action === 'openAirplay') { if (action === 'openAirplay') {
lazyLoadCast().openAirplay() lazyLoadCast().open('airplay')
} }
if (action === 'stopCasting') { if (action === 'stopCasting') {
lazyLoadCast().stopCasting() lazyLoadCast().stopCasting()

View File

@@ -9,8 +9,7 @@ var state = require('../state')
// * Starts and stops casting, provides remote video controls // * Starts and stops casting, provides remote video controls
module.exports = { module.exports = {
init, init,
openChromecast, open,
openAirplay,
stopCasting, stopCasting,
playPause, playPause,
seek, seek,
@@ -21,50 +20,102 @@ module.exports = {
// Callback to notify module users when state has changed // Callback to notify module users when state has changed
var update var update
function init (callback) { // chromecast player implementation
update = callback function chromecastPlayer (player) {
function addEvents () {
player.on('error', function (err) {
player.errorMessage = err.message
update()
})
player.on('disconnect', function () {
state.playing.location = 'local'
update()
})
}
// Start polling Chromecast or Airplay, whenever we're connected function open () {
setInterval(() => pollCastStatus(state), 1000) var torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash)
player.play(state.server.networkURL, {
type: 'video/mp4',
title: config.APP_NAME + ' — ' + torrentSummary.name
}, function (err) {
if (err) {
state.playing.location = 'local'
} else {
state.playing.location = 'chromecast'
}
update()
})
}
// Listen for devices: Chromecast and Airplay function playPause (callback) {
chromecasts.on('update', function (player) { if (!state.playing.isPaused) player.pause(callback)
state.devices.chromecast = player else player.play(null, null, callback)
addChromecastEvents() }
})
var browser = airplay.createBrowser() function stop (callback) {
browser.on('deviceOn', function (player) { player.stop(callback)
state.devices.airplay = player }
addAirplayEvents()
}).start()
}
function addChromecastEvents () { function status (state) {
state.devices.chromecast.on('error', function (err) { player.status(function (err, status) {
state.devices.chromecast.errorMessage = err.message
update()
})
state.devices.chromecast.on('disconnect', function () {
state.playing.location = 'local'
update()
})
}
function addAirplayEvents () {}
// Update our state from the remote TV
function pollCastStatus (state) {
if (state.playing.location === 'chromecast') {
state.devices.chromecast.status(function (err, status) {
if (err) return console.log('error getting %s status: %o', state.playing.location, err) if (err) return console.log('error getting %s status: %o', state.playing.location, err)
state.playing.isPaused = status.playerState === 'PAUSED' state.playing.isPaused = status.playerState === 'PAUSED'
state.playing.currentTime = status.currentTime state.playing.currentTime = status.currentTime
state.playing.volume = status.volume.muted ? 0 : status.volume.level state.playing.volume = status.volume.muted ? 0 : status.volume.level
update() update()
}) })
} else if (state.playing.location === 'airplay') { }
state.devices.airplay.status(function (status) {
function seek (time, callback) {
player.seek(time, callback)
}
function volume (volume, callback) {
player.volume(volume, callback)
}
addEvents()
return {
player: player,
open: open,
playPause: playPause,
stop: stop,
status: status,
seek: seek,
volume: volume
}
}
// airplay player implementation
function airplayPlayer (player) {
function open () {
player.play(state.server.networkURL, 0, function (res) {
if (res.statusCode !== 200) {
state.playing.location = 'local'
state.errors.push({
time: new Date().getTime(),
message: 'Couldn\'t connect to Airplay'
})
} else {
state.playing.location = 'airplay'
}
update()
})
}
function playPause (callback) {
if (!state.playing.isPaused) player.rate(0, callback)
else player.rate(1, callback)
}
function stop (callback) {
player.stop(callback)
}
function status (state) {
player.status(function (status) {
state.playing.isPaused = status.rate === 0 state.playing.isPaused = status.rate === 0
state.playing.currentTime = status.position state.playing.currentTime = status.position
// TODO: get airplay volume, implementation needed. meanwhile set value in setVolume // TODO: get airplay volume, implementation needed. meanwhile set value in setVolume
@@ -73,54 +124,75 @@ function pollCastStatus (state) {
update() update()
}) })
} }
}
function openChromecast () { function seek (time, callback) {
if (state.playing.location !== 'local') { player.scrub(time, callback)
throw new Error('You can\'t connect to Chromecast when already connected to another device')
} }
state.playing.location = 'chromecast-pending' function volume (volume, callback) {
var torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash) // TODO remove line below once we can fetch the information in status update
state.devices.chromecast.play(state.server.networkURL, { state.playing.volume = volume
type: 'video/mp4', volume = (volume - 1) * 30
title: config.APP_NAME + ' — ' + torrentSummary.name player.volume(volume, callback)
}, function (err) {
state.playing.location = err ? 'local' : 'chromecast'
update()
})
update()
}
function openAirplay () {
if (state.playing.location !== 'local') {
throw new Error('You can\'t connect to Airplay when already connected to another device')
} }
state.playing.location = 'airplay-pending' return {
state.devices.airplay.play(state.server.networkURL, 0, function (res) { player: player,
if (res.statusCode !== 200) { open: open,
state.playing.location = 'local' playPause: playPause,
state.errors.push({ stop: stop,
time: new Date().getTime(), status: status,
message: 'Couldn\'t connect to Airplay' seek: seek,
}) volume: volume
} else { }
state.playing.location = 'airplay' }
}
update() // start export functions
function init (callback) {
update = callback
// Start polling Chromecast or Airplay, whenever we're connected
setInterval(() => pollCastStatus(state), 1000)
// Listen for devices: Chromecast and Airplay
chromecasts.on('update', function (player) {
state.devices.chromecast = chromecastPlayer(player)
}) })
var browser = airplay.createBrowser()
browser.on('deviceOn', function (player) {
state.devices.airplay = airplayPlayer(player)
}).start()
}
// Update our state from the remote TV
function pollCastStatus (state) {
var device = getDevice()
if (device) {
device.status(state)
}
}
function open (location) {
if (state.playing.location !== 'local') {
throw new Error('You can\'t connect to ' + location + ' when already connected to another device')
}
state.playing.location = location + '-pending'
var device = getDevice(location)
if (device) {
getDevice(location).open()
}
update() update()
} }
// Stops Chromecast or Airplay, move video back to local screen // Stops Chromecast or Airplay, move video back to local screen
function stopCasting () { function stopCasting () {
if (state.playing.location === 'chromecast') { var device = getDevice()
state.devices.chromecast.stop(stoppedCasting) if (device) {
} else if (state.playing.location === 'airplay') { device.stop(stoppedCasting)
state.devices.airplay.stop(stoppedCasting) } else {
} else if (state.playing.location.endsWith('-pending')) {
// Connecting to Chromecast took too long or errored out. Let the user cancel
stoppedCasting() stoppedCasting()
} }
} }
@@ -138,38 +210,37 @@ function isCasting () {
return state.playing.location === 'chromecast' || state.playing.location === 'airplay' return state.playing.location === 'chromecast' || state.playing.location === 'airplay'
} }
function playPause () { function getDevice (location) {
var device if (location && state.devices[location]) {
if (state.playing.location === 'chromecast') { return state.devices[location]
device = state.devices.chromecast } else if (state.playing.location === 'chromecast') {
if (!state.playing.isPaused) device.pause(castCallback) return state.devices.chromecast
else device.play(null, null, castCallback)
} else if (state.playing.location === 'airplay') { } else if (state.playing.location === 'airplay') {
device = state.devices.airplay return state.devices.airplay
if (!state.playing.isPaused) device.rate(0, castCallback) }
else device.rate(1, castCallback) }
function playPause () {
var device = getDevice()
if (device) {
device.playPause(castCallback)
} }
} }
function seek (time) { function seek (time) {
if (state.playing.location === 'chromecast') { var device = getDevice()
state.devices.chromecast.seek(time, castCallback) if (device) {
} else if (state.playing.location === 'airplay') { device.seek(time, castCallback)
state.devices.airplay.scrub(time, castCallback)
} }
} }
function setVolume (volume) { function setVolume (volume) {
if (state.playing.location === 'chromecast') { var device = getDevice()
state.devices.chromecast.volume(volume, castCallback) if (device) {
} else if (state.playing.location === 'airplay') { device.volume(volume, castCallback)
// TODO remove line below once we can fetch the information in status update
state.playing.volume = volume
volume = (volume - 1) * 30
state.devices.airplay.volume(volume, castCallback)
} }
} }
function castCallback () { function castCallback () {
console.log(state.playing.location + ' callback: %o', arguments) console.log('%s callback: %o', state.playing.location, arguments)
} }