Compare commits
1 Commits
feross-tes
...
dc/vlc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
229143ffb2 |
@@ -36,6 +36,8 @@
|
|||||||
"srt-to-vtt": "^1.1.1",
|
"srt-to-vtt": "^1.1.1",
|
||||||
"upload-element": "^1.0.1",
|
"upload-element": "^1.0.1",
|
||||||
"virtual-dom": "^2.1.1",
|
"virtual-dom": "^2.1.1",
|
||||||
|
"wcjs-player": "^0.5.7",
|
||||||
|
"webchimera.js": "^0.2.3",
|
||||||
"webtorrent": "0.x",
|
"webtorrent": "0.x",
|
||||||
"winreg": "^1.1.1"
|
"winreg": "^1.1.1"
|
||||||
},
|
},
|
||||||
@@ -74,5 +76,9 @@
|
|||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"test": "standard",
|
"test": "standard",
|
||||||
"update-authors": "./bin/update-authors.sh"
|
"update-authors": "./bin/update-authors.sh"
|
||||||
|
},
|
||||||
|
"cmake-js": {
|
||||||
|
"runtime": "electron",
|
||||||
|
"runtimeVersion": "0.37.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -674,9 +674,11 @@ body.drag .app::after {
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player video {
|
.player .video-player {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ function dispatcher (...args) {
|
|||||||
var handler = _dispatchers[json]
|
var handler = _dispatchers[json]
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
handler = _dispatchers[json] = (e) => {
|
handler = _dispatchers[json] = (e) => {
|
||||||
// Don't click on whatever is below the button
|
if (e && e.stopPropagation && e.currentTarget) {
|
||||||
e.stopPropagation()
|
// Don't click on whatever is below the button
|
||||||
// Don't regisiter clicks on disabled buttons
|
e.stopPropagation()
|
||||||
if (e.currentTarget.classList.contains('disabled')) return
|
// Don't register clicks on disabled buttons
|
||||||
|
if (e.currentTarget.classList.contains('disabled')) return
|
||||||
|
}
|
||||||
_dispatch.apply(null, args)
|
_dispatch.apply(null, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ var h = require('virtual-dom/h')
|
|||||||
var hyperx = require('hyperx')
|
var hyperx = require('hyperx')
|
||||||
var hx = hyperx(h)
|
var hx = hyperx(h)
|
||||||
|
|
||||||
|
var WebChimeraPlayer = require('wcjs-player')
|
||||||
var prettyBytes = require('prettier-bytes')
|
var prettyBytes = require('prettier-bytes')
|
||||||
var Bitfield = require('bitfield')
|
var Bitfield = require('bitfield')
|
||||||
|
|
||||||
@@ -27,7 +28,14 @@ function Player (state) {
|
|||||||
|
|
||||||
function renderMedia (state) {
|
function renderMedia (state) {
|
||||||
if (!state.server) return
|
if (!state.server) return
|
||||||
|
if (false) return renderMediaTag(state)
|
||||||
|
else return renderMediaVLC(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders using a <video> or <audio> tag
|
||||||
|
// Handles only a subset of codecs, but it's cleaner and more efficient
|
||||||
|
// See renderMediaVLC()
|
||||||
|
function renderMediaTag (state) {
|
||||||
// Unfortunately, play/pause can't be done just by modifying HTML.
|
// Unfortunately, play/pause can't be done just by modifying HTML.
|
||||||
// Instead, grab the DOM node and play/pause it if necessary
|
// Instead, grab the DOM node and play/pause it if necessary
|
||||||
var mediaElement = document.querySelector(state.playing.type) /* get the <video> or <audio> tag */
|
var mediaElement = document.querySelector(state.playing.type) /* get the <video> or <audio> tag */
|
||||||
@@ -65,7 +73,6 @@ function renderMedia (state) {
|
|||||||
|
|
||||||
// Add subtitles to the <video> tag
|
// Add subtitles to the <video> tag
|
||||||
var trackTags = []
|
var trackTags = []
|
||||||
|
|
||||||
if (state.playing.subtitles.enabled && state.playing.subtitles.tracks.length > 0) {
|
if (state.playing.subtitles.enabled && state.playing.subtitles.tracks.length > 0) {
|
||||||
for (var i = 0; i < state.playing.subtitles.tracks.length; i++) {
|
for (var i = 0; i < state.playing.subtitles.tracks.length; i++) {
|
||||||
var track = state.playing.subtitles.tracks[i]
|
var track = state.playing.subtitles.tracks[i]
|
||||||
@@ -122,6 +129,102 @@ function renderMedia (state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders using WebChimera.js to render using VLC
|
||||||
|
// That lets us play media that the <video> tag can't play
|
||||||
|
function renderMediaVLC (state) {
|
||||||
|
// Unfortunately, WebChimera can't be done just by modifying HTML.
|
||||||
|
// Instead, grab the DOM node
|
||||||
|
if (document.querySelector('#media-player')) {
|
||||||
|
if (!state.playing.chimera) {
|
||||||
|
state.playing.chimera = new WebChimeraPlayer('#media-player')
|
||||||
|
.addPlayer({
|
||||||
|
autoplay: true,
|
||||||
|
vlcArgs: ['-vvv'],
|
||||||
|
wcjsRendererOptions: {'fallbackRenderer': true}
|
||||||
|
})
|
||||||
|
.onPlaying(dispatcher('mediaPlaying'))
|
||||||
|
.onPaused(dispatcher('mediaPaused'))
|
||||||
|
.onBuffering(dispatcher('mediaStalled'))
|
||||||
|
.onTime(dispatcher('mediaTimeUpdate'))
|
||||||
|
.onEnded(onEnded)
|
||||||
|
.onFrameSetup(onLoadedMetadata)
|
||||||
|
.addPlaylist(state.server.localURL)
|
||||||
|
state.playing.chimera.ui(false)
|
||||||
|
} else {
|
||||||
|
var player = state.playing.chimera
|
||||||
|
if (state.playing.isPaused && player.playing()) {
|
||||||
|
player.pause()
|
||||||
|
} else if (!state.playing.isPaused && !player.playing()) {
|
||||||
|
player.play()
|
||||||
|
}
|
||||||
|
// When the user clicks or drags on the progress bar, jump to that position
|
||||||
|
if (state.playing.jumpToTime) {
|
||||||
|
player.time(state.playing.jumpToTime * 1000) // WebChimera expects milliseconds
|
||||||
|
state.playing.jumpToTime = null
|
||||||
|
}
|
||||||
|
// Set volume
|
||||||
|
if (state.playing.setVolume !== null && isFinite(state.playing.setVolume)) {
|
||||||
|
player.volume(Math.round(state.playing.setVolume * 100)) // WebChimera expects integer percent
|
||||||
|
state.playing.setVolume = null
|
||||||
|
}
|
||||||
|
|
||||||
|
state.playing.currentTime = player.time() / 1000
|
||||||
|
state.playing.duration = player.length() / 1000
|
||||||
|
state.playing.volume = player.volume() / 100
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.playing.chimera = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add subtitles to the <video> tag
|
||||||
|
var trackTags = []
|
||||||
|
if (state.playing.subtitles.enabled && state.playing.subtitles.tracks.length > 0) {
|
||||||
|
for (var i = 0; i < state.playing.subtitles.tracks.length; i++) {
|
||||||
|
var track = state.playing.subtitles.tracks[i]
|
||||||
|
trackTags.push(hx`
|
||||||
|
<track
|
||||||
|
default=${track.selected ? 'default' : ''}
|
||||||
|
label=${track.language}
|
||||||
|
type='subtitles'
|
||||||
|
src=${track.buffer}>
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the <audio> or <video> tag
|
||||||
|
var mediaType = state.playing.type /* 'video' or 'audio' */
|
||||||
|
var mediaTag = hx`
|
||||||
|
<div id='media-player' class='${mediaType}-player'>
|
||||||
|
${trackTags}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
// Show the media.
|
||||||
|
return hx`
|
||||||
|
<div
|
||||||
|
class='letterbox'
|
||||||
|
onmousemove=${dispatcher('mediaMouseMoved')}>
|
||||||
|
${mediaTag}
|
||||||
|
${renderOverlay(state)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
// As soon as the video loads enough to know the video dimensions, resize the window
|
||||||
|
function onLoadedMetadata (e) {
|
||||||
|
if (mediaType !== 'video') return
|
||||||
|
var dimensions = {
|
||||||
|
width: player.width(),
|
||||||
|
height: player.height()
|
||||||
|
}
|
||||||
|
dispatch('setDimensions', dimensions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the video completes, pause the video instead of looping
|
||||||
|
function onEnded (e) {
|
||||||
|
state.playing.isPaused = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderOverlay (state) {
|
function renderOverlay (state) {
|
||||||
var elems = []
|
var elems = []
|
||||||
var audioMetadataElem = renderAudioMetadata(state)
|
var audioMetadataElem = renderAudioMetadata(state)
|
||||||
|
|||||||
Reference in New Issue
Block a user