135 lines
4.3 KiB
JavaScript
135 lines
4.3 KiB
JavaScript
const electron = require('electron')
|
|
const fs = require('fs-extra')
|
|
const path = require('path')
|
|
const parallel = require('run-parallel')
|
|
|
|
const {dispatch} = require('../lib/dispatcher')
|
|
|
|
module.exports = class SubtitlesController {
|
|
constructor (state) {
|
|
this.state = state
|
|
}
|
|
|
|
openSubtitles () {
|
|
electron.remote.dialog.showOpenDialog({
|
|
title: 'Select a subtitles file.',
|
|
filters: [ { name: 'Subtitles', extensions: ['vtt', 'srt'] } ],
|
|
properties: [ 'openFile' ]
|
|
}, (filenames) => {
|
|
if (!Array.isArray(filenames)) return
|
|
this.addSubtitles(filenames, true)
|
|
})
|
|
}
|
|
|
|
selectSubtitle (ix) {
|
|
this.state.playing.subtitles.selectedIndex = ix
|
|
}
|
|
|
|
toggleSubtitlesMenu () {
|
|
var subtitles = this.state.playing.subtitles
|
|
subtitles.showMenu = !subtitles.showMenu
|
|
}
|
|
|
|
addSubtitles (files, autoSelect) {
|
|
// Subtitles are only supported when playing video files
|
|
if (this.state.playing.type !== 'video') return
|
|
if (files.length === 0) return
|
|
var subtitles = this.state.playing.subtitles
|
|
|
|
// Read the files concurrently, then add all resulting subtitle tracks
|
|
var tasks = files.map((file) => (cb) => loadSubtitle(file, cb))
|
|
parallel(tasks, function (err, tracks) {
|
|
if (err) return dispatch('error', err)
|
|
|
|
for (var i = 0; i < tracks.length; i++) {
|
|
// No dupes allowed
|
|
var track = tracks[i]
|
|
if (subtitles.tracks.some(
|
|
(t) => track.filePath === t.filePath)) continue
|
|
|
|
// Add the track
|
|
subtitles.tracks.push(track)
|
|
|
|
// If we're auto-selecting a track, try to find one in the user's language
|
|
if (autoSelect && (i === 0 || isSystemLanguage(track.language))) {
|
|
subtitles.selectedIndex = subtitles.tracks.length - 1
|
|
}
|
|
}
|
|
|
|
// Finally, make sure no two tracks have the same label
|
|
relabelSubtitles(subtitles)
|
|
})
|
|
}
|
|
|
|
checkForSubtitles () {
|
|
if (this.state.playing.type !== 'video') return
|
|
var torrentSummary = this.state.getPlayingTorrentSummary()
|
|
if (!torrentSummary || !torrentSummary.progress) return
|
|
|
|
torrentSummary.progress.files.forEach((fp, ix) => {
|
|
if (fp.numPieces !== fp.numPiecesPresent) return // ignore incomplete files
|
|
var file = torrentSummary.files[ix]
|
|
if (!this.isSubtitle(file.name)) return
|
|
var filePath = path.join(torrentSummary.path, file.path)
|
|
this.addSubtitles([filePath], false)
|
|
})
|
|
}
|
|
|
|
isSubtitle (file) {
|
|
var name = typeof file === 'string' ? file : file.name
|
|
var ext = path.extname(name).toLowerCase()
|
|
return ext === '.srt' || ext === '.vtt'
|
|
}
|
|
}
|
|
|
|
function loadSubtitle (file, cb) {
|
|
// Lazy load to keep startup fast
|
|
var concat = require('simple-concat')
|
|
var LanguageDetect = require('languagedetect')
|
|
var srtToVtt = require('srt-to-vtt')
|
|
|
|
// Read the .SRT or .VTT file, parse it, add subtitle track
|
|
var filePath = file.path || file
|
|
|
|
var vttStream = fs.createReadStream(filePath).pipe(srtToVtt())
|
|
|
|
concat(vttStream, function (err, buf) {
|
|
if (err) return dispatch('error', 'Can\'t parse subtitles file.')
|
|
|
|
// Detect what language the subtitles are in
|
|
var vttContents = buf.toString().replace(/(.*-->.*)/g, '')
|
|
var langDetected = (new LanguageDetect()).detect(vttContents, 2)
|
|
langDetected = langDetected.length ? langDetected[0][0] : 'subtitle'
|
|
langDetected = langDetected.slice(0, 1).toUpperCase() + langDetected.slice(1)
|
|
|
|
var track = {
|
|
buffer: 'data:text/vtt;base64,' + buf.toString('base64'),
|
|
language: langDetected,
|
|
label: langDetected,
|
|
filePath: filePath
|
|
}
|
|
|
|
cb(null, track)
|
|
})
|
|
}
|
|
|
|
// Checks whether a language name like "English" or "German" matches the system
|
|
// language, aka the current locale
|
|
function isSystemLanguage (language) {
|
|
var iso639 = require('iso-639-1')
|
|
var osLangISO = window.navigator.language.split('-')[0] // eg "en"
|
|
var langIso = iso639.getCode(language) // eg "de" if language is "German"
|
|
return langIso === osLangISO
|
|
}
|
|
|
|
// 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 (subtitles) {
|
|
var counts = {}
|
|
subtitles.tracks.forEach(function (track) {
|
|
var lang = track.language
|
|
counts[lang] = (counts[lang] || 0) + 1
|
|
track.label = counts[lang] > 1 ? (lang + ' ' + counts[lang]) : lang
|
|
})
|
|
}
|