Add subtitle support (via drag-n-drop) (#361)
* issue template * cleanup closePlayer() and stopServer() * Add subtitle support (via drag-n-drop) Drag and drop a subtitles file (.srt or .vtt) onto the player (or the app icon on OS X) to add subtitles to the currently playing video. For #281 * add multiple subtitles structure * add open subtitle dialog from cc player controls
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
console.time('init')
|
||||
|
||||
var cfg = require('application-config')('WebTorrent')
|
||||
var concat = require('concat-stream')
|
||||
var dragDrop = require('drag-drop')
|
||||
var electron = require('electron')
|
||||
var EventEmitter = require('events')
|
||||
@@ -8,6 +9,7 @@ var fs = require('fs')
|
||||
var mainLoop = require('main-loop')
|
||||
var path = require('path')
|
||||
var remote = require('remote')
|
||||
var srtToVtt = require('srt-to-vtt')
|
||||
|
||||
var createElement = require('virtual-dom/create-element')
|
||||
var diff = require('virtual-dom/diff')
|
||||
@@ -255,6 +257,9 @@ function dispatch (action, ...args) {
|
||||
if (action === 'setVolume') {
|
||||
setVolume(args[0] /* increase */)
|
||||
}
|
||||
if (action === 'openSubtitles') {
|
||||
openSubtitles()
|
||||
}
|
||||
if (action === 'mediaPlaying') {
|
||||
state.playing.isPaused = false
|
||||
ipcRenderer.send('blockPowerSave')
|
||||
@@ -331,7 +336,6 @@ function changeVolume (delta) {
|
||||
setVolume(state.playing.volume + delta)
|
||||
}
|
||||
|
||||
// TODO: never called. Either remove or make a volume control that calls it
|
||||
function setVolume (volume) {
|
||||
// check if its in [0.0 - 1.0] range
|
||||
volume = Math.max(0, Math.min(1, volume))
|
||||
@@ -342,6 +346,17 @@ function setVolume (volume) {
|
||||
}
|
||||
}
|
||||
|
||||
function openSubtitles () {
|
||||
dialog.showOpenDialog({
|
||||
title: 'Select a subtitles file.',
|
||||
filters: [ { name: 'Subtitles', extensions: ['vtt', 'srt'] } ],
|
||||
properties: [ 'openFile' ]
|
||||
}, function (filenames) {
|
||||
if (!Array.isArray(filenames)) return
|
||||
addSubtitle({path: filenames[0]})
|
||||
})
|
||||
}
|
||||
|
||||
// Checks whether we are connected and already casting
|
||||
// Returns false if we not casting (state.playing.location === 'local')
|
||||
// or if we're trying to connect but haven't yet ('chromecast-pending', etc)
|
||||
@@ -459,12 +474,35 @@ function onOpen (files) {
|
||||
if (!Array.isArray(files)) files = [ files ]
|
||||
|
||||
// .torrent file = start downloading the torrent
|
||||
files.filter(isTorrent).forEach(function (torrentFile) {
|
||||
addTorrent(torrentFile)
|
||||
})
|
||||
files.filter(isTorrent).forEach(addTorrent)
|
||||
|
||||
// subtitle file
|
||||
files.filter(isSubtitle).forEach(addSubtitle)
|
||||
|
||||
// everything else = seed these files
|
||||
createTorrentFromFileObjects(files.filter(isNotTorrent))
|
||||
var rest = files.filter(not(isTorrent)).filter(not(isSubtitle))
|
||||
if (rest.length > 0) {
|
||||
createTorrentFromFileObjects(rest)
|
||||
}
|
||||
}
|
||||
|
||||
function isTorrent (file) {
|
||||
var name = typeof file === 'string' ? file : file.name
|
||||
var isTorrentFile = path.extname(name).toLowerCase() === '.torrent'
|
||||
var isMagnet = typeof file === 'string' && /^magnet:/.test(file)
|
||||
return isTorrentFile || isMagnet
|
||||
}
|
||||
|
||||
function isSubtitle (file) {
|
||||
var name = typeof file === 'string' ? file : file.name
|
||||
var ext = path.extname(name).toLowerCase()
|
||||
return ext === '.srt' || ext === '.vtt'
|
||||
}
|
||||
|
||||
function not (test) {
|
||||
return function (...args) {
|
||||
return !test(...args)
|
||||
}
|
||||
}
|
||||
|
||||
function onPaste (e) {
|
||||
@@ -478,17 +516,6 @@ function onPaste (e) {
|
||||
})
|
||||
}
|
||||
|
||||
function isTorrent (file) {
|
||||
var name = typeof file === 'string' ? file : file.name
|
||||
var isTorrentFile = path.extname(name).toLowerCase() === '.torrent'
|
||||
var isMagnet = typeof file === 'string' && /^magnet:/.test(file)
|
||||
return isTorrentFile || isMagnet
|
||||
}
|
||||
|
||||
function isNotTorrent (file) {
|
||||
return !isTorrent(file)
|
||||
}
|
||||
|
||||
// Gets a torrent summary {name, infoHash, status} from state.saved.torrents
|
||||
// Returns undefined if we don't know that infoHash
|
||||
function getTorrentSummary (torrentKey) {
|
||||
@@ -509,6 +536,23 @@ function addTorrent (torrentId) {
|
||||
ipcRenderer.send('wt-start-torrenting', torrentKey, torrentId, path)
|
||||
}
|
||||
|
||||
function addSubtitle (file) {
|
||||
if (state.playing.type !== 'video') return
|
||||
fs.createReadStream(file.path || file).pipe(srtToVtt()).pipe(concat(function (buf) {
|
||||
// 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
|
||||
// possible via CSS.
|
||||
var subtitles = Buffer(buf.toString().replace(/(-->.*)/g, '$1 line:88%'))
|
||||
var track = {
|
||||
buffer: 'data:text/vtt;base64,' + subtitles.toString('base64'),
|
||||
language: 'Language ' + state.playing.subtitles.tracks.length,
|
||||
selected: true
|
||||
}
|
||||
state.playing.subtitles.tracks.push(track)
|
||||
state.playing.subtitles.enabled = true
|
||||
}))
|
||||
}
|
||||
|
||||
// Starts downloading and/or seeding a given torrentSummary. Returns WebTorrent object
|
||||
function startTorrentingSummary (torrentSummary) {
|
||||
var s = torrentSummary
|
||||
@@ -744,12 +788,6 @@ function pickFileToPlay (files) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
function stopServer () {
|
||||
ipcRenderer.send('wt-stop-server')
|
||||
state.playing = State.getDefaultPlayState()
|
||||
state.server = null
|
||||
}
|
||||
|
||||
// Opens the video player
|
||||
function openPlayer (infoHash, index, cb) {
|
||||
var torrentSummary = getTorrentSummary(infoHash)
|
||||
@@ -817,23 +855,23 @@ function openPlayerFromActiveTorrent (torrentSummary, index, timeout, cb) {
|
||||
}
|
||||
|
||||
function closePlayer (cb) {
|
||||
state.window.title = config.APP_WINDOW_TITLE
|
||||
update() /* needed for OSX: toggleFullScreen animation w/ correct title */
|
||||
|
||||
if (isCasting()) {
|
||||
Cast.close()
|
||||
}
|
||||
state.window.title = config.APP_WINDOW_TITLE
|
||||
state.playing = State.getDefaultPlayState()
|
||||
state.server = null
|
||||
|
||||
if (state.window.isFullScreen) {
|
||||
dispatch('toggleFullScreen', false)
|
||||
}
|
||||
restoreBounds()
|
||||
stopServer()
|
||||
update()
|
||||
|
||||
ipcRenderer.send('wt-stop-server')
|
||||
ipcRenderer.send('unblockPowerSave')
|
||||
ipcRenderer.send('onPlayerClose')
|
||||
|
||||
update()
|
||||
cb()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user