Simplify subtitles code
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
"electron-prebuilt": "1.0.2",
|
"electron-prebuilt": "1.0.2",
|
||||||
"fs-extra": "^0.27.0",
|
"fs-extra": "^0.27.0",
|
||||||
"hyperx": "^2.0.2",
|
"hyperx": "^2.0.2",
|
||||||
|
"iso-639-1": "^1.2.1",
|
||||||
"languagedetect": "^1.1.1",
|
"languagedetect": "^1.1.1",
|
||||||
"main-loop": "^3.2.0",
|
"main-loop": "^3.2.0",
|
||||||
"musicmetadata": "^2.0.2",
|
"musicmetadata": "^2.0.2",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ var appConfig = require('application-config')('WebTorrent')
|
|||||||
var concat = require('concat-stream')
|
var concat = require('concat-stream')
|
||||||
var dragDrop = require('drag-drop')
|
var dragDrop = require('drag-drop')
|
||||||
var fs = require('fs-extra')
|
var fs = require('fs-extra')
|
||||||
|
var iso639 = require('iso-639-1')
|
||||||
var mainLoop = require('main-loop')
|
var mainLoop = require('main-loop')
|
||||||
var path = require('path')
|
var path = require('path')
|
||||||
|
|
||||||
@@ -295,10 +296,10 @@ function dispatch (action, ...args) {
|
|||||||
openSubtitles()
|
openSubtitles()
|
||||||
}
|
}
|
||||||
if (action === 'selectSubtitle') {
|
if (action === 'selectSubtitle') {
|
||||||
selectSubtitle(args[0] /* label */)
|
selectSubtitle(args[0] /* index */)
|
||||||
}
|
}
|
||||||
if (action === 'showSubtitles') {
|
if (action === 'toggleSubtitlesMenu') {
|
||||||
showSubtitles()
|
toggleSubtitlesMenu()
|
||||||
}
|
}
|
||||||
if (action === 'mediaStalled') {
|
if (action === 'mediaStalled') {
|
||||||
state.playing.isStalled = true
|
state.playing.isStalled = true
|
||||||
@@ -600,41 +601,60 @@ function addSubtitle (file) {
|
|||||||
// Set the cue text position so it appears above the player controls.
|
// Set the cue text position so it appears above the player controls.
|
||||||
// The only way to change cue text position is by modifying the VTT. It is not
|
// The only way to change cue text position is by modifying the VTT. It is not
|
||||||
// possible via CSS.
|
// possible via CSS.
|
||||||
var langDetected = (new LanguageDetect()).detect(buf.toString().replace(/(.*-->.*)/g, ''), 2)
|
var vttContents = buf.toString().replace(/(.*-->.*)/g, '')
|
||||||
|
var langDetected = (new LanguageDetect()).detect(vttContents, 2)
|
||||||
langDetected = langDetected.length ? langDetected[0][0] : 'subtitle'
|
langDetected = langDetected.length ? langDetected[0][0] : 'subtitle'
|
||||||
langDetected = langDetected.slice(0, 1).toUpperCase() + langDetected.slice(1)
|
langDetected = langDetected.slice(0, 1).toUpperCase() + langDetected.slice(1)
|
||||||
var subtitles = Buffer(buf.toString().replace(/(-->.*)/g, '$1 line:88%'))
|
var subtitles = Buffer(buf.toString().replace(/(-->.*)/g, '$1 line:88%'))
|
||||||
var track = {
|
var track = {
|
||||||
buffer: 'data:text/vtt;base64,' + subtitles.toString('base64'),
|
buffer: 'data:text/vtt;base64,' + subtitles.toString('base64'),
|
||||||
label: langDetected,
|
language: langDetected,
|
||||||
selected: true
|
label: langDetected
|
||||||
}
|
}
|
||||||
state.playing.subtitles.tracks.forEach(function (trackItem) {
|
var subs = state.playing.subtitles
|
||||||
trackItem.selected = false
|
subs.tracks.push(track)
|
||||||
if (trackItem.label === track.label) {
|
selectNewlyAddedSubtitle()
|
||||||
var labelParts = /([^\d]+)(\d+)$/.exec(track.label)
|
relabelSubtitles()
|
||||||
track.label = labelParts
|
|
||||||
? labelParts[1] + (parseInt(labelParts[2]) + 1)
|
|
||||||
: track.label + ' 2'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
state.playing.subtitles.change = track.label
|
|
||||||
state.playing.subtitles.tracks.push(track)
|
|
||||||
state.playing.subtitles.enabled = true
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectSubtitle (label) {
|
function selectSubtitle (ix) {
|
||||||
state.playing.subtitles.tracks.forEach(function (track) {
|
state.playing.subtitles.selectedIndex = ix
|
||||||
track.selected = (track.label === label)
|
|
||||||
})
|
|
||||||
state.playing.subtitles.enabled = !!label
|
|
||||||
state.playing.subtitles.change = label
|
|
||||||
state.playing.subtitles.show = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSubtitles () {
|
// Automatically choose the subtitle in the user's language, if possible
|
||||||
state.playing.subtitles.show = !state.playing.subtitles.show
|
function selectNewlyAddedSubtitle () {
|
||||||
|
var oldIx = state.playing.subtitles.selectedIndex
|
||||||
|
if (oldIx === -1) oldIx = undefined
|
||||||
|
var newIx = state.playing.subtitles.tracks.length - 1
|
||||||
|
|
||||||
|
// Find which subtitle track fits the current locale
|
||||||
|
var langIx
|
||||||
|
var osLangISO = window.navigator.language.split('-')[0] // eg "en"
|
||||||
|
var trackLang = state.playing.subtitles.tracks[newIx].language // eg "German"
|
||||||
|
var trackLangISO = iso639.getCode(trackLang) // eg "de"
|
||||||
|
if (trackLangISO === osLangISO) {
|
||||||
|
selectSubtitle(newIx) // newly added track is in the user's language
|
||||||
|
} else {
|
||||||
|
selectSubtitle(oldIx || newIx) // otherwise, if we've already selected a track, keep it
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('SELECTING', langIx, oldIx, newIx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't have two subtitle tracks with the same label
|
||||||
|
// Labels each track by language, eg "German", "English", "English 2", ...
|
||||||
|
function relabelSubtitles () {
|
||||||
|
var counts = {}
|
||||||
|
state.playing.subtitles.tracks.forEach(function (track) {
|
||||||
|
var lang = track.language
|
||||||
|
counts[lang] = (counts[lang] || 0) + 1
|
||||||
|
track.label = counts[lang] > 1 ? (lang + ' ' + counts[lang]) : lang
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSubtitlesMenu () {
|
||||||
|
state.playing.subtitles.showMenu = !state.playing.subtitles.showMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts downloading and/or seeding a given torrentSummary. Returns WebTorrent object
|
// Starts downloading and/or seeding a given torrentSummary. Returns WebTorrent object
|
||||||
|
|||||||
@@ -75,8 +75,9 @@ function getDefaultPlayState () {
|
|||||||
lastTimeUpdate: 0, /* Unix time in ms */
|
lastTimeUpdate: 0, /* Unix time in ms */
|
||||||
mouseStationarySince: 0, /* Unix time in ms */
|
mouseStationarySince: 0, /* Unix time in ms */
|
||||||
subtitles: {
|
subtitles: {
|
||||||
tracks: [], /* subtitles file (Buffer) */
|
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
||||||
enabled: false
|
selectedIndex: -1, /* current subtitle track */
|
||||||
|
showMenu: false /* popover menu, above the video */
|
||||||
},
|
},
|
||||||
aspectRatio: 0 /* aspect ratio of the video */
|
aspectRatio: 0 /* aspect ratio of the video */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ function CreateTorrentPage (state) {
|
|||||||
pathPrefix = files[0]
|
pathPrefix = files[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log('WTF', pathPrefix, files)
|
||||||
|
|
||||||
// Sanity check: show the number of files and total size
|
// Sanity check: show the number of files and total size
|
||||||
var numFiles = files.length
|
var numFiles = files.length
|
||||||
|
|||||||
@@ -54,14 +54,10 @@ function renderMedia (state) {
|
|||||||
state.playing.setVolume = null
|
state.playing.setVolume = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix textTrack cues not been removed <track> rerender
|
// Switch to the newly added subtitle track, if available
|
||||||
if (state.playing.subtitles.change) {
|
var tracks = mediaElement.textTracks
|
||||||
var tracks = mediaElement.textTracks
|
for (var j = 0; j < tracks.length; j++) {
|
||||||
for (var j = 0; j < tracks.length; j++) {
|
tracks[j].mode = (j === state.playing.subtitles.selectedIndex) ? 'showing' : 'hidden'
|
||||||
// mode is not an <track> attribute, only available on DOM
|
|
||||||
tracks[j].mode = (tracks[j].label === state.playing.subtitles.change) ? 'showing' : 'hidden'
|
|
||||||
}
|
|
||||||
state.playing.subtitles.change = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.playing.currentTime = mediaElement.currentTime
|
state.playing.currentTime = mediaElement.currentTime
|
||||||
@@ -71,13 +67,13 @@ function renderMedia (state) {
|
|||||||
|
|
||||||
// Add subtitles to the <video> tag
|
// Add subtitles to the <video> tag
|
||||||
var trackTags = []
|
var trackTags = []
|
||||||
|
if (state.playing.subtitles.selectedIndex >= 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]
|
||||||
|
var isSelected = state.playing.subtitles.selectedIndex === i
|
||||||
trackTags.push(hx`
|
trackTags.push(hx`
|
||||||
<track
|
<track
|
||||||
${track.selected ? 'default' : ''}
|
${isSelected ? 'default' : ''}
|
||||||
label=${track.label}
|
label=${track.label}
|
||||||
type='subtitles'
|
type='subtitles'
|
||||||
src=${track.buffer}>
|
src=${track.buffer}>
|
||||||
@@ -270,22 +266,24 @@ function renderCastScreen (state) {
|
|||||||
|
|
||||||
function renderSubtitlesOptions (state) {
|
function renderSubtitlesOptions (state) {
|
||||||
var subtitles = state.playing.subtitles
|
var subtitles = state.playing.subtitles
|
||||||
if (!subtitles.tracks.length || !subtitles.show) return
|
if (!subtitles.tracks.length || !subtitles.showMenu) return
|
||||||
|
|
||||||
var items = subtitles.tracks.map(function (track) {
|
var items = subtitles.tracks.map(function (track, ix) {
|
||||||
|
var isSelected = state.playing.subtitles.selectedIndex === ix
|
||||||
return hx`
|
return hx`
|
||||||
<li onclick=${dispatcher('selectSubtitle', track.label)}>
|
<li onclick=${dispatcher('selectSubtitle', ix)}>
|
||||||
<i.icon>${track.selected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
<i.icon>${isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
||||||
${track.label}
|
${track.label}
|
||||||
</li>
|
</li>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var noneSelected = state.playing.subtitles.selectedIndex === -1
|
||||||
return hx`
|
return hx`
|
||||||
<ul.subtitles-list>
|
<ul.subtitles-list>
|
||||||
${items}
|
${items}
|
||||||
<li onclick=${dispatcher('selectSubtitle', '')}>
|
<li onclick=${dispatcher('selectSubtitle', -1)}>
|
||||||
<i.icon>${!subtitles.enabled ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
<i.icon>${noneSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
||||||
None
|
None
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -297,7 +295,7 @@ function renderPlayerControls (state) {
|
|||||||
var playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 8px)' }
|
var playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 8px)' }
|
||||||
var captionsClass = state.playing.subtitles.tracks.length === 0
|
var captionsClass = state.playing.subtitles.tracks.length === 0
|
||||||
? 'disabled'
|
? 'disabled'
|
||||||
: state.playing.subtitles.enabled
|
: state.playing.subtitles.selectedIndex >= 0
|
||||||
? 'active'
|
? 'active'
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
@@ -484,7 +482,7 @@ function renderPlayerControls (state) {
|
|||||||
// if no subtitles available select it
|
// if no subtitles available select it
|
||||||
dispatch('openSubtitles')
|
dispatch('openSubtitles')
|
||||||
} else {
|
} else {
|
||||||
dispatch('showSubtitles')
|
dispatch('toggleSubtitlesMenu')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user