Play unsupported files in VLC

This commit is contained in:
DC
2016-04-19 01:02:47 -07:00
parent 0a005eb054
commit bde5dc14c3
6 changed files with 183 additions and 19 deletions

View File

@@ -987,3 +987,7 @@ body.drag .app::after {
.error-popover .error:last-child {
border-bottom: none;
}
.error-text {
color: #c44;
}

View File

@@ -251,6 +251,8 @@ function dispatch (action, ...args) {
setDimensions(args[0] /* dimensions */)
}
if (action === 'backToList') {
// Exit any modals and screens with a back button
state.modal = null
while (state.location.hasBack()) state.location.back()
// Work around virtual-dom issue: it doesn't expose its redraw function,
@@ -302,20 +304,38 @@ function dispatch (action, ...args) {
state.playing.isStalled = true
}
if (action === 'mediaError') {
state.location.back(function () {
onError(new Error('Unsupported file format'))
})
if (state.location.current().url === 'player') {
state.playing.location = 'error'
ipcRenderer.send('vlcVersion')
ipcRenderer.once('vlcVersion', function (e, version) {
console.log('vlcVersion', version)
state.modal = {
id: 'unsupported-media-modal',
error: args[0],
vlcInstalled: !!version
}
})
}
}
if (action === 'mediaTimeUpdate') {
state.playing.lastTimeUpdate = new Date().getTime()
state.playing.isStalled = false
}
if (action === 'toggleFullScreen') {
ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */)
}
if (action === 'mediaMouseMoved') {
state.playing.mouseStationarySince = new Date().getTime()
}
if (action === 'vlcPlay') {
ipcRenderer.send('vlcPlay', state.server.localURL)
state.playing.location = 'vlc'
}
if (action === 'vlcNotFound') {
if (state.modal && state.modal.id === 'unsupported-media-modal') {
state.modal.vlcNotFound = true
}
}
if (action === 'toggleFullScreen') {
ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */)
}
if (action === 'exitModal') {
state.modal = null
}
@@ -624,6 +644,7 @@ function startTorrentingSummary (torrentSummary) {
torrentID = s.magnetURI || s.infoHash
}
console.log('start torrenting %s %s', s.torrentKey, torrentID)
ipcRenderer.send('wt-start-torrenting', s.torrentKey, torrentID, path, s.fileModtimes)
}
@@ -908,6 +929,9 @@ function closePlayer (cb) {
if (isCasting()) {
Cast.close()
}
if (state.playing.location === 'vlc') {
ipcRenderer.send('vlcQuit')
}
state.window.title = config.APP_WINDOW_TITLE
state.playing = State.getDefaultPlayState()
state.server = null

View File

@@ -12,7 +12,8 @@ var Views = {
}
var Modals = {
'open-torrent-address-modal': require('./open-torrent-address-modal'),
'update-available-modal': require('./update-available-modal')
'update-available-modal': require('./update-available-modal'),
'unsupported-media-modal': require('./unsupported-media-modal')
}
function App (state) {

View File

@@ -89,7 +89,8 @@ function renderMedia (state) {
onstalling=${dispatcher('mediaStalled')}
onerror=${dispatcher('mediaError')}
ontimeupdate=${dispatcher('mediaTimeUpdate')}
autoplay>
onencrypted=${dispatcher('mediaEncrypted')}
oncanplay=${onCanPlay}>
${trackTags}
</div>
`
@@ -120,6 +121,16 @@ function renderMedia (state) {
function onEnded (e) {
state.playing.isPaused = true
}
function onCanPlay (e) {
var video = e.target
if (video.webkitVideoDecodedByteCount > 0 &&
video.webkitAudioDecodedByteCount === 0) {
dispatch('mediaError', 'Audio codec unsupported')
} else {
video.play()
}
}
}
function renderOverlay (state) {
@@ -207,20 +218,33 @@ function renderLoadingSpinner (state) {
}
function renderCastScreen (state) {
var castIcon, castType
var castIcon, castType, isCast
if (state.playing.location.startsWith('chromecast')) {
castIcon = 'cast_connected'
castType = 'Chromecast'
isCast = true
} else if (state.playing.location.startsWith('airplay')) {
castIcon = 'airplay'
castType = 'AirPlay'
isCast = true
} else if (state.playing.location.startsWith('dlna')) {
castIcon = 'tv'
castType = 'DLNA'
isCast = true
} else if (state.playing.location === 'vlc') {
castIcon = 'tv'
castType = 'VLC'
isCast = false
} else if (state.playing.location === 'error') {
castIcon = 'error_outline'
castType = 'Error'
isCast = false
}
var isStarting = state.playing.location.endsWith('-pending')
var castStatus = isStarting ? 'Connecting...' : 'Connected'
var castStatus
if (isCast) castStatus = isStarting ? 'Connecting...' : 'Connected'
else castStatus = ''
// Show a nice title image, if possible
var style = {
@@ -240,15 +264,26 @@ function renderCastScreen (state) {
function renderSubtitlesOptions (state) {
var subtitles = state.playing.subtitles
if (subtitles.tracks.length && subtitles.show) {
return hx`<ul.subtitles-list>
${subtitles.tracks.map(function (w, i) {
return hx`<li onclick=${dispatcher('selectSubtitle', w.label)}><i.icon>${w.selected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>${w.label}</li>`
})}
<li onclick=${dispatcher('selectSubtitle', '')}><i.icon>${!subtitles.enabled ? 'radio_button_checked' : 'radio_button_unchecked'}</i>None</li>
</ul>
if (!subtitles.tracks.length || !subtitles.show) return
var items = subtitles.tracks.map(function (track) {
return hx`
<li onclick=${dispatcher('selectSubtitle', track.label)}>
<i.icon>${track.selected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
${track.label}
</li>
`
}
})
return hx`
<ul.subtitles-list>
${items}
<li onclick=${dispatcher('selectSubtitle', '')}>
<i.icon>${!subtitles.enabled ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
None
</li>
</ul>
`
}
function renderPlayerControls (state) {

View File

@@ -0,0 +1,42 @@
module.exports = UnsupportedMediaModal
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var electron = require('electron')
var {dispatch, dispatcher} = require('../lib/dispatcher')
function UnsupportedMediaModal (state) {
var err = state.modal.error
var message = (err && err.getMessage)
? err.getMessage()
: err
var actionButton = state.modal.vlcInstalled
? hx`<button class="button-raised" onclick=${onPlay}>Play in VLC</button>`
: hx`<button class="button-raised" onclick=${onInstall}>Install VLC</button>`
var vlcMessage = state.modal.vlcNotFound
? 'Couldn\'t run VLC. Please make sure it\'s installed.'
: ''
return hx`
<div>
<p><strong>Sorry, we can't play that file.</strong></p>
<p>${message}</p>
<p class='float-right'>
<button class="button-flat" onclick=${dispatcher('backToList')}>Cancel</button>
${actionButton}
</p>
<p class='error-text'>${vlcMessage}</p>
</div>
`
function onInstall () {
electron.shell.openExternal('http://www.videolan.org/vlc/')
state.modal.vlcInstalled = true // Assume they'll install it successfully
}
function onPlay () {
dispatch('vlcPlay')
}
}