From 26dc1e82fd797fdc0f55bc48476d581793a2a23d Mon Sep 17 00:00:00 2001 From: DC Date: Sun, 15 Mar 2015 23:02:04 -0700 Subject: [PATCH] Airplay support. Nicer looking cast screen --- renderer/index.css | 27 +++++++------- renderer/lib/cast.js | 77 +++++++++++++++++++++++----------------- renderer/views/player.js | 33 ++++++++--------- 3 files changed, 73 insertions(+), 64 deletions(-) diff --git a/renderer/index.css b/renderer/index.css index d70568da..38552636 100644 --- a/renderer/index.css +++ b/renderer/index.css @@ -356,6 +356,8 @@ input { width: 100%; height: 100%; display: flex; + background-size: cover; + background-position: center center; } .player video { @@ -701,28 +703,27 @@ body.drag .torrent-placeholder span { /* * CHROMECAST / AIRPLAY CONTROLS */ + .cast-screen { - width: 400px; - margin: auto; + width: 100%; + height: 200px; color: #eee; - line-height: normal; + text-align: center; + line-height: 2; + align-self: center; } -.cast-screen h1 { - font-size: 3em; +.cast-screen .icon { + font-size: 50px; } +.cast-screen .cast-type, .cast-screen .cast-status { - margin: 40px 0; - font-size: 2em; + font-size: 32px; } -.cast-screen .stop-casting { - cursor: pointer; -} - -.cast-screen .stop-casting:hover { - color: #9af; +.cast-screen .cast-type { + font-weight: bold; } /* diff --git a/renderer/lib/cast.js b/renderer/lib/cast.js index ccb213cf..4a1384b9 100644 --- a/renderer/lib/cast.js +++ b/renderer/lib/cast.js @@ -32,7 +32,10 @@ function init (callback) { addChromecastEvents() }) - airplay.createBrowser().on('deviceOn', function (player) { + var browser = airplay.createBrowser() + var devices = browser.getDevices(true) + console.log('TODO GET DEVICES RET %o', devices) + browser.on('deviceOn', function (player) { state.devices.airplay = player addAirplayEvents() }).start() @@ -47,27 +50,26 @@ function addChromecastEvents () { state.playing.location = 'local' update() }) - state.devices.chromecast.on('status', handleStatus) } function addAirplayEvents () {} // Update our state from the remote TV function pollCastStatus (state) { - var device - if (state.playing.location === 'chromecast') device = state.devices.chromecast - else if (state.playing.location === 'airplay') device = state.devices.airplay - else return - - device.status(function (err, status) { - if (err) return console.log('Error getting %s status: %o', state.playing.location, err) - handleStatus(status) - }) -} - -function handleStatus (status) { - state.video.isCastPaused = status.playerState === 'PAUSED' - state.video.currentTime = status.currentTime + 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) + state.video.isPaused = status.playerState === 'PAUSED' + state.video.currentTime = status.currentTime + update() + }) + } else if (state.playing.location === 'airplay') { + state.devices.airplay.status(function (status) { + state.video.isPaused = status.rate === 0 + state.video.currentTime = status.position + update() + }) + } } function openChromecast () { @@ -93,9 +95,16 @@ function openAirplay () { } state.playing.location = 'airplay-pending' - state.devices.airplay.play(state.server.networkURL, 0, function () { - console.log('Airplay', arguments) // TODO: handle airplay errors - state.playing.location = 'airplay' + state.devices.airplay.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() }) update() @@ -106,7 +115,7 @@ function stopCasting () { if (state.playing.location === 'chromecast') { state.devices.chromecast.stop(stoppedCasting) } else if (state.playing.location === 'airplay') { - throw new Error('Unimplemented') // TODO stop airplay + state.devices.airplay.stop(stoppedCasting) } else if (state.playing.location.endsWith('-pending')) { // Connecting to Chromecast took too long or errored out. Let the user cancel stoppedCasting() @@ -127,22 +136,26 @@ function isCasting () { } function playPause () { - var device = getActiveDevice() - if (!state.video.isPaused) device.pause(castCallback) - else device.play(null, null, castCallback) + var device + if (state.playing.location === 'chromecast') { + device = state.devices.chromecast + if (!state.video.isPaused) device.pause(castCallback) + else device.play(null, null, castCallback) + } else if (state.playing.location === 'airplay') { + device = state.devices.airplay + if (!state.video.isPaused) device.rate(0, castCallback) + else device.rate(1, castCallback) + } } function seek (time) { - var device = getActiveDevice() - device.seek(time, castCallback) -} - -function getActiveDevice () { - if (state.playing.location === 'chromecast') return state.devices.chromecast - else if (state.playing.location === 'airplay') return state.devices.airplay - else throw new Error('getActiveDevice() called, but we\'re not casting') + if (state.playing.location === 'chromecast') { + state.devices.chromecast.seek(time, castCallback) + } else if (state.playing.location === 'airplay') { + state.devices.airplay.scrub(time, castCallback) + } } function castCallback () { - console.log('Cast callback: %o', arguments) + console.log(state.playing.location + ' callback: %o', arguments) } diff --git a/renderer/views/player.js b/renderer/views/player.js index aafb81d7..df4e7e8f 100644 --- a/renderer/views/player.js +++ b/renderer/views/player.js @@ -76,28 +76,23 @@ function renderCastScreen (state, dispatch) { var isStarting = state.playing.location.endsWith('-pending') if (!isChromecast && !isAirplay) throw new Error('Unimplemented cast type') - // Finally, show a static title screen and the cast status - var header = isChromecast ? 'Chromecast' : 'AirPlay' - var content - if (isStarting) { - content = hx` -
Connecting...
- ` - } else { - content = hx` -
-
dispatch('stopCasting')}> - Stop Casting -
-
- ` + // Show a nice title image, if possible + var style = {} + var infoHash = state.playing.infoHash + var torrentSummary = state.saved.torrents.find((x) => x.infoHash === infoHash) + if (torrentSummary && torrentSummary.posterURL) { + var cleanURL = torrentSummary.posterURL.replace(/\\/g, '/') + style.backgroundImage = `radial-gradient(circle at center, rgba(0,0,0,0.4) 0%,rgba(0,0,0,1) 100%), url(${cleanURL})` } + + // Show whether we're connected to Chromecast / Airplay + var castStatus = isStarting ? 'Connecting...' : 'Connected' return hx` -
+
-

${header}

- ${content} + ${isAirplay ? 'airplay' : 'cast'} +
${isAirplay ? 'AirPlay' : 'Chromecast'}
+
${castStatus}
`