Style: no more var

This commit is contained in:
DC
2016-08-31 14:36:11 -07:00
parent 0bda5358bd
commit 3f6cc97a02
54 changed files with 676 additions and 679 deletions

View File

@@ -1,4 +1,4 @@
language: node_js language: node_js
node_js: node_js:
- 'node' - 'node'
install: npm install standard depcheck install: npm install standard depcheck walk-sync

View File

@@ -30,10 +30,9 @@ files.forEach(function (file) {
error = 'Line >100 chars' error = 'Line >100 chars'
} }
// TODO: No vars if (line.match(/^var /) || line.match(/ var /)) {
// if (line.match(/^var /) || line.match(/ var /)) { error = 'Use const or let'
// error = 'Use const or let' }
// }
if (error) { if (error) {
let name = path.basename(file) let name = path.basename(file)

View File

@@ -1,12 +1,12 @@
var appConfig = require('application-config')('WebTorrent') const appConfig = require('application-config')('WebTorrent')
var fs = require('fs') const fs = require('fs')
var path = require('path') const path = require('path')
var APP_NAME = 'WebTorrent' const APP_NAME = 'WebTorrent'
var APP_TEAM = 'WebTorrent, LLC' const APP_TEAM = 'WebTorrent, LLC'
var APP_VERSION = require('../package.json').version const APP_VERSION = require('../package.json').version
var PORTABLE_PATH = path.join(path.dirname(process.execPath), 'Portable Settings') const PORTABLE_PATH = path.join(path.dirname(process.execPath), 'Portable Settings')
module.exports = { module.exports = {
ANNOUNCEMENT_URL: 'https://webtorrent.io/desktop/announcement', ANNOUNCEMENT_URL: 'https://webtorrent.io/desktop/announcement',
@@ -95,7 +95,7 @@ function getDefaultDownloadPath () {
return path.join(getConfigPath(), 'Downloads') return path.join(getConfigPath(), 'Downloads')
} }
var electron = require('electron') const electron = require('electron')
return process.type === 'renderer' return process.type === 'renderer'
? electron.remote.app.getPath('downloads') ? electron.remote.app.getPath('downloads')

View File

@@ -2,8 +2,8 @@ module.exports = {
init init
} }
var config = require('./config') const config = require('./config')
var electron = require('electron') const electron = require('electron')
function init () { function init () {
electron.crashReporter.start({ electron.crashReporter.start({

View File

@@ -2,12 +2,12 @@ module.exports = {
init init
} }
var electron = require('electron') const electron = require('electron')
var config = require('../config') const config = require('../config')
var log = require('./log') const log = require('./log')
var ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL + const ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL +
'?version=' + config.APP_VERSION + '?version=' + config.APP_VERSION +
'&platform=' + process.platform '&platform=' + process.platform
@@ -26,7 +26,7 @@ var ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL +
* } * }
*/ */
function init () { function init () {
var get = require('simple-get') const get = require('simple-get')
get.concat(ANNOUNCEMENT_URL, onResponse) get.concat(ANNOUNCEMENT_URL, onResponse)
} }

View File

@@ -6,10 +6,10 @@ module.exports = {
openFiles openFiles
} }
var electron = require('electron') const electron = require('electron')
var log = require('./log') const log = require('./log')
var windows = require('./windows') const windows = require('./windows')
/** /**
* Show open dialog to create a single-file torrent. * Show open dialog to create a single-file torrent.
@@ -17,7 +17,7 @@ var windows = require('./windows')
function openSeedFile () { function openSeedFile () {
if (!windows.main.win) return if (!windows.main.win) return
log('openSeedFile') log('openSeedFile')
var opts = { const opts = {
title: 'Select a file for the torrent.', title: 'Select a file for the torrent.',
properties: [ 'openFile' ] properties: [ 'openFile' ]
} }
@@ -37,7 +37,7 @@ function openSeedFile () {
function openSeedDirectory () { function openSeedDirectory () {
if (!windows.main.win) return if (!windows.main.win) return
log('openSeedDirectory') log('openSeedDirectory')
var opts = process.platform === 'darwin' const opts = process.platform === 'darwin'
? { ? {
title: 'Select a file or folder for the torrent.', title: 'Select a file or folder for the torrent.',
properties: [ 'openFile', 'openDirectory' ] properties: [ 'openFile', 'openDirectory' ]
@@ -61,7 +61,7 @@ function openSeedDirectory () {
function openFiles () { function openFiles () {
if (!windows.main.win) return if (!windows.main.win) return
log('openFiles') log('openFiles')
var opts = process.platform === 'darwin' const opts = process.platform === 'darwin'
? { ? {
title: 'Select a file or folder to add.', title: 'Select a file or folder to add.',
properties: [ 'openFile', 'openDirectory' ] properties: [ 'openFile', 'openDirectory' ]
@@ -84,7 +84,7 @@ function openFiles () {
function openTorrentFile () { function openTorrentFile () {
if (!windows.main.win) return if (!windows.main.win) return
log('openTorrentFile') log('openTorrentFile')
var opts = { const opts = {
title: 'Select a .torrent file.', title: 'Select a .torrent file.',
filters: [{ name: 'Torrent Files', extensions: ['torrent'] }], filters: [{ name: 'Torrent Files', extensions: ['torrent'] }],
properties: [ 'openFile', 'multiSelections' ] properties: [ 'openFile', 'multiSelections' ]

View File

@@ -4,17 +4,17 @@ module.exports = {
setBadge setBadge
} }
var {app, Menu} = require('electron') const {app, Menu} = require('electron')
var dialog = require('./dialog') const dialog = require('./dialog')
var log = require('./log') const log = require('./log')
/** /**
* Add a right-click menu to the dock icon. (Mac) * Add a right-click menu to the dock icon. (Mac)
*/ */
function init () { function init () {
if (!app.dock) return if (!app.dock) return
var menu = Menu.buildFromTemplate(getMenuTemplate()) const menu = Menu.buildFromTemplate(getMenuTemplate())
app.dock.setMenu(menu) app.dock.setMenu(menu)
} }

View File

@@ -4,14 +4,14 @@ module.exports = {
checkInstall checkInstall
} }
var cp = require('child_process') const cp = require('child_process')
var vlcCommand = require('vlc-command') const vlcCommand = require('vlc-command')
var log = require('./log') const log = require('./log')
var windows = require('./windows') const windows = require('./windows')
// holds a ChildProcess while we're playing a video in an external player, null otherwise // holds a ChildProcess while we're playing a video in an external player, null otherwise
var proc let proc = null
function checkInstall (path, cb) { function checkInstall (path, cb) {
// check for VLC if external player has not been specified by the user // check for VLC if external player has not been specified by the user
@@ -26,7 +26,7 @@ function spawn (path, url, title) {
// Try to find and use VLC if external player is not specified // Try to find and use VLC if external player is not specified
vlcCommand(function (err, vlcPath) { vlcCommand(function (err, vlcPath) {
if (err) return windows.main.dispatch('externalPlayerNotFound') if (err) return windows.main.dispatch('externalPlayerNotFound')
var args = [ const args = [
'--play-and-exit', '--play-and-exit',
'--video-on-top', '--video-on-top',
'--quiet', '--quiet',
@@ -50,7 +50,7 @@ function spawnExternal (path, args) {
proc = cp.spawn(path, args, {stdio: 'ignore'}) proc = cp.spawn(path, args, {stdio: 'ignore'})
// If it works, close the modal after a second // If it works, close the modal after a second
var closeModalTimeout = setTimeout(() => const closeModalTimeout = setTimeout(() =>
windows.main.dispatch('exitModal'), 1000) windows.main.dispatch('exitModal'), 1000)
proc.on('close', function (code) { proc.on('close', function (code) {

View File

@@ -3,8 +3,8 @@ module.exports = {
uninstall uninstall
} }
var config = require('../config') const config = require('../config')
var path = require('path') const path = require('path')
function install () { function install () {
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
@@ -31,8 +31,8 @@ function uninstall () {
} }
function installDarwin () { function installDarwin () {
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
// On Mac, only protocols that are listed in `Info.plist` can be set as the // On Mac, only protocols that are listed in `Info.plist` can be set as the
// default handler at runtime. // default handler at runtime.
@@ -44,18 +44,18 @@ function installDarwin () {
function uninstallDarwin () {} function uninstallDarwin () {}
var EXEC_COMMAND = [ process.execPath ] const EXEC_COMMAND = [ process.execPath ]
if (!config.IS_PRODUCTION) { if (!config.IS_PRODUCTION) {
EXEC_COMMAND.push(config.ROOT_PATH) EXEC_COMMAND.push(config.ROOT_PATH)
} }
function installWin32 () { function installWin32 () {
var Registry = require('winreg') const Registry = require('winreg')
var log = require('./log') const log = require('./log')
var iconPath = path.join( const iconPath = path.join(
process.resourcesPath, 'app.asar.unpacked', 'static', 'WebTorrentFile.ico' process.resourcesPath, 'app.asar.unpacked', 'static', 'WebTorrentFile.ico'
) )
registerProtocolHandlerWin32( registerProtocolHandlerWin32(
@@ -100,7 +100,7 @@ function installWin32 () {
*/ */
function registerProtocolHandlerWin32 (protocol, name, icon, command) { function registerProtocolHandlerWin32 (protocol, name, icon, command) {
var protocolKey = new Registry({ const protocolKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER hive: Registry.HKCU, // HKEY_CURRENT_USER
key: '\\Software\\Classes\\' + protocol key: '\\Software\\Classes\\' + protocol
}) })
@@ -120,7 +120,7 @@ function installWin32 () {
function setIcon (err) { function setIcon (err) {
if (err) log.error(err.message) if (err) log.error(err.message)
var iconKey = new Registry({ const iconKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + protocol + '\\DefaultIcon' key: '\\Software\\Classes\\' + protocol + '\\DefaultIcon'
}) })
@@ -130,7 +130,7 @@ function installWin32 () {
function setCommand (err) { function setCommand (err) {
if (err) log.error(err.message) if (err) log.error(err.message)
var commandKey = new Registry({ const commandKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + protocol + '\\shell\\open\\command' key: '\\Software\\Classes\\' + protocol + '\\shell\\open\\command'
}) })
@@ -161,7 +161,7 @@ function installWin32 () {
setExt() setExt()
function setExt () { function setExt () {
var extKey = new Registry({ const extKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER hive: Registry.HKCU, // HKEY_CURRENT_USER
key: '\\Software\\Classes\\' + ext key: '\\Software\\Classes\\' + ext
}) })
@@ -171,7 +171,7 @@ function installWin32 () {
function setId (err) { function setId (err) {
if (err) log.error(err.message) if (err) log.error(err.message)
var idKey = new Registry({ const idKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + id key: '\\Software\\Classes\\' + id
}) })
@@ -181,7 +181,7 @@ function installWin32 () {
function setIcon (err) { function setIcon (err) {
if (err) log.error(err.message) if (err) log.error(err.message)
var iconKey = new Registry({ const iconKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + id + '\\DefaultIcon' key: '\\Software\\Classes\\' + id + '\\DefaultIcon'
}) })
@@ -191,7 +191,7 @@ function installWin32 () {
function setCommand (err) { function setCommand (err) {
if (err) log.error(err.message) if (err) log.error(err.message)
var commandKey = new Registry({ const commandKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + id + '\\shell\\open\\command' key: '\\Software\\Classes\\' + id + '\\shell\\open\\command'
}) })
@@ -205,7 +205,7 @@ function installWin32 () {
} }
function uninstallWin32 () { function uninstallWin32 () {
var Registry = require('winreg') const Registry = require('winreg')
unregisterProtocolHandlerWin32('magnet', EXEC_COMMAND) unregisterProtocolHandlerWin32('magnet', EXEC_COMMAND)
unregisterProtocolHandlerWin32('stream-magnet', EXEC_COMMAND) unregisterProtocolHandlerWin32('stream-magnet', EXEC_COMMAND)
@@ -215,7 +215,7 @@ function uninstallWin32 () {
getCommand() getCommand()
function getCommand () { function getCommand () {
var commandKey = new Registry({ const commandKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER hive: Registry.HKCU, // HKEY_CURRENT_USER
key: '\\Software\\Classes\\' + protocol + '\\shell\\open\\command' key: '\\Software\\Classes\\' + protocol + '\\shell\\open\\command'
}) })
@@ -227,7 +227,7 @@ function uninstallWin32 () {
} }
function destroyProtocol () { function destroyProtocol () {
var protocolKey = new Registry({ const protocolKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + protocol key: '\\Software\\Classes\\' + protocol
}) })
@@ -239,7 +239,7 @@ function uninstallWin32 () {
eraseId() eraseId()
function eraseId () { function eraseId () {
var idKey = new Registry({ const idKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER hive: Registry.HKCU, // HKEY_CURRENT_USER
key: '\\Software\\Classes\\' + id key: '\\Software\\Classes\\' + id
}) })
@@ -247,7 +247,7 @@ function uninstallWin32 () {
} }
function getExt () { function getExt () {
var extKey = new Registry({ const extKey = new Registry({
hive: Registry.HKCU, hive: Registry.HKCU,
key: '\\Software\\Classes\\' + ext key: '\\Software\\Classes\\' + ext
}) })
@@ -259,7 +259,7 @@ function uninstallWin32 () {
} }
function destroyExt () { function destroyExt () {
var extKey = new Registry({ const extKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER hive: Registry.HKCU, // HKEY_CURRENT_USER
key: '\\Software\\Classes\\' + ext key: '\\Software\\Classes\\' + ext
}) })
@@ -273,12 +273,12 @@ function commandToArgs (command) {
} }
function installLinux () { function installLinux () {
var fs = require('fs-extra') const fs = require('fs-extra')
var os = require('os') const os = require('os')
var path = require('path') const path = require('path')
var config = require('../config') const config = require('../config')
var log = require('./log') const log = require('./log')
// Do not install in user dir if running on system // Do not install in user dir if running on system
if (/^\/opt/.test(process.execPath)) return if (/^\/opt/.test(process.execPath)) return
@@ -287,7 +287,7 @@ function installLinux () {
installIconFile() installIconFile()
function installDesktopFile () { function installDesktopFile () {
var templatePath = path.join( const templatePath = path.join(
config.STATIC_PATH, 'linux', 'webtorrent-desktop.desktop' config.STATIC_PATH, 'linux', 'webtorrent-desktop.desktop'
) )
fs.readFile(templatePath, 'utf8', writeDesktopFile) fs.readFile(templatePath, 'utf8', writeDesktopFile)
@@ -296,7 +296,7 @@ function installLinux () {
function writeDesktopFile (err, desktopFile) { function writeDesktopFile (err, desktopFile) {
if (err) return log.error(err.message) if (err) return log.error(err.message)
var appPath = config.IS_PRODUCTION const appPath = config.IS_PRODUCTION
? path.dirname(process.execPath) ? path.dirname(process.execPath)
: config.ROOT_PATH : config.ROOT_PATH
@@ -305,7 +305,7 @@ function installLinux () {
desktopFile = desktopFile.replace(/\$EXEC_PATH/g, EXEC_COMMAND.join(' ')) desktopFile = desktopFile.replace(/\$EXEC_PATH/g, EXEC_COMMAND.join(' '))
desktopFile = desktopFile.replace(/\$TRY_EXEC_PATH/g, process.execPath) desktopFile = desktopFile.replace(/\$TRY_EXEC_PATH/g, process.execPath)
var desktopFilePath = path.join( const desktopFilePath = path.join(
os.homedir(), os.homedir(),
'.local', '.local',
'share', 'share',
@@ -319,14 +319,14 @@ function installLinux () {
} }
function installIconFile () { function installIconFile () {
var iconStaticPath = path.join(config.STATIC_PATH, 'WebTorrent.png') const iconStaticPath = path.join(config.STATIC_PATH, 'WebTorrent.png')
fs.readFile(iconStaticPath, writeIconFile) fs.readFile(iconStaticPath, writeIconFile)
} }
function writeIconFile (err, iconFile) { function writeIconFile (err, iconFile) {
if (err) return log.error(err.message) if (err) return log.error(err.message)
var iconFilePath = path.join( const iconFilePath = path.join(
os.homedir(), os.homedir(),
'.local', '.local',
'share', 'share',
@@ -341,11 +341,11 @@ function installLinux () {
} }
function uninstallLinux () { function uninstallLinux () {
var os = require('os') const os = require('os')
var path = require('path') const path = require('path')
var fs = require('fs-extra') const fs = require('fs-extra')
var desktopFilePath = path.join( const desktopFilePath = path.join(
os.homedir(), os.homedir(),
'.local', '.local',
'share', 'share',
@@ -354,7 +354,7 @@ function uninstallLinux () {
) )
fs.removeSync(desktopFilePath) fs.removeSync(desktopFilePath)
var iconFilePath = path.join( const iconFilePath = path.join(
os.homedir(), os.homedir(),
'.local', '.local',
'share', 'share',

View File

@@ -1,26 +1,26 @@
console.time('init') console.time('init')
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
var ipcMain = electron.ipcMain const ipcMain = electron.ipcMain
var announcement = require('./announcement') const announcement = require('./announcement')
var config = require('../config') const config = require('../config')
var crashReporter = require('../crash-reporter') const crashReporter = require('../crash-reporter')
var dialog = require('./dialog') const dialog = require('./dialog')
var dock = require('./dock') const dock = require('./dock')
var ipc = require('./ipc') const ipc = require('./ipc')
var log = require('./log') const log = require('./log')
var menu = require('./menu') const menu = require('./menu')
var squirrelWin32 = require('./squirrel-win32') const squirrelWin32 = require('./squirrel-win32')
var tray = require('./tray') const tray = require('./tray')
var updater = require('./updater') const updater = require('./updater')
var userTasks = require('./user-tasks') const userTasks = require('./user-tasks')
var windows = require('./windows') const windows = require('./windows')
var shouldQuit = false let shouldQuit = false
var argv = sliceArgv(process.argv) let argv = sliceArgv(process.argv)
if (config.IS_PRODUCTION) { if (config.IS_PRODUCTION) {
// When Electron is running in production mode (packaged app), then run React // When Electron is running in production mode (packaged app), then run React
@@ -51,7 +51,7 @@ function init () {
app.setPath('userData', config.CONFIG_PATH) app.setPath('userData', config.CONFIG_PATH)
} }
var isReady = false // app ready, windows can be created let isReady = false // app ready, windows can be created
app.ipcReady = false // main window has finished loading and IPC is ready app.ipcReady = false // main window has finished loading and IPC is ready
app.isQuitting = false app.isQuitting = false
@@ -78,7 +78,7 @@ function init () {
// Report uncaught exceptions // Report uncaught exceptions
process.on('uncaughtException', (err) => { process.on('uncaughtException', (err) => {
console.error(err) console.error(err)
var error = {message: err.message, stack: err.stack} const error = {message: err.message, stack: err.stack}
windows.main.dispatch('uncaughtError', 'main', error) windows.main.dispatch('uncaughtError', 'main', error)
}) })
}) })
@@ -148,7 +148,7 @@ function sliceArgv (argv) {
} }
function processArgv (argv) { function processArgv (argv) {
var torrentIds = [] let torrentIds = []
argv.forEach(function (arg) { argv.forEach(function (arg) {
if (arg === '-n') { if (arg === '-n') {
dialog.openSeedDirectory() dialog.openSeedDirectory()

View File

@@ -2,27 +2,27 @@ module.exports = {
init init
} }
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
var dialog = require('./dialog') const dialog = require('./dialog')
var dock = require('./dock') const dock = require('./dock')
var handlers = require('./handlers') const handlers = require('./handlers')
var log = require('./log') const log = require('./log')
var menu = require('./menu') const menu = require('./menu')
var powerSaveBlocker = require('./power-save-blocker') const powerSaveBlocker = require('./power-save-blocker')
var shell = require('./shell') const shell = require('./shell')
var shortcuts = require('./shortcuts') const shortcuts = require('./shortcuts')
var externalPlayer = require('./external-player') const externalPlayer = require('./external-player')
var windows = require('./windows') const windows = require('./windows')
var thumbar = require('./thumbar') const thumbar = require('./thumbar')
// Messages from the main process, to be sent once the WebTorrent process starts // Messages from the main process, to be sent once the WebTorrent process starts
var messageQueueMainToWebTorrent = [] const messageQueueMainToWebTorrent = []
function init () { function init () {
var ipc = electron.ipcMain const ipc = electron.ipcMain
ipc.once('ipcReady', function (e) { ipc.once('ipcReady', function (e) {
app.ipcReady = true app.ipcReady = true
@@ -106,7 +106,7 @@ function init () {
* Windows: Main * Windows: Main
*/ */
var main = windows.main const main = windows.main
ipc.on('setAspectRatio', (e, ...args) => main.setAspectRatio(...args)) ipc.on('setAspectRatio', (e, ...args) => main.setAspectRatio(...args))
ipc.on('setBounds', (e, ...args) => main.setBounds(...args)) ipc.on('setBounds', (e, ...args) => main.setBounds(...args))
@@ -130,7 +130,7 @@ function init () {
ipc.on('quitExternalPlayer', () => externalPlayer.kill()) ipc.on('quitExternalPlayer', () => externalPlayer.kill())
// Capture all events // Capture all events
var oldEmit = ipc.emit const oldEmit = ipc.emit
ipc.emit = function (name, e, ...args) { ipc.emit = function (name, e, ...args) {
// Relay messages between the main window and the WebTorrent hidden window // Relay messages between the main window and the WebTorrent hidden window
if (name.startsWith('wt-') && !app.isQuitting) { if (name.startsWith('wt-') && !app.isQuitting) {

View File

@@ -8,10 +8,10 @@ module.exports.error = error
* where they can be viewed in Developer Tools. * where they can be viewed in Developer Tools.
*/ */
var electron = require('electron') const electron = require('electron')
var windows = require('./windows') const windows = require('./windows')
var app = electron.app const app = electron.app
function log (...args) { function log (...args) {
if (app.ipcReady) { if (app.ipcReady) {

View File

@@ -8,16 +8,16 @@ module.exports = {
onToggleFullScreen onToggleFullScreen
} }
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
var config = require('../config') const config = require('../config')
var dialog = require('./dialog') const dialog = require('./dialog')
var shell = require('./shell') const shell = require('./shell')
var windows = require('./windows') const windows = require('./windows')
var menu let menu = null
function init () { function init () {
menu = electron.Menu.buildFromTemplate(getMenuTemplate()) menu = electron.Menu.buildFromTemplate(getMenuTemplate())
@@ -72,8 +72,8 @@ function onToggleFullScreen (flag) {
} }
function getMenuItem (label) { function getMenuItem (label) {
for (var i = 0; i < menu.items.length; i++) { for (let i = 0; i < menu.items.length; i++) {
var menuItem = menu.items[i].submenu.items.find(function (item) { const menuItem = menu.items[i].submenu.items.find(function (item) {
return item.label === label return item.label === label
}) })
if (menuItem) return menuItem if (menuItem) return menuItem
@@ -81,7 +81,7 @@ function getMenuItem (label) {
} }
function getMenuTemplate () { function getMenuTemplate () {
var template = [ const template = [
{ {
label: 'File', label: 'File',
submenu: [ submenu: [

View File

@@ -3,10 +3,10 @@ module.exports = {
disable disable
} }
var electron = require('electron') const electron = require('electron')
var log = require('./log') const log = require('./log')
var blockId = 0 let blockId = 0
/** /**
* Block the system from entering low-power (sleep) mode or turning off the * Block the system from entering low-power (sleep) mode or turning off the

View File

@@ -5,8 +5,8 @@ module.exports = {
moveItemToTrash moveItemToTrash
} }
var electron = require('electron') const electron = require('electron')
var log = require('./log') const log = require('./log')
/** /**
* Open the given external protocol URL in the desktops default manner. * Open the given external protocol URL in the desktops default manner.

View File

@@ -3,8 +3,8 @@ module.exports = {
enable enable
} }
var electron = require('electron') const electron = require('electron')
var windows = require('./windows') const windows = require('./windows')
function enable () { function enable () {
// Register play/pause media key, available on some keyboards. // Register play/pause media key, available on some keyboards.

View File

@@ -2,18 +2,18 @@ module.exports = {
handleEvent handleEvent
} }
var cp = require('child_process') const cp = require('child_process')
var electron = require('electron') const electron = require('electron')
var fs = require('fs') const fs = require('fs')
var os = require('os') const os = require('os')
var path = require('path') const path = require('path')
var app = electron.app const app = electron.app
var handlers = require('./handlers') const handlers = require('./handlers')
var EXE_NAME = path.basename(process.execPath) const EXE_NAME = path.basename(process.execPath)
var UPDATE_EXE = path.join(process.execPath, '..', '..', 'Update.exe') const UPDATE_EXE = path.join(process.execPath, '..', '..', 'Update.exe')
function handleEvent (cmd) { function handleEvent (cmd) {
if (cmd === '--squirrel-install') { if (cmd === '--squirrel-install') {
@@ -73,9 +73,9 @@ function handleEvent (cmd) {
* the output from standard out. * the output from standard out.
*/ */
function spawn (command, args, cb) { function spawn (command, args, cb) {
var stdout = '' let stdout = ''
let error = null
var child let child = null
try { try {
child = cp.spawn(command, args) child = cp.spawn(command, args)
} catch (err) { } catch (err) {
@@ -90,10 +90,10 @@ function spawn (command, args, cb) {
stdout += data stdout += data
}) })
var error = null
child.on('error', function (processError) { child.on('error', function (processError) {
error = processError error = processError
}) })
child.on('close', function (code, signal) { child.on('close', function (code, signal) {
if (code !== 0 && !error) error = new Error('Command failed: #{signal || code}') if (code !== 0 && !error) error = new Error('Command failed: #{signal || code}')
if (error) error.stdout = stdout if (error) error.stdout = stdout
@@ -122,12 +122,12 @@ function createShortcuts (cb) {
* command. * command.
*/ */
function updateShortcuts (cb) { function updateShortcuts (cb) {
var homeDir = os.homedir() const homeDir = os.homedir()
if (homeDir) { if (homeDir) {
var desktopShortcutPath = path.join(homeDir, 'Desktop', 'WebTorrent.lnk') const desktopShortcutPath = path.join(homeDir, 'Desktop', 'WebTorrent.lnk')
// If the desktop shortcut was deleted by the user, then keep it deleted. // If the desktop shortcut was deleted by the user, then keep it deleted.
fs.access(desktopShortcutPath, function (err) { fs.access(desktopShortcutPath, function (err) {
var desktopShortcutExists = !err const desktopShortcutExists = !err
createShortcuts(function () { createShortcuts(function () {
if (desktopShortcutExists) { if (desktopShortcutExists) {
cb() cb()

View File

@@ -12,10 +12,10 @@ module.exports = {
* or activating the window. * or activating the window.
*/ */
var path = require('path') const path = require('path')
var config = require('../config') const config = require('../config')
var windows = require('./windows') const windows = require('./windows')
const PREV_ICON = path.join(config.STATIC_PATH, 'PreviousTrackThumbnailBarButton.png') const PREV_ICON = path.join(config.STATIC_PATH, 'PreviousTrackThumbnailBarButton.png')
const PLAY_ICON = path.join(config.STATIC_PATH, 'PlayThumbnailBarButton.png') const PLAY_ICON = path.join(config.STATIC_PATH, 'PlayThumbnailBarButton.png')
@@ -27,7 +27,7 @@ const PREV = 0
const PLAY_PAUSE = 1 const PLAY_PAUSE = 1
const NEXT = 2 const NEXT = 2
var buttons = [] let buttons = []
/** /**
* Show the Windows thumbnail toolbar buttons. * Show the Windows thumbnail toolbar buttons.

View File

@@ -4,14 +4,14 @@ module.exports = {
setWindowFocus setWindowFocus
} }
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
var config = require('../config') const config = require('../config')
var windows = require('./windows') const windows = require('./windows')
var tray let tray
function init () { function init () {
if (process.platform === 'linux') { if (process.platform === 'linux') {
@@ -49,7 +49,7 @@ function initWin32 () {
* Check for libappindicator1 support before creating tray icon * Check for libappindicator1 support before creating tray icon
*/ */
function checkLinuxTraySupport (cb) { function checkLinuxTraySupport (cb) {
var cp = require('child_process') const cp = require('child_process')
// Check that we're on Ubuntu (or another debian system) and that we have // Check that we're on Ubuntu (or another debian system) and that we have
// libappindicator1. If WebTorrent was installed from the deb file, we should // libappindicator1. If WebTorrent was installed from the deb file, we should
@@ -74,7 +74,7 @@ function createTray () {
} }
function updateTrayMenu () { function updateTrayMenu () {
var contextMenu = electron.Menu.buildFromTemplate(getMenuTemplate()) const contextMenu = electron.Menu.buildFromTemplate(getMenuTemplate())
tray.setContextMenu(contextMenu) tray.setContextMenu(contextMenu)
} }

View File

@@ -2,14 +2,14 @@ module.exports = {
init init
} }
var electron = require('electron') const electron = require('electron')
var get = require('simple-get') const get = require('simple-get')
var config = require('../config') const config = require('../config')
var log = require('./log') const log = require('./log')
var windows = require('./windows') const windows = require('./windows')
var AUTO_UPDATE_URL = config.AUTO_UPDATE_URL + const AUTO_UPDATE_URL = config.AUTO_UPDATE_URL +
'?version=' + config.APP_VERSION + '?version=' + config.APP_VERSION +
'&platform=' + process.platform '&platform=' + process.platform

View File

@@ -2,9 +2,9 @@ module.exports = {
init init
} }
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
/** /**
* Add a user task menu to the app icon on right-click. (Windows) * Add a user task menu to the app icon on right-click. (Windows)

View File

@@ -1,17 +1,17 @@
var about = module.exports = { const about = module.exports = {
init, init,
win: null win: null
} }
var config = require('../../config') const config = require('../../config')
var electron = require('electron') const electron = require('electron')
function init () { function init () {
if (about.win) { if (about.win) {
return about.win.show() return about.win.show()
} }
var win = about.win = new electron.BrowserWindow({ const win = about.win = new electron.BrowserWindow({
backgroundColor: '#ECECEC', backgroundColor: '#ECECEC',
center: true, center: true,
fullscreen: false, fullscreen: false,

View File

@@ -1,4 +1,4 @@
var main = module.exports = { const main = module.exports = {
dispatch, dispatch,
hide, hide,
init, init,
@@ -14,23 +14,23 @@ var main = module.exports = {
win: null win: null
} }
var electron = require('electron') const electron = require('electron')
var app = electron.app const app = electron.app
var config = require('../../config') const config = require('../../config')
var log = require('../log') const log = require('../log')
var menu = require('../menu') const menu = require('../menu')
var tray = require('../tray') const tray = require('../tray')
var HEADER_HEIGHT = 38 const HEADER_HEIGHT = 38
var TORRENT_HEIGHT = 100 const TORRENT_HEIGHT = 100
function init () { function init () {
if (main.win) { if (main.win) {
return main.win.show() return main.win.show()
} }
var win = main.win = new electron.BrowserWindow({ const win = main.win = new electron.BrowserWindow({
backgroundColor: '#282828', backgroundColor: '#282828',
darkTheme: true, // Forces dark theme (GTK+3) darkTheme: true, // Forces dark theme (GTK+3)
icon: getIconPath(), // Window icon (Windows, Linux) icon: getIconPath(), // Window icon (Windows, Linux)
@@ -114,7 +114,7 @@ function setBounds (bounds, maximize) {
} }
// Maximize or minimize, if the second argument is present // Maximize or minimize, if the second argument is present
var willBeMaximized let willBeMaximized
if (maximize === true) { if (maximize === true) {
if (!main.win.isMaximized()) { if (!main.win.isMaximized()) {
log('setBounds: maximizing') log('setBounds: maximizing')
@@ -136,7 +136,7 @@ function setBounds (bounds, maximize) {
log('setBounds: setting bounds to ' + JSON.stringify(bounds)) log('setBounds: setting bounds to ' + JSON.stringify(bounds))
if (bounds.x === null && bounds.y === null) { if (bounds.x === null && bounds.y === null) {
// X and Y not specified? By default, center on current screen // X and Y not specified? By default, center on current screen
var scr = electron.screen.getDisplayMatching(main.win.getBounds()) const scr = electron.screen.getDisplayMatching(main.win.getBounds())
bounds.x = Math.round(scr.bounds.x + scr.bounds.width / 2 - bounds.width / 2) bounds.x = Math.round(scr.bounds.x + scr.bounds.width / 2 - bounds.width / 2)
bounds.y = Math.round(scr.bounds.y + scr.bounds.height / 2 - bounds.height / 2) bounds.y = Math.round(scr.bounds.y + scr.bounds.height / 2 - bounds.height / 2)
log('setBounds: centered to ' + JSON.stringify(bounds)) log('setBounds: centered to ' + JSON.stringify(bounds))

View File

@@ -1,4 +1,4 @@
var webtorrent = module.exports = { const webtorrent = module.exports = {
init, init,
send, send,
show, show,
@@ -6,13 +6,13 @@ var webtorrent = module.exports = {
win: null win: null
} }
var electron = require('electron') const electron = require('electron')
var config = require('../../config') const config = require('../../config')
var log = require('../log') const log = require('../log')
function init () { function init () {
var win = webtorrent.win = new electron.BrowserWindow({ const win = webtorrent.win = new electron.BrowserWindow({
backgroundColor: '#1E1E1E', backgroundColor: '#1E1E1E',
center: true, center: true,
fullscreen: false, fullscreen: false,

View File

@@ -4,7 +4,7 @@ const {dispatcher} = require('../lib/dispatcher')
class Header extends React.Component { class Header extends React.Component {
render () { render () {
var loc = this.props.state.location const loc = this.props.state.location
return ( return (
<div className='header'> <div className='header'>
{this.getTitle()} {this.getTitle()}
@@ -31,12 +31,12 @@ class Header extends React.Component {
getTitle () { getTitle () {
if (process.platform !== 'darwin') return null if (process.platform !== 'darwin') return null
var state = this.props.state const state = this.props.state
return (<div className='title ellipsis'>{state.window.title}</div>) return (<div className='title ellipsis'>{state.window.title}</div>)
} }
getAddButton () { getAddButton () {
var state = this.props.state const state = this.props.state
if (state.location.url() !== 'home') return null if (state.location.url() !== 'home') return null
return ( return (
<i <i

View File

@@ -29,7 +29,7 @@ class PathSelector extends React.Component {
} }
handleClick () { handleClick () {
var opts = Object.assign({ const opts = Object.assign({
defaultPath: this.props.value, defaultPath: this.props.value,
properties: [ 'openFile', 'openDirectory' ] properties: [ 'openFile', 'openDirectory' ]
}, this.props.dialog) }, this.props.dialog)

View File

@@ -4,11 +4,11 @@ const {dispatch, dispatcher} = require('../lib/dispatcher')
module.exports = class RemoveTorrentModal extends React.Component { module.exports = class RemoveTorrentModal extends React.Component {
render () { render () {
var state = this.props.state const state = this.props.state
var message = state.modal.deleteData const message = state.modal.deleteData
? 'Are you sure you want to remove this torrent from the list and delete the data file?' ? 'Are you sure you want to remove this torrent from the list and delete the data file?'
: 'Are you sure you want to remove this torrent from the list?' : 'Are you sure you want to remove this torrent from the list?'
var buttonText = state.modal.deleteData ? 'Remove Data' : 'Remove' const buttonText = state.modal.deleteData ? 'Remove Data' : 'Remove'
return ( return (
<div> <div>

View File

@@ -6,20 +6,20 @@ const {dispatcher} = require('../lib/dispatcher')
module.exports = class UnsupportedMediaModal extends React.Component { module.exports = class UnsupportedMediaModal extends React.Component {
render () { render () {
var state = this.props.state const state = this.props.state
var err = state.modal.error const err = state.modal.error
var message = (err && err.getMessage) const message = (err && err.getMessage)
? err.getMessage() ? err.getMessage()
: err : err
var playerPath = state.saved.prefs.externalPlayerPath const playerPath = state.saved.prefs.externalPlayerPath
var playerName = playerPath const playerName = playerPath
? path.basename(playerPath).split('.')[0] ? path.basename(playerPath).split('.')[0]
: 'VLC' : 'VLC'
var onPlay = dispatcher('openExternalPlayer') const onPlay = dispatcher('openExternalPlayer')
var actionButton = state.modal.externalPlayerInstalled const actionButton = state.modal.externalPlayerInstalled
? (<button className='button-raised' onClick={onPlay}>Play in {playerName}</button>) ? (<button className='button-raised' onClick={onPlay}>Play in {playerName}</button>)
: (<button className='button-raised' onClick={() => this.onInstall()}>Install VLC</button>) : (<button className='button-raised' onClick={() => this.onInstall()}>Install VLC</button>)
var playerMessage = state.modal.externalPlayerNotFound const playerMessage = state.modal.externalPlayerNotFound
? 'Couldn\'t run external player. Please make sure it\'s installed.' ? 'Couldn\'t run external player. Please make sure it\'s installed.'
: '' : ''
return ( return (
@@ -39,7 +39,7 @@ module.exports = class UnsupportedMediaModal extends React.Component {
electron.shell.openExternal('http://www.videolan.org/vlc/') electron.shell.openExternal('http://www.videolan.org/vlc/')
// TODO: dcposch send a dispatch rather than modifying state directly // TODO: dcposch send a dispatch rather than modifying state directly
var state = this.props.state const state = this.props.state
state.modal.externalPlayerInstalled = true // Assume they'll install it successfully state.modal.externalPlayerInstalled = true // Assume they'll install it successfully
} }
} }

View File

@@ -5,7 +5,7 @@ const {dispatch} = require('../lib/dispatcher')
module.exports = class UpdateAvailableModal extends React.Component { module.exports = class UpdateAvailableModal extends React.Component {
render () { render () {
var state = this.props.state const state = this.props.state
return ( return (
<div className='update-available-modal'> <div className='update-available-modal'>
<p><strong>A new version of WebTorrent is available: v{state.modal.version}</strong></p> <p><strong>A new version of WebTorrent is available: v{state.modal.version}</strong></p>

View File

@@ -20,7 +20,7 @@ module.exports = class MediaController {
} }
mediaError (error) { mediaError (error) {
var state = this.state const state = this.state
if (state.location.url() === 'player') { if (state.location.url() === 'player') {
state.playing.result = 'error' state.playing.result = 'error'
state.playing.location = 'error' state.playing.location = 'error'
@@ -45,8 +45,8 @@ module.exports = class MediaController {
} }
openExternalPlayer () { openExternalPlayer () {
var state = this.state const state = this.state
var mediaURL = Playlist.getCurrentLocalURL(this.state) const mediaURL = Playlist.getCurrentLocalURL(this.state)
ipcRenderer.send('openExternalPlayer', ipcRenderer.send('openExternalPlayer',
state.saved.prefs.externalPlayerPath, state.saved.prefs.externalPlayerPath,
mediaURL, mediaURL,
@@ -55,7 +55,7 @@ module.exports = class MediaController {
} }
externalPlayerNotFound () { externalPlayerNotFound () {
var modal = this.state.modal const modal = this.state.modal
if (modal && modal.id === 'unsupported-media-modal') { if (modal && modal.id === 'unsupported-media-modal') {
modal.externalPlayerNotFound = true modal.externalPlayerNotFound = true
} }

View File

@@ -27,7 +27,7 @@ module.exports = class PlaybackController {
// * Stream, if not already fully downloaded // * Stream, if not already fully downloaded
// * If no file index is provided, restore the most recently viewed file or autoplay the first // * If no file index is provided, restore the most recently viewed file or autoplay the first
playFile (infoHash, index /* optional */) { playFile (infoHash, index /* optional */) {
var state = this.state const state = this.state
if (state.location.url() === 'player') { if (state.location.url() === 'player') {
this.updatePlayer(infoHash, index, false, (err) => { this.updatePlayer(infoHash, index, false, (err) => {
if (err) dispatch('error', err) if (err) dispatch('error', err)
@@ -52,8 +52,8 @@ module.exports = class PlaybackController {
// Open a file in OS default app. // Open a file in OS default app.
openItem (infoHash, index) { openItem (infoHash, index) {
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash) const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
var filePath = path.join( const filePath = path.join(
torrentSummary.path, torrentSummary.path,
torrentSummary.files[index].path) torrentSummary.files[index].path)
ipcRenderer.send('openItem', filePath) ipcRenderer.send('openItem', filePath)
@@ -61,12 +61,12 @@ module.exports = class PlaybackController {
// Toggle (play or pause) the currently playing media // Toggle (play or pause) the currently playing media
playPause () { playPause () {
var state = this.state const state = this.state
if (state.location.url() !== 'player') return if (state.location.url() !== 'player') return
// force rerendering if window is hidden, // force rerendering if window is hidden,
// in order to bypass `raf` and play/pause media immediately // in order to bypass `raf` and play/pause media immediately
var mediaTag = document.querySelector('video,audio') const mediaTag = document.querySelector('video,audio')
if (!state.window.isVisible && mediaTag) { if (!state.window.isVisible && mediaTag) {
if (state.playing.isPaused) mediaTag.play() if (state.playing.isPaused) mediaTag.play()
else mediaTag.pause() else mediaTag.pause()
@@ -78,7 +78,7 @@ module.exports = class PlaybackController {
// Play next file in list (if any) // Play next file in list (if any)
nextTrack () { nextTrack () {
var state = this.state const state = this.state
if (Playlist.hasNext(state)) { if (Playlist.hasNext(state)) {
this.updatePlayer( this.updatePlayer(
state.playing.infoHash, Playlist.getNextIndex(state), false, (err) => { state.playing.infoHash, Playlist.getNextIndex(state), false, (err) => {
@@ -90,7 +90,7 @@ module.exports = class PlaybackController {
// Play previous track in list (if any) // Play previous track in list (if any)
previousTrack () { previousTrack () {
var state = this.state const state = this.state
if (Playlist.hasPrevious(state)) { if (Playlist.hasPrevious(state)) {
this.updatePlayer( this.updatePlayer(
state.playing.infoHash, Playlist.getPreviousIndex(state), false, (err) => { state.playing.infoHash, Playlist.getPreviousIndex(state), false, (err) => {
@@ -102,7 +102,7 @@ module.exports = class PlaybackController {
// Play (unpause) the current media // Play (unpause) the current media
play () { play () {
var state = this.state const state = this.state
if (!state.playing.isPaused) return if (!state.playing.isPaused) return
state.playing.isPaused = false state.playing.isPaused = false
if (isCasting(state)) { if (isCasting(state)) {
@@ -113,7 +113,7 @@ module.exports = class PlaybackController {
// Pause the currently playing media // Pause the currently playing media
pause () { pause () {
var state = this.state const state = this.state
if (state.playing.isPaused) return if (state.playing.isPaused) return
state.playing.isPaused = true state.playing.isPaused = true
if (isCasting(state)) { if (isCasting(state)) {
@@ -142,8 +142,8 @@ module.exports = class PlaybackController {
// to 0.25 (quarter-speed playback), then goes to -0.25, -0.5, -1, -2, etc // to 0.25 (quarter-speed playback), then goes to -0.25, -0.5, -1, -2, etc
// until -16 (fast rewind) // until -16 (fast rewind)
changePlaybackRate (direction) { changePlaybackRate (direction) {
var state = this.state const state = this.state
var rate = state.playing.playbackRate let rate = state.playing.playbackRate
if (direction > 0 && rate >= 0.25 && rate < 2) { if (direction > 0 && rate >= 0.25 && rate < 2) {
rate += 0.25 rate += 0.25
} else if (direction < 0 && rate > 0.25 && rate <= 2) { } else if (direction < 0 && rate > 0.25 && rate <= 2) {
@@ -178,7 +178,7 @@ module.exports = class PlaybackController {
// check if its in [0.0 - 1.0] range // check if its in [0.0 - 1.0] range
volume = Math.max(0, Math.min(1, volume)) volume = Math.max(0, Math.min(1, volume))
var state = this.state const state = this.state
if (isCasting(state)) { if (isCasting(state)) {
Cast.setVolume(volume) Cast.setVolume(volume)
} else { } else {
@@ -192,8 +192,8 @@ module.exports = class PlaybackController {
// * The video is paused // * The video is paused
// * The video is playing remotely on Chromecast or Airplay // * The video is playing remotely on Chromecast or Airplay
showOrHidePlayerControls () { showOrHidePlayerControls () {
var state = this.state const state = this.state
var hideControls = state.location.url() === 'player' && const hideControls = state.location.url() === 'player' &&
state.playing.mouseStationarySince !== 0 && state.playing.mouseStationarySince !== 0 &&
new Date().getTime() - state.playing.mouseStationarySince > 2000 && new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
!state.playing.isPaused && !state.playing.isPaused &&
@@ -208,9 +208,8 @@ module.exports = class PlaybackController {
// Opens the video player to a specific torrent // Opens the video player to a specific torrent
openPlayer (infoHash, index, cb) { openPlayer (infoHash, index, cb) {
var state = this.state const state = this.state
const torrentSummary = TorrentSummary.getByKey(state, infoHash)
var torrentSummary = TorrentSummary.getByKey(state, infoHash)
if (index === undefined) index = torrentSummary.mostRecentFileIndex if (index === undefined) index = torrentSummary.mostRecentFileIndex
if (index === undefined) index = torrentSummary.files.findIndex(TorrentPlayer.isPlayable) if (index === undefined) index = torrentSummary.files.findIndex(TorrentPlayer.isPlayable)
@@ -224,7 +223,7 @@ module.exports = class PlaybackController {
torrentSummary.playStatus = 'requested' torrentSummary.playStatus = 'requested'
this.update() this.update()
var timeout = setTimeout(() => { const timeout = setTimeout(() => {
telemetry.logPlayAttempt('timeout') telemetry.logPlayAttempt('timeout')
// TODO: remove torrentSummary.playStatus // TODO: remove torrentSummary.playStatus
torrentSummary.playStatus = 'timeout' /* no seeders available? */ torrentSummary.playStatus = 'timeout' /* no seeders available? */
@@ -237,7 +236,7 @@ module.exports = class PlaybackController {
clearTimeout(timeout) clearTimeout(timeout)
// if we timed out (user clicked play a long time ago), don't autoplay // if we timed out (user clicked play a long time ago), don't autoplay
var timedOut = torrentSummary.playStatus === 'timeout' const timedOut = torrentSummary.playStatus === 'timeout'
delete torrentSummary.playStatus delete torrentSummary.playStatus
if (timedOut) { if (timedOut) {
ipcRenderer.send('wt-stop-server') ipcRenderer.send('wt-stop-server')
@@ -267,10 +266,10 @@ module.exports = class PlaybackController {
// Called each time the current file changes // Called each time the current file changes
updatePlayer (infoHash, index, resume, cb) { updatePlayer (infoHash, index, resume, cb) {
var state = this.state const state = this.state
var torrentSummary = TorrentSummary.getByKey(state, infoHash) const torrentSummary = TorrentSummary.getByKey(state, infoHash)
var fileSummary = torrentSummary.files[index] const fileSummary = torrentSummary.files[index]
if (!TorrentPlayer.isPlayable(fileSummary)) { if (!TorrentPlayer.isPlayable(fileSummary)) {
torrentSummary.mostRecentFileIndex = undefined torrentSummary.mostRecentFileIndex = undefined
@@ -280,16 +279,17 @@ module.exports = class PlaybackController {
torrentSummary.mostRecentFileIndex = index torrentSummary.mostRecentFileIndex = index
// update state // update state
state.playing.infoHash = infoHash
state.playing.fileIndex = index state.playing.fileIndex = index
state.playing.type = TorrentPlayer.isVideo(fileSummary) ? 'video' state.playing.type = TorrentPlayer.isVideo(fileSummary) ? 'video'
: TorrentPlayer.isAudio(fileSummary) ? 'audio' : TorrentPlayer.isAudio(fileSummary) ? 'audio'
: 'other' : 'other'
// pick up where we left off // pick up where we left off
var jumpToTime = 0 let jumpToTime = 0
if (resume && fileSummary.currentTime) { if (resume && fileSummary.currentTime) {
var fraction = fileSummary.currentTime / fileSummary.duration const fraction = fileSummary.currentTime / fileSummary.duration
var secondsLeft = fileSummary.duration - fileSummary.currentTime const secondsLeft = fileSummary.duration - fileSummary.currentTime
if (fraction < 0.9 && secondsLeft > 10) { if (fraction < 0.9 && secondsLeft > 10) {
jumpToTime = fileSummary.currentTime jumpToTime = fileSummary.currentTime
} }
@@ -330,7 +330,7 @@ module.exports = class PlaybackController {
console.log('closePlayer') console.log('closePlayer')
// Quit any external players, like Chromecast/Airplay/etc or VLC // Quit any external players, like Chromecast/Airplay/etc or VLC
var state = this.state const state = this.state
if (isCasting(state)) { if (isCasting(state)) {
Cast.stop() Cast.stop()
} }
@@ -342,7 +342,7 @@ module.exports = class PlaybackController {
state.previousVolume = state.playing.volume state.previousVolume = state.playing.volume
// Telemetry: track what happens after the user clicks play // Telemetry: track what happens after the user clicks play
var result = state.playing.result // 'success' or 'error' const result = state.playing.result // 'success' or 'error'
if (result === 'success') telemetry.logPlayAttempt('success') // first frame displayed if (result === 'success') telemetry.logPlayAttempt('success') // first frame displayed
else if (result === 'error') telemetry.logPlayAttempt('error') // codec missing, etc else if (result === 'error') telemetry.logPlayAttempt('error') // codec missing, etc
else if (result === undefined) telemetry.logPlayAttempt('abandoned') // user gave up waiting else if (result === undefined) telemetry.logPlayAttempt('abandoned') // user gave up waiting

View File

@@ -11,7 +11,7 @@ module.exports = class PrefsController {
// Goes to the Preferences screen // Goes to the Preferences screen
show () { show () {
var state = this.state const state = this.state
state.location.go({ state.location.go({
url: 'preferences', url: 'preferences',
setup: function (cb) { setup: function (cb) {
@@ -32,20 +32,21 @@ module.exports = class PrefsController {
// For example: updatePreferences('foo.bar', 'baz') // For example: updatePreferences('foo.bar', 'baz')
// Call save() to save to config.json // Call save() to save to config.json
update (property, value) { update (property, value) {
var path = property.split('.') const path = property.split('.')
var key = this.state.unsaved.prefs let obj = this.state.unsaved.prefs
for (var i = 0; i < path.length - 1; i++) { let i
if (typeof key[path[i]] === 'undefined') { for (i = 0; i < path.length - 1; i++) {
key[path[i]] = {} if (typeof obj[path[i]] === 'undefined') {
obj[path[i]] = {}
} }
key = key[path[i]] obj = obj[path[i]]
} }
key[path[i]] = value obj[path[i]] = value
} }
// All unsaved prefs take effect atomically, and are saved to config.json // All unsaved prefs take effect atomically, and are saved to config.json
save () { save () {
var state = this.state const state = this.state
if (state.unsaved.prefs.isFileHandler !== state.saved.prefs.isFileHandler) { if (state.unsaved.prefs.isFileHandler !== state.saved.prefs.isFileHandler) {
ipcRenderer.send('setDefaultFileHandler', state.unsaved.prefs.isFileHandler) ipcRenderer.send('setDefaultFileHandler', state.unsaved.prefs.isFileHandler)
} }

View File

@@ -28,26 +28,26 @@ module.exports = class SubtitlesController {
} }
toggleSubtitlesMenu () { toggleSubtitlesMenu () {
var subtitles = this.state.playing.subtitles const subtitles = this.state.playing.subtitles
subtitles.showMenu = !subtitles.showMenu subtitles.showMenu = !subtitles.showMenu
} }
addSubtitles (files, autoSelect) { addSubtitles (files, autoSelect) {
var state = this.state const state = this.state
// Subtitles are only supported when playing video files // Subtitles are only supported when playing video files
if (state.playing.type !== 'video') return if (state.playing.type !== 'video') return
if (files.length === 0) return if (files.length === 0) return
var subtitles = state.playing.subtitles const subtitles = state.playing.subtitles
// Read the files concurrently, then add all resulting subtitle tracks // Read the files concurrently, then add all resulting subtitle tracks
var tasks = files.map((file) => (cb) => loadSubtitle(file, cb)) const tasks = files.map((file) => (cb) => loadSubtitle(file, cb))
parallel(tasks, function (err, tracks) { parallel(tasks, function (err, tracks) {
if (err) return dispatch('error', err) if (err) return dispatch('error', err)
for (var i = 0; i < tracks.length; i++) { for (let i = 0; i < tracks.length; i++) {
// No dupes allowed // No dupes allowed
var track = tracks[i] const track = tracks[i]
var trackIndex = state.playing.subtitles.tracks let trackIndex = state.playing.subtitles.tracks
.findIndex((t) => track.filePath === t.filePath) .findIndex((t) => track.filePath === t.filePath)
// Add the track // Add the track
@@ -68,46 +68,46 @@ module.exports = class SubtitlesController {
checkForSubtitles () { checkForSubtitles () {
if (this.state.playing.type !== 'video') return if (this.state.playing.type !== 'video') return
var torrentSummary = this.state.getPlayingTorrentSummary() const torrentSummary = this.state.getPlayingTorrentSummary()
if (!torrentSummary || !torrentSummary.progress) return if (!torrentSummary || !torrentSummary.progress) return
torrentSummary.progress.files.forEach((fp, ix) => { torrentSummary.progress.files.forEach((fp, ix) => {
if (fp.numPieces !== fp.numPiecesPresent) return // ignore incomplete files if (fp.numPieces !== fp.numPiecesPresent) return // ignore incomplete files
var file = torrentSummary.files[ix] const file = torrentSummary.files[ix]
if (!this.isSubtitle(file.name)) return if (!this.isSubtitle(file.name)) return
var filePath = path.join(torrentSummary.path, file.path) const filePath = path.join(torrentSummary.path, file.path)
this.addSubtitles([filePath], false) this.addSubtitles([filePath], false)
}) })
} }
isSubtitle (file) { isSubtitle (file) {
var name = typeof file === 'string' ? file : file.name const name = typeof file === 'string' ? file : file.name
var ext = path.extname(name).toLowerCase() const ext = path.extname(name).toLowerCase()
return ext === '.srt' || ext === '.vtt' return ext === '.srt' || ext === '.vtt'
} }
} }
function loadSubtitle (file, cb) { function loadSubtitle (file, cb) {
// Lazy load to keep startup fast // Lazy load to keep startup fast
var concat = require('simple-concat') const concat = require('simple-concat')
var LanguageDetect = require('languagedetect') const LanguageDetect = require('languagedetect')
var srtToVtt = require('srt-to-vtt') const srtToVtt = require('srt-to-vtt')
// Read the .SRT or .VTT file, parse it, add subtitle track // Read the .SRT or .VTT file, parse it, add subtitle track
var filePath = file.path || file const filePath = file.path || file
var vttStream = fs.createReadStream(filePath).pipe(srtToVtt()) const vttStream = fs.createReadStream(filePath).pipe(srtToVtt())
concat(vttStream, function (err, buf) { concat(vttStream, function (err, buf) {
if (err) return dispatch('error', 'Can\'t parse subtitles file.') if (err) return dispatch('error', 'Can\'t parse subtitles file.')
// Detect what language the subtitles are in // Detect what language the subtitles are in
var vttContents = buf.toString().replace(/(.*-->.*)/g, '') const vttContents = buf.toString().replace(/(.*-->.*)/g, '')
var langDetected = (new LanguageDetect()).detect(vttContents, 2) let 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 track = { const track = {
buffer: 'data:text/vtt;base64,' + buf.toString('base64'), buffer: 'data:text/vtt;base64,' + buf.toString('base64'),
language: langDetected, language: langDetected,
label: langDetected, label: langDetected,
@@ -121,18 +121,18 @@ function loadSubtitle (file, cb) {
// Checks whether a language name like 'English' or 'German' matches the system // Checks whether a language name like 'English' or 'German' matches the system
// language, aka the current locale // language, aka the current locale
function isSystemLanguage (language) { function isSystemLanguage (language) {
var iso639 = require('iso-639-1') const iso639 = require('iso-639-1')
var osLangISO = window.navigator.language.split('-')[0] // eg 'en' const osLangISO = window.navigator.language.split('-')[0] // eg 'en'
var langIso = iso639.getCode(language) // eg 'de' if language is 'German' const langIso = iso639.getCode(language) // eg 'de' if language is 'German'
return langIso === osLangISO return langIso === osLangISO
} }
// Make sure we don't have two subtitle tracks with the same label // Make sure we don't have two subtitle tracks with the same label
// Labels each track by language, eg 'German', 'English', 'English 2', ... // Labels each track by language, eg 'German', 'English', 'English 2', ...
function relabelSubtitles (subtitles) { function relabelSubtitles (subtitles) {
var counts = {} const counts = {}
subtitles.tracks.forEach(function (track) { subtitles.tracks.forEach(function (track) {
var lang = track.language const lang = track.language
counts[lang] = (counts[lang] || 0) + 1 counts[lang] = (counts[lang] || 0) + 1
track.label = counts[lang] > 1 ? (lang + ' ' + counts[lang]) : lang track.label = counts[lang] > 1 ? (lang + ' ' + counts[lang]) : lang
}) })

View File

@@ -11,12 +11,12 @@ module.exports = class TorrentController {
} }
torrentInfoHash (torrentKey, infoHash) { torrentInfoHash (torrentKey, infoHash) {
var torrentSummary = this.getTorrentSummary(torrentKey) let torrentSummary = this.getTorrentSummary(torrentKey)
console.log('got infohash for %s torrent %s', console.log('got infohash for %s torrent %s',
torrentSummary ? 'existing' : 'new', torrentKey) torrentSummary ? 'existing' : 'new', torrentKey)
if (!torrentSummary) { if (!torrentSummary) {
var torrents = this.state.saved.torrents const torrents = this.state.saved.torrents
// Check if an existing (non-active) torrent has the same info hash // Check if an existing (non-active) torrent has the same info hash
if (torrents.find((t) => t.infoHash === infoHash)) { if (torrents.find((t) => t.infoHash === infoHash)) {
@@ -48,7 +48,7 @@ module.exports = class TorrentController {
} }
dispatch('error', message) dispatch('error', message)
var torrentSummary = this.getTorrentSummary(torrentKey) const torrentSummary = this.getTorrentSummary(torrentKey)
if (torrentSummary) { if (torrentSummary) {
console.log('Pausing torrent %s due to error: %s', torrentSummary.infoHash, message) console.log('Pausing torrent %s due to error: %s', torrentSummary.infoHash, message)
torrentSummary.status = 'paused' torrentSummary.status = 'paused'
@@ -58,14 +58,14 @@ module.exports = class TorrentController {
torrentMetadata (torrentKey, torrentInfo) { torrentMetadata (torrentKey, torrentInfo) {
// Summarize torrent // Summarize torrent
var torrentSummary = this.getTorrentSummary(torrentKey) const torrentSummary = this.getTorrentSummary(torrentKey)
torrentSummary.status = 'downloading' torrentSummary.status = 'downloading'
torrentSummary.name = torrentSummary.displayName || torrentInfo.name torrentSummary.name = torrentSummary.displayName || torrentInfo.name
torrentSummary.path = torrentInfo.path torrentSummary.path = torrentInfo.path
torrentSummary.magnetURI = torrentInfo.magnetURI torrentSummary.magnetURI = torrentInfo.magnetURI
// TODO: make torrentInfo immutable, save separately as torrentSummary.info // TODO: make torrentInfo immutable, save separately as torrentSummary.info
// For now, check whether torrentSummary.files has already been set: // For now, check whether torrentSummary.files has already been set:
var hasDetailedFileInfo = torrentSummary.files && torrentSummary.files[0].path const hasDetailedFileInfo = torrentSummary.files && torrentSummary.files[0].path
if (!hasDetailedFileInfo) { if (!hasDetailedFileInfo) {
torrentSummary.files = torrentInfo.files torrentSummary.files = torrentInfo.files
} }
@@ -83,7 +83,7 @@ module.exports = class TorrentController {
torrentDone (torrentKey, torrentInfo) { torrentDone (torrentKey, torrentInfo) {
// Update the torrent summary // Update the torrent summary
var torrentSummary = this.getTorrentSummary(torrentKey) const torrentSummary = this.getTorrentSummary(torrentKey)
torrentSummary.status = 'seeding' torrentSummary.status = 'seeding'
// Notify the user that a torrent finished, but only if we actually DL'd at least part of it. // Notify the user that a torrent finished, but only if we actually DL'd at least part of it.
@@ -100,22 +100,18 @@ module.exports = class TorrentController {
} }
torrentProgress (progressInfo) { torrentProgress (progressInfo) {
// Overall progress across all active torrents, 0 to 1 // Overall progress across all active torrents, 0 to 1, or -1 to hide the progress bar
var progress = progressInfo.progress
var hasActiveTorrents = progressInfo.hasActiveTorrents
// Hide progress bar when client has no torrents, or progress is 100% // Hide progress bar when client has no torrents, or progress is 100%
// TODO: isn't this equivalent to: if (progress === 1) ? const progress = (!progressInfo.hasActiveTorrents || progressInfo.progress === 1)
if (!hasActiveTorrents || progress === 1) { ? -1
progress = -1 : progressInfo.progress
}
// Show progress bar under the WebTorrent taskbar icon, on OSX // Show progress bar under the WebTorrent taskbar icon, on OSX
this.state.dock.progress = progress this.state.dock.progress = progress
// Update progress for each individual torrent // Update progress for each individual torrent
progressInfo.torrents.forEach((p) => { progressInfo.torrents.forEach((p) => {
var torrentSummary = this.getTorrentSummary(p.torrentKey) const torrentSummary = this.getTorrentSummary(p.torrentKey)
if (!torrentSummary) { if (!torrentSummary) {
console.log('warning: got progress for missing torrent %s', p.torrentKey) console.log('warning: got progress for missing torrent %s', p.torrentKey)
return return
@@ -130,27 +126,27 @@ module.exports = class TorrentController {
} }
torrentFileModtimes (torrentKey, fileModtimes) { torrentFileModtimes (torrentKey, fileModtimes) {
var torrentSummary = this.getTorrentSummary(torrentKey) const torrentSummary = this.getTorrentSummary(torrentKey)
torrentSummary.fileModtimes = fileModtimes torrentSummary.fileModtimes = fileModtimes
dispatch('saveStateThrottled') dispatch('saveStateThrottled')
} }
torrentFileSaved (torrentKey, torrentFileName) { torrentFileSaved (torrentKey, torrentFileName) {
console.log('torrent file saved %s: %s', torrentKey, torrentFileName) console.log('torrent file saved %s: %s', torrentKey, torrentFileName)
var torrentSummary = this.getTorrentSummary(torrentKey) const torrentSummary = this.getTorrentSummary(torrentKey)
torrentSummary.torrentFileName = torrentFileName torrentSummary.torrentFileName = torrentFileName
dispatch('saveStateThrottled') dispatch('saveStateThrottled')
} }
torrentPosterSaved (torrentKey, posterFileName) { torrentPosterSaved (torrentKey, posterFileName) {
var torrentSummary = this.getTorrentSummary(torrentKey) const torrentSummary = this.getTorrentSummary(torrentKey)
torrentSummary.posterFileName = posterFileName torrentSummary.posterFileName = posterFileName
dispatch('saveStateThrottled') dispatch('saveStateThrottled')
} }
torrentAudioMetadata (infoHash, index, info) { torrentAudioMetadata (infoHash, index, info) {
var torrentSummary = this.getTorrentSummary(infoHash) const torrentSummary = this.getTorrentSummary(infoHash)
var fileSummary = torrentSummary.files[index] const fileSummary = torrentSummary.files[index]
fileSummary.audioInfo = info fileSummary.audioInfo = info
dispatch('update') dispatch('update')
} }
@@ -167,7 +163,7 @@ module.exports = class TorrentController {
} }
function getTorrentPath (torrentSummary) { function getTorrentPath (torrentSummary) {
var itemPath = TorrentSummary.getFileOrFolder(torrentSummary) let itemPath = TorrentSummary.getFileOrFolder(torrentSummary)
if (torrentSummary.files.length > 1) { if (torrentSummary.files.length > 1) {
itemPath = path.dirname(itemPath) itemPath = path.dirname(itemPath)
} }
@@ -175,7 +171,7 @@ function getTorrentPath (torrentSummary) {
} }
function showDoneNotification (torrent) { function showDoneNotification (torrent) {
var notif = new window.Notification('Download Complete', { const notif = new window.Notification('Download Complete', {
body: torrent.name, body: torrent.name,
silent: true silent: true
}) })

View File

@@ -30,8 +30,8 @@ module.exports = class TorrentListController {
torrentId = torrentId.slice(torrentId.indexOf('#') + 1) torrentId = torrentId.slice(torrentId.indexOf('#') + 1)
} }
var torrentKey = this.state.nextTorrentKey++ const torrentKey = this.state.nextTorrentKey++
var path = this.state.saved.prefs.downloadPath const path = this.state.saved.prefs.downloadPath
ipcRenderer.send('wt-start-torrenting', torrentKey, torrentId, path) ipcRenderer.send('wt-start-torrenting', torrentKey, torrentId, path)
@@ -66,15 +66,15 @@ module.exports = class TorrentListController {
// Creates a new torrent and start seeeding // Creates a new torrent and start seeeding
createTorrent (options) { createTorrent (options) {
var state = this.state const state = this.state
var torrentKey = state.nextTorrentKey++ const torrentKey = state.nextTorrentKey++
ipcRenderer.send('wt-create-torrent', torrentKey, options) ipcRenderer.send('wt-create-torrent', torrentKey, options)
state.location.cancel() state.location.cancel()
} }
// Starts downloading and/or seeding a given torrentSummary. // Starts downloading and/or seeding a given torrentSummary.
startTorrentingSummary (torrentKey) { startTorrentingSummary (torrentKey) {
var s = TorrentSummary.getByKey(this.state, torrentKey) const s = TorrentSummary.getByKey(this.state, torrentKey)
if (!s) throw new Error('Missing key: ' + torrentKey) if (!s) throw new Error('Missing key: ' + torrentKey)
// New torrent: give it a path // New torrent: give it a path
@@ -84,7 +84,7 @@ module.exports = class TorrentListController {
return start() return start()
} }
var fileOrFolder = TorrentSummary.getFileOrFolder(s) const fileOrFolder = TorrentSummary.getFileOrFolder(s)
// New torrent: metadata not yet received // New torrent: metadata not yet received
if (!fileOrFolder) return start() if (!fileOrFolder) return start()
@@ -110,7 +110,7 @@ module.exports = class TorrentListController {
// TODO: use torrentKey, not infoHash // TODO: use torrentKey, not infoHash
toggleTorrent (infoHash) { toggleTorrent (infoHash) {
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash) const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
if (torrentSummary.status === 'paused') { if (torrentSummary.status === 'paused') {
torrentSummary.status = 'new' torrentSummary.status = 'new'
this.startTorrentingSummary(torrentSummary.torrentKey) this.startTorrentingSummary(torrentSummary.torrentKey)
@@ -123,7 +123,7 @@ module.exports = class TorrentListController {
} }
toggleTorrentFile (infoHash, index) { toggleTorrentFile (infoHash, index) {
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash) const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
torrentSummary.selections[index] = !torrentSummary.selections[index] torrentSummary.selections[index] = !torrentSummary.selections[index]
// Let the WebTorrent process know to start or stop fetching that file // Let the WebTorrent process know to start or stop fetching that file
@@ -142,10 +142,10 @@ module.exports = class TorrentListController {
deleteTorrent (infoHash, deleteData) { deleteTorrent (infoHash, deleteData) {
ipcRenderer.send('wt-stop-torrenting', infoHash) ipcRenderer.send('wt-stop-torrenting', infoHash)
var index = this.state.saved.torrents.findIndex((x) => x.infoHash === infoHash) const index = this.state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
if (index > -1) { if (index > -1) {
var summary = this.state.saved.torrents[index] const summary = this.state.saved.torrents[index]
// remove torrent and poster file // remove torrent and poster file
deleteFile(TorrentSummary.getTorrentPath(summary)) deleteFile(TorrentSummary.getTorrentPath(summary))
@@ -173,8 +173,8 @@ module.exports = class TorrentListController {
} }
openTorrentContextMenu (infoHash) { openTorrentContextMenu (infoHash) {
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash) const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
var menu = new electron.remote.Menu() const menu = new electron.remote.Menu()
menu.append(new electron.remote.MenuItem({ menu.append(new electron.remote.MenuItem({
label: 'Remove From List', label: 'Remove From List',
@@ -223,11 +223,11 @@ module.exports = class TorrentListController {
// Calls `cb` on success, calls `onError` on failure // Calls `cb` on success, calls `onError` on failure
function findFilesRecursive (paths, cb) { function findFilesRecursive (paths, cb) {
if (paths.length > 1) { if (paths.length > 1) {
var numComplete = 0 let numComplete = 0
var ret = [] let ret = []
paths.forEach(function (path) { paths.forEach(function (path) {
findFilesRecursive([path], function (fileObjs) { findFilesRecursive([path], function (fileObjs) {
ret = ret.concat(fileObjs) ret.push(...fileObjs)
if (++numComplete === paths.length) { if (++numComplete === paths.length) {
ret.sort((a, b) => a.path < b.path ? -1 : a.path > b.path) ret.sort((a, b) => a.path < b.path ? -1 : a.path > b.path)
cb(ret) cb(ret)
@@ -237,13 +237,13 @@ function findFilesRecursive (paths, cb) {
return return
} }
var fileOrFolder = paths[0] const fileOrFolder = paths[0]
fs.stat(fileOrFolder, function (err, stat) { fs.stat(fileOrFolder, function (err, stat) {
if (err) return dispatch('error', err) if (err) return dispatch('error', err)
// Files: return name, path, and size // Files: return name, path, and size
if (!stat.isDirectory()) { if (!stat.isDirectory()) {
var filePath = fileOrFolder const filePath = fileOrFolder
return cb([{ return cb([{
name: path.basename(filePath), name: path.basename(filePath),
path: filePath, path: filePath,
@@ -252,10 +252,10 @@ function findFilesRecursive (paths, cb) {
} }
// Folders: recurse, make a list of all the files // Folders: recurse, make a list of all the files
var folderPath = fileOrFolder const folderPath = fileOrFolder
fs.readdir(folderPath, function (err, fileNames) { fs.readdir(folderPath, function (err, fileNames) {
if (err) return dispatch('error', err) if (err) return dispatch('error', err)
var paths = fileNames.map((fileName) => path.join(folderPath, fileName)) const paths = fileNames.map((fileName) => path.join(folderPath, fileName))
findFilesRecursive(paths, cb) findFilesRecursive(paths, cb)
}) })
}) })
@@ -270,7 +270,7 @@ function deleteFile (path) {
// Delete all files in a torrent // Delete all files in a torrent
function moveItemToTrash (torrentSummary) { function moveItemToTrash (torrentSummary) {
var filePath = TorrentSummary.getFileOrFolder(torrentSummary) const filePath = TorrentSummary.getFileOrFolder(torrentSummary)
if (filePath) ipcRenderer.send('moveItemToTrash', filePath) if (filePath) ipcRenderer.send('moveItemToTrash', filePath)
} }
@@ -279,9 +279,9 @@ function showItemInFolder (torrentSummary) {
} }
function saveTorrentFileAs (torrentSummary) { function saveTorrentFileAs (torrentSummary) {
var downloadPath = this.state.saved.prefs.downloadPath const downloadPath = this.state.saved.prefs.downloadPath
var newFileName = path.parse(torrentSummary.name).name + '.torrent' const newFileName = path.parse(torrentSummary.name).name + '.torrent'
var opts = { const opts = {
title: 'Save Torrent File', title: 'Save Torrent File',
defaultPath: path.join(downloadPath, newFileName), defaultPath: path.join(downloadPath, newFileName),
filters: [ filters: [
@@ -289,10 +289,10 @@ function saveTorrentFileAs (torrentSummary) {
{ name: 'All Files', extensions: ['*'] } { name: 'All Files', extensions: ['*'] }
] ]
} }
var win = electron.remote.getCurrentWindow() const win = electron.remote.getCurrentWindow()
electron.remote.dialog.showSaveDialog(win, opts, function (savePath) { electron.remote.dialog.showSaveDialog(win, opts, function (savePath) {
if (!savePath) return // They clicked Cancel if (!savePath) return // They clicked Cancel
var torrentPath = TorrentSummary.getTorrentPath(torrentSummary) const torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
fs.readFile(torrentPath, function (err, torrentFile) { fs.readFile(torrentPath, function (err, torrentFile) {
if (err) return dispatch('error', err) if (err) return dispatch('error', err)
fs.writeFile(savePath, torrentFile, function (err) { fs.writeFile(savePath, torrentFile, function (err) {

View File

@@ -8,7 +8,7 @@ module.exports = class UpdateController {
// Shows a modal saying that we have an update // Shows a modal saying that we have an update
updateAvailable (version) { updateAvailable (version) {
var skipped = this.state.saved.skippedVersions const skipped = this.state.saved.skippedVersions
if (skipped && skipped.includes(version)) { if (skipped && skipped.includes(version)) {
console.log('new version skipped by user: v' + version) console.log('new version skipped by user: v' + version)
return return
@@ -18,7 +18,7 @@ module.exports = class UpdateController {
// Don't show the modal again until the next version // Don't show the modal again until the next version
skipVersion (version) { skipVersion (version) {
var skipped = this.state.saved.skippedVersions let skipped = this.state.saved.skippedVersions
if (!skipped) skipped = this.state.saved.skippedVersions = [] if (!skipped) skipped = this.state.saved.skippedVersions = []
skipped.push(version) skipped.push(version)
State.saveThrottled(this.state) State.saveThrottled(this.state)

View File

@@ -17,14 +17,14 @@ function captureVideoFrame (video, format) {
throw new Error('Second argument must be one of "png", "jpg", or "webp"') throw new Error('Second argument must be one of "png", "jpg", or "webp"')
} }
var canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
canvas.width = video.videoWidth canvas.width = video.videoWidth
canvas.height = video.videoHeight canvas.height = video.videoHeight
canvas.getContext('2d').drawImage(video, 0, 0) canvas.getContext('2d').drawImage(video, 0, 0)
var dataUri = canvas.toDataURL('image/' + format) const dataUri = canvas.toDataURL('image/' + format)
var data = dataUri.split(',')[1] const data = dataUri.split(',')[1]
return new Buffer(data, 'base64') return new Buffer(data, 'base64')
} }

View File

@@ -13,19 +13,19 @@ module.exports = {
setRate setRate
} }
// Lazy load these for a ~300ms improvement in startup time const config = require('../../config')
var airplayer, chromecasts, dlnacasts
var config = require('../../config') // Lazy load these for a ~300ms improvement in startup time
let airplayer, chromecasts, dlnacasts
// App state. Cast modifies state.playing and state.errors in response to events // App state. Cast modifies state.playing and state.errors in response to events
var state let state
// Callback to notify module users when state has changed // Callback to notify module users when state has changed
var update let update
// setInterval() for updating cast status // setInterval() for updating cast status
var statusInterval = null let statusInterval = null
// Start looking for cast devices on the local network // Start looking for cast devices on the local network
function init (appState, callback) { function init (appState, callback) {
@@ -59,7 +59,7 @@ function init (appState, callback) {
// chromecast player implementation // chromecast player implementation
function chromecastPlayer () { function chromecastPlayer () {
var ret = { const ret = {
device: null, device: null,
addDevice, addDevice,
getDevices, getDevices,
@@ -95,7 +95,7 @@ function chromecastPlayer () {
} }
function open () { function open () {
var torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash) const torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash)
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, { ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, {
type: 'video/mp4', type: 'video/mp4',
title: config.APP_NAME + ' - ' + torrentSummary.name title: config.APP_NAME + ' - ' + torrentSummary.name
@@ -146,7 +146,7 @@ function chromecastPlayer () {
// airplay player implementation // airplay player implementation
function airplayPlayer () { function airplayPlayer () {
var ret = { const ret = {
device: null, device: null,
addDevice, addDevice,
getDevices, getDevices,
@@ -238,7 +238,7 @@ function airplayPlayer () {
// DLNA player implementation // DLNA player implementation
function dlnaPlayer (player) { function dlnaPlayer (player) {
var ret = { const ret = {
device: null, device: null,
addDevice, addDevice,
getDevices, getDevices,
@@ -274,7 +274,7 @@ function dlnaPlayer (player) {
} }
function open () { function open () {
var torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash) const torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash)
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, { ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, {
type: 'video/mp4', type: 'video/mp4',
title: config.APP_NAME + ' - ' + torrentSummary.name, title: config.APP_NAME + ' - ' + torrentSummary.name,
@@ -331,7 +331,7 @@ function dlnaPlayer (player) {
// Start polling cast device state, whenever we're connected // Start polling cast device state, whenever we're connected
function startStatusInterval () { function startStatusInterval () {
statusInterval = setInterval(function () { statusInterval = setInterval(function () {
var player = getPlayer() const player = getPlayer()
if (player) player.status() if (player) player.status()
}, 1000) }, 1000)
} }
@@ -355,8 +355,8 @@ function toggleMenu (location) {
} }
// Find all cast devices of the given type // Find all cast devices of the given type
var player = getPlayer(location) const player = getPlayer(location)
var devices = player ? player.getDevices() : [] const devices = player ? player.getDevices() : []
if (devices.length === 0) throw new Error('No ' + location + ' devices available') if (devices.length === 0) throw new Error('No ' + location + ' devices available')
// Show a menu // Show a menu
@@ -364,10 +364,10 @@ function toggleMenu (location) {
} }
function selectDevice (index) { function selectDevice (index) {
var {location, devices} = state.devices.castMenu const {location, devices} = state.devices.castMenu
// Start casting // Start casting
var player = getPlayer(location) const player = getPlayer(location)
player.device = devices[index] player.device = devices[index]
player.open() player.open()
@@ -383,7 +383,7 @@ function selectDevice (index) {
// Stops casting, move video back to local screen // Stops casting, move video back to local screen
function stop () { function stop () {
var player = getPlayer() const player = getPlayer()
if (player) { if (player) {
player.stop(function () { player.stop(function () {
player.device = null player.device = null
@@ -418,18 +418,18 @@ function getPlayer (location) {
} }
function play () { function play () {
var player = getPlayer() const player = getPlayer()
if (player) player.play(castCallback) if (player) player.play(castCallback)
} }
function pause () { function pause () {
var player = getPlayer() const player = getPlayer()
if (player) player.pause(castCallback) if (player) player.pause(castCallback)
} }
function setRate (rate) { function setRate (rate) {
var player let player
var result = true let result = true
if (state.playing.location === 'chromecast') { if (state.playing.location === 'chromecast') {
// TODO find how to control playback rate on chromecast // TODO find how to control playback rate on chromecast
castCallback() castCallback()
@@ -444,12 +444,12 @@ function setRate (rate) {
} }
function seek (time) { function seek (time) {
var player = getPlayer() const player = getPlayer()
if (player) player.seek(time, castCallback) if (player) player.seek(time, castCallback)
} }
function setVolume (volume) { function setVolume (volume) {
var player = getPlayer() const player = getPlayer()
if (player) player.volume(volume, castCallback) if (player) player.volume(volume, castCallback)
} }

View File

@@ -4,8 +4,8 @@ module.exports = {
setDispatch setDispatch
} }
var dispatchers = {} const dispatchers = {}
var _dispatch = function () {} let _dispatch = function () {}
function setDispatch (dispatch) { function setDispatch (dispatch) {
_dispatch = dispatch _dispatch = dispatch
@@ -20,8 +20,8 @@ function dispatch (...args) {
// function. This prevents React from updating the listener functions on // function. This prevents React from updating the listener functions on
// each update(). // each update().
function dispatcher (...args) { function dispatcher (...args) {
var str = JSON.stringify(args) const str = JSON.stringify(args)
var handler = dispatchers[str] let handler = dispatchers[str]
if (!handler) { if (!handler) {
handler = dispatchers[str] = function (e) { handler = dispatchers[str] = function (e) {
// Do not propagate click to elements below the button // Do not propagate click to elements below the button

View File

@@ -17,7 +17,7 @@ function run (state) {
state.saved.version = '0.0.0' // Pre-0.7.0 version, so run all migrations state.saved.version = '0.0.0' // Pre-0.7.0 version, so run all migrations
} }
var version = state.saved.version const version = state.saved.version
if (semver.lt(version, '0.7.0')) { if (semver.lt(version, '0.7.0')) {
migrate_0_7_0(state.saved) migrate_0_7_0(state.saved)
@@ -40,11 +40,11 @@ function run (state) {
} }
function migrate_0_7_0 (saved) { function migrate_0_7_0 (saved) {
var fs = require('fs-extra') const fs = require('fs-extra')
var path = require('path') const path = require('path')
saved.torrents.forEach(function (ts) { saved.torrents.forEach(function (ts) {
var infoHash = ts.infoHash const infoHash = ts.infoHash
// Replace torrentPath with torrentFileName // Replace torrentPath with torrentFileName
// There are a number of cases to handle here: // There are a number of cases to handle here:
@@ -52,7 +52,7 @@ function migrate_0_7_0 (saved) {
// * Then, relative paths for the default torrents, eg '../static/sintel.torrent' // * Then, relative paths for the default torrents, eg '../static/sintel.torrent'
// * Then, paths computed at runtime for default torrents, eg 'sintel.torrent' // * Then, paths computed at runtime for default torrents, eg 'sintel.torrent'
// * Finally, now we're getting rid of torrentPath altogether // * Finally, now we're getting rid of torrentPath altogether
var src, dst let src, dst
if (ts.torrentPath) { if (ts.torrentPath) {
if (path.isAbsolute(ts.torrentPath) || ts.torrentPath.startsWith('..')) { if (path.isAbsolute(ts.torrentPath) || ts.torrentPath.startsWith('..')) {
src = ts.torrentPath src = ts.torrentPath
@@ -70,7 +70,7 @@ function migrate_0_7_0 (saved) {
// Replace posterURL with posterFileName // Replace posterURL with posterFileName
if (ts.posterURL) { if (ts.posterURL) {
var extension = path.extname(ts.posterURL) const extension = path.extname(ts.posterURL)
src = path.isAbsolute(ts.posterURL) src = path.isAbsolute(ts.posterURL)
? ts.posterURL ? ts.posterURL
: path.join(config.STATIC_PATH, ts.posterURL) : path.join(config.STATIC_PATH, ts.posterURL)
@@ -116,7 +116,7 @@ function migrate_0_12_0 (saved) {
// Undo a terrible bug where clicking Play on a default torrent on a fresh // Undo a terrible bug where clicking Play on a default torrent on a fresh
// install results in a "path missing" error // install results in a "path missing" error
// See https://github.com/feross/webtorrent-desktop/pull/806 // See https://github.com/feross/webtorrent-desktop/pull/806
var defaultTorrentFiles = [ const defaultTorrentFiles = [
'6a9759bffd5c0af65319979fb7832189f4f3c35d.torrent', '6a9759bffd5c0af65319979fb7832189f4f3c35d.torrent',
'88594aaacbde40ef3e2510c47374ec0aa396c08e.torrent', '88594aaacbde40ef3e2510c47374ec0aa396c08e.torrent',
'6a02592d2bbc069628cd5ed8a54f88ee06ac0ba5.torrent', '6a02592d2bbc069628cd5ed8a54f88ee06ac0ba5.torrent',
@@ -125,7 +125,7 @@ function migrate_0_12_0 (saved) {
] ]
saved.torrents.forEach(function (torrentSummary) { saved.torrents.forEach(function (torrentSummary) {
if (!defaultTorrentFiles.includes(torrentSummary.torrentFileName)) return if (!defaultTorrentFiles.includes(torrentSummary.torrentFileName)) return
var fileOrFolder = TorrentSummary.getFileOrFolder(torrentSummary) const fileOrFolder = TorrentSummary.getFileOrFolder(torrentSummary)
if (!fileOrFolder) return if (!fileOrFolder) return
try { try {
fs.statSync(fileOrFolder) fs.statSync(fileOrFolder)

View File

@@ -9,7 +9,7 @@ module.exports = {
const TorrentSummary = require('./torrent-summary') const TorrentSummary = require('./torrent-summary')
const TorrentPlayer = require('./torrent-player') const TorrentPlayer = require('./torrent-player')
var cache = { const cache = {
infoHash: null, infoHash: null,
previousIndex: null, previousIndex: null,
currentIndex: null, currentIndex: null,
@@ -41,8 +41,8 @@ function getCurrentLocalURL (state) {
} }
function updateCache (state) { function updateCache (state) {
var infoHash = state.playing.infoHash const infoHash = state.playing.infoHash
var fileIndex = state.playing.fileIndex const fileIndex = state.playing.fileIndex
if (infoHash === cache.infoHash) { if (infoHash === cache.infoHash) {
switch (fileIndex) { switch (fileIndex) {
@@ -69,7 +69,7 @@ function updateCache (state) {
} }
function findPreviousIndex (state) { function findPreviousIndex (state) {
var files = TorrentSummary.getByKey(state, state.playing.infoHash).files const files = TorrentSummary.getByKey(state, state.playing.infoHash).files
for (var i = state.playing.fileIndex - 1; i >= 0; i--) { for (var i = state.playing.fileIndex - 1; i >= 0; i--) {
if (TorrentPlayer.isPlayable(files[i])) return i if (TorrentPlayer.isPlayable(files[i])) return i
} }
@@ -77,7 +77,7 @@ function findPreviousIndex (state) {
} }
function findNextIndex (state) { function findNextIndex (state) {
var files = TorrentSummary.getByKey(state, state.playing.infoHash).files const files = TorrentSummary.getByKey(state, state.playing.infoHash).files
for (var i = state.playing.fileIndex + 1; i < files.length; i++) { for (var i = state.playing.fileIndex + 1; i < files.length; i++) {
if (TorrentPlayer.isPlayable(files[i])) return i if (TorrentPlayer.isPlayable(files[i])) return i
} }

View File

@@ -3,15 +3,15 @@ module.exports = {
play play
} }
var config = require('../../config') const config = require('../../config')
var path = require('path') const path = require('path')
var VOLUME = 0.15 const VOLUME = 0.15
/* Cache of Audio elements, for instant playback */ /* Cache of Audio elements, for instant playback */
var cache = {} const cache = {}
var sounds = { const sounds = {
ADD: { ADD: {
url: 'file://' + path.join(config.STATIC_PATH, 'sound', 'add.wav'), url: 'file://' + path.join(config.STATIC_PATH, 'sound', 'add.wav'),
volume: VOLUME volume: VOLUME
@@ -47,10 +47,10 @@ var sounds = {
} }
function preload () { function preload () {
for (var name in sounds) { for (let name in sounds) {
if (!cache[name]) { if (!cache[name]) {
var sound = sounds[name] const sound = sounds[name]
var audio = cache[name] = new window.Audio() const audio = cache[name] = new window.Audio()
audio.volume = sound.volume audio.volume = sound.volume
audio.src = sound.url audio.src = sound.url
} }
@@ -58,9 +58,9 @@ function preload () {
} }
function play (name) { function play (name) {
var audio = cache[name] let audio = cache[name]
if (!audio) { if (!audio) {
var sound = sounds[name] const sound = sounds[name]
if (!sound) { if (!sound) {
throw new Error('Invalid sound name') throw new Error('Invalid sound name')
} }

View File

@@ -1,11 +1,11 @@
var appConfig = require('application-config')('WebTorrent') const appConfig = require('application-config')('WebTorrent')
var path = require('path') const path = require('path')
var {EventEmitter} = require('events') const {EventEmitter} = require('events')
var config = require('../../config') const config = require('../../config')
var migrations = require('./migrations') const migrations = require('./migrations')
var State = module.exports = Object.assign(new EventEmitter(), { const State = module.exports = Object.assign(new EventEmitter(), {
getDefaultPlayState, getDefaultPlayState,
load, load,
save, save,
@@ -15,7 +15,7 @@ var State = module.exports = Object.assign(new EventEmitter(), {
appConfig.filePath = path.join(config.CONFIG_PATH, 'config.json') appConfig.filePath = path.join(config.CONFIG_PATH, 'config.json')
function getDefaultState () { function getDefaultState () {
var LocationHistory = require('location-history') const LocationHistory = require('location-history')
return { return {
/* /*
@@ -98,11 +98,11 @@ function getDefaultPlayState () {
/* If the saved state file doesn't exist yet, here's what we use instead */ /* If the saved state file doesn't exist yet, here's what we use instead */
function setupSavedState (cb) { function setupSavedState (cb) {
var fs = require('fs-extra') const fs = require('fs-extra')
var parseTorrent = require('parse-torrent') const parseTorrent = require('parse-torrent')
var parallel = require('run-parallel') const parallel = require('run-parallel')
var saved = { const saved = {
prefs: { prefs: {
downloadPath: config.DEFAULT_DOWNLOAD_PATH, downloadPath: config.DEFAULT_DOWNLOAD_PATH,
isFileHandler: false, isFileHandler: false,
@@ -113,10 +113,10 @@ function setupSavedState (cb) {
version: config.APP_VERSION /* make sure we can upgrade gracefully later */ version: config.APP_VERSION /* make sure we can upgrade gracefully later */
} }
var tasks = [] const tasks = []
config.DEFAULT_TORRENTS.map(function (t, i) { config.DEFAULT_TORRENTS.map(function (t, i) {
var infoHash = saved.torrents[i].infoHash const infoHash = saved.torrents[i].infoHash
tasks.push(function (cb) { tasks.push(function (cb) {
fs.copy( fs.copy(
path.join(config.STATIC_PATH, t.posterFileName), path.join(config.STATIC_PATH, t.posterFileName),
@@ -139,8 +139,8 @@ function setupSavedState (cb) {
}) })
function createTorrentObject (t) { function createTorrentObject (t) {
var torrent = fs.readFileSync(path.join(config.STATIC_PATH, t.torrentFileName)) const torrent = fs.readFileSync(path.join(config.STATIC_PATH, t.torrentFileName))
var parsedTorrent = parseTorrent(torrent) const parsedTorrent = parseTorrent(torrent)
return { return {
status: 'paused', status: 'paused',
@@ -157,18 +157,18 @@ function setupSavedState (cb) {
} }
function getPlayingTorrentSummary () { function getPlayingTorrentSummary () {
var infoHash = this.playing.infoHash const infoHash = this.playing.infoHash
return this.saved.torrents.find((x) => x.infoHash === infoHash) return this.saved.torrents.find((x) => x.infoHash === infoHash)
} }
function getPlayingFileSummary () { function getPlayingFileSummary () {
var torrentSummary = this.getPlayingTorrentSummary() const torrentSummary = this.getPlayingTorrentSummary()
if (!torrentSummary) return null if (!torrentSummary) return null
return torrentSummary.files[this.playing.fileIndex] return torrentSummary.files[this.playing.fileIndex]
} }
function load (cb) { function load (cb) {
var state = getDefaultState() const state = getDefaultState()
appConfig.read(function (err, saved) { appConfig.read(function (err, saved) {
if (err || !saved.version) { if (err || !saved.version) {
@@ -193,14 +193,14 @@ function save (state, cb) {
delete state.saveStateTimeout delete state.saveStateTimeout
// Clean up, so that we're not saving any pending state // Clean up, so that we're not saving any pending state
var copy = Object.assign({}, state.saved) const copy = Object.assign({}, state.saved)
// Remove torrents pending addition to the list, where we haven't finished // Remove torrents pending addition to the list, where we haven't finished
// reading the torrent file or file(s) to seed & don't have an infohash // reading the torrent file or file(s) to seed & don't have an infohash
copy.torrents = copy.torrents copy.torrents = copy.torrents
.filter((x) => x.infoHash) .filter((x) => x.infoHash)
.map(function (x) { .map(function (x) {
var torrent = {} const torrent = {}
for (var key in x) { for (let key in x) {
if (key === 'progress' || key === 'torrentKey') { if (key === 'progress' || key === 'torrentKey') {
continue // Don't save progress info or key for the webtorrent process continue // Don't save progress info or key for the webtorrent process
} }

View File

@@ -14,7 +14,7 @@ const url = require('url')
const config = require('../../config') const config = require('../../config')
var telemetry let telemetry
function init (state) { function init (state) {
telemetry = state.saved.telemetry telemetry = state.saved.telemetry
@@ -23,7 +23,7 @@ function init (state) {
reset() reset()
} }
var now = new Date() const now = new Date()
telemetry.version = config.APP_VERSION telemetry.version = config.APP_VERSION
telemetry.timestamp = now.toISOString() telemetry.timestamp = now.toISOString()
telemetry.localTime = now.toTimeString() telemetry.localTime = now.toTimeString()
@@ -56,17 +56,17 @@ function reset () {
function postToServer () { function postToServer () {
// Serialize the telemetry summary // Serialize the telemetry summary
var payload = new Buffer(JSON.stringify(telemetry), 'utf8') const payload = new Buffer(JSON.stringify(telemetry), 'utf8')
// POST to our server // POST to our server
var options = url.parse(config.TELEMETRY_URL) const options = url.parse(config.TELEMETRY_URL)
options.method = 'POST' options.method = 'POST'
options.headers = { options.headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Content-Length': payload.length 'Content-Length': payload.length
} }
var req = https.request(options, function (res) { const req = https.request(options, function (res) {
if (res.statusCode === 200) { if (res.statusCode === 200) {
console.log('Successfully posted telemetry summary') console.log('Successfully posted telemetry summary')
reset() reset()
@@ -85,7 +85,7 @@ function postToServer () {
// collects screen resolution, etc // collects screen resolution, etc
function createSummary () { function createSummary () {
// Make a 256-bit random unique ID // Make a 256-bit random unique ID
var userID = crypto.randomBytes(32).toString('hex') const userID = crypto.randomBytes(32).toString('hex')
return { userID } return { userID }
} }
@@ -111,10 +111,10 @@ function getSystemInfo () {
// Get the number of torrents, rounded to the nearest power of two // Get the number of torrents, rounded to the nearest power of two
function getApproxNumTorrents (state) { function getApproxNumTorrents (state) {
var exactNum = state.saved.torrents.length const exactNum = state.saved.torrents.length
if (exactNum === 0) return 0 if (exactNum === 0) return 0
// Otherwise, return 1, 2, 4, 8, etc by rounding in log space // Otherwise, return 1, 2, 4, 8, etc by rounding in log space
var log2 = Math.log(exactNum) / Math.log(2) const log2 = Math.log(exactNum) / Math.log(2)
return 1 << Math.round(log2) return 1 << Math.round(log2)
} }
@@ -124,8 +124,8 @@ function logUncaughtError (procName, e) {
// Hopefully uncaught errors immediately on startup are fixed in dev // Hopefully uncaught errors immediately on startup are fixed in dev
if (!telemetry) return if (!telemetry) return
var message let message
var stack = '' let stack = ''
if (e == null) { if (e == null) {
message = 'Unexpected undefined error' message = 'Unexpected undefined error'
} else if (e.error) { } else if (e.error) {
@@ -165,14 +165,14 @@ function logUncaughtError (procName, e) {
if (stack.length > 1000) stack = stack.substring(0, 1000) if (stack.length > 1000) stack = stack.substring(0, 1000)
// Log the app version *at the time of the error* // Log the app version *at the time of the error*
var version = config.APP_VERSION const version = config.APP_VERSION
telemetry.uncaughtErrors.push({process: procName, message, stack, version}) telemetry.uncaughtErrors.push({process: procName, message, stack, version})
} }
// Turns a DOM element into a string, eg "DIV.my-class.visible" // Turns a DOM element into a string, eg "DIV.my-class.visible"
function getElemString (elem) { function getElemString (elem) {
var ret = elem.tagName let ret = elem.tagName
try { try {
ret += '.' + Array.from(elem.classList).join('.') ret += '.' + Array.from(elem.classList).join('.')
} catch (e) {} } catch (e) {}
@@ -186,7 +186,7 @@ function logPlayAttempt (result) {
return console.error('Unknown play attempt result', result) return console.error('Unknown play attempt result', result)
} }
var attempts = telemetry.playAttempts const attempts = telemetry.playAttempts
attempts.total = (attempts.total || 0) + 1 attempts.total = (attempts.total || 0) + 1
attempts[result] = (attempts[result] || 0) + 1 attempts[result] = (attempts[result] || 0) + 1
} }

View File

@@ -6,7 +6,7 @@ module.exports = {
isPlayableTorrentSummary isPlayableTorrentSummary
} }
var path = require('path') const path = require('path')
// Checks whether a fileSummary or file path is audio/video that we can play, // Checks whether a fileSummary or file path is audio/video that we can play,
// based on the file extension // based on the file extension
@@ -46,13 +46,13 @@ function isAudio (file) {
// - a file object where obj.name is ends in .torrent // - a file object where obj.name is ends in .torrent
// - a string that's a magnet link (magnet://...) // - a string that's a magnet link (magnet://...)
function isTorrent (file) { function isTorrent (file) {
var isTorrentFile = getFileExtension(file) === '.torrent' const isTorrentFile = getFileExtension(file) === '.torrent'
var isMagnet = typeof file === 'string' && /^(stream-)?magnet:/.test(file) const isMagnet = typeof file === 'string' && /^(stream-)?magnet:/.test(file)
return isTorrentFile || isMagnet return isTorrentFile || isMagnet
} }
function getFileExtension (file) { function getFileExtension (file) {
var name = typeof file === 'string' ? file : file.name const name = typeof file === 'string' ? file : file.name
return path.extname(name).toLowerCase() return path.extname(name).toLowerCase()
} }

View File

@@ -1,22 +1,22 @@
module.exports = torrentPoster module.exports = torrentPoster
var captureVideoFrame = require('./capture-video-frame') const captureVideoFrame = require('./capture-video-frame')
var path = require('path') const path = require('path')
function torrentPoster (torrent, cb) { function torrentPoster (torrent, cb) {
// First, try to use a poster image if available // First, try to use a poster image if available
var posterFile = torrent.files.filter(function (file) { const posterFile = torrent.files.filter(function (file) {
return /^poster\.(jpg|png|gif)$/.test(file.name) return /^poster\.(jpg|png|gif)$/.test(file.name)
})[0] })[0]
if (posterFile) return torrentPosterFromImage(posterFile, torrent, cb) if (posterFile) return torrentPosterFromImage(posterFile, torrent, cb)
// Second, try to use the largest video file // Second, try to use the largest video file
// Filter out file formats that the <video> tag definitely can't play // Filter out file formats that the <video> tag definitely can't play
var videoFile = getLargestFileByExtension(torrent, ['.mp4', '.m4v', '.webm', '.mov', '.mkv']) const videoFile = getLargestFileByExtension(torrent, ['.mp4', '.m4v', '.webm', '.mov', '.mkv'])
if (videoFile) return torrentPosterFromVideo(videoFile, torrent, cb) if (videoFile) return torrentPosterFromVideo(videoFile, torrent, cb)
// Third, try to use the largest image file // Third, try to use the largest image file
var imgFile = getLargestFileByExtension(torrent, ['.gif', '.jpg', '.jpeg', '.png']) const imgFile = getLargestFileByExtension(torrent, ['.gif', '.jpg', '.jpeg', '.png'])
if (imgFile) return torrentPosterFromImage(imgFile, torrent, cb) if (imgFile) return torrentPosterFromImage(imgFile, torrent, cb)
// TODO: generate a waveform from the largest sound file // TODO: generate a waveform from the largest sound file
@@ -25,8 +25,8 @@ function torrentPoster (torrent, cb) {
} }
function getLargestFileByExtension (torrent, extensions) { function getLargestFileByExtension (torrent, extensions) {
var files = torrent.files.filter(function (file) { const files = torrent.files.filter(function (file) {
var extname = path.extname(file.name).toLowerCase() const extname = path.extname(file.name).toLowerCase()
return extensions.indexOf(extname) !== -1 return extensions.indexOf(extname) !== -1
}) })
if (files.length === 0) return undefined if (files.length === 0) return undefined
@@ -36,15 +36,15 @@ function getLargestFileByExtension (torrent, extensions) {
} }
function torrentPosterFromVideo (file, torrent, cb) { function torrentPosterFromVideo (file, torrent, cb) {
var index = torrent.files.indexOf(file) const index = torrent.files.indexOf(file)
var server = torrent.createServer(0) const server = torrent.createServer(0)
server.listen(0, onListening) server.listen(0, onListening)
function onListening () { function onListening () {
var port = server.address().port const port = server.address().port
var url = 'http://localhost:' + port + '/' + index const url = 'http://localhost:' + port + '/' + index
var video = document.createElement('video') const video = document.createElement('video')
video.addEventListener('canplay', onCanPlay) video.addEventListener('canplay', onCanPlay)
video.volume = 0 video.volume = 0
@@ -61,7 +61,7 @@ function torrentPosterFromVideo (file, torrent, cb) {
function onSeeked () { function onSeeked () {
video.removeEventListener('seeked', onSeeked) video.removeEventListener('seeked', onSeeked)
var buf = captureVideoFrame(video) const buf = captureVideoFrame(video)
// unload video element // unload video element
video.pause() video.pause()
@@ -78,6 +78,6 @@ function torrentPosterFromVideo (file, torrent, cb) {
} }
function torrentPosterFromImage (file, torrent, cb) { function torrentPosterFromImage (file, torrent, cb) {
var extname = path.extname(file.name) const extname = path.extname(file.name)
file.getBuffer((err, buf) => cb(err, buf, extname)) file.getBuffer((err, buf) => cb(err, buf, extname))
} }

View File

@@ -6,8 +6,8 @@ module.exports = {
getFileOrFolder getFileOrFolder
} }
var path = require('path') const path = require('path')
var config = require('../../config') const config = require('../../config')
// Expects a torrentSummary // Expects a torrentSummary
// Returns an absolute path to the torrent file, or null if unavailable // Returns an absolute path to the torrent file, or null if unavailable
@@ -20,7 +20,7 @@ function getTorrentPath (torrentSummary) {
// Returns an absolute path to the poster image, or null if unavailable // Returns an absolute path to the poster image, or null if unavailable
function getPosterPath (torrentSummary) { function getPosterPath (torrentSummary) {
if (!torrentSummary || !torrentSummary.posterFileName) return null if (!torrentSummary || !torrentSummary.posterFileName) return null
var posterPath = path.join(config.POSTER_PATH, torrentSummary.posterFileName) const posterPath = path.join(config.POSTER_PATH, torrentSummary.posterFileName)
// Work around a Chrome bug (reproduced in vanilla Chrome, not just Electron): // Work around a Chrome bug (reproduced in vanilla Chrome, not just Electron):
// Backslashes in URLS in CSS cause bizarre string encoding issues // Backslashes in URLS in CSS cause bizarre string encoding issues
return posterPath.replace(/\\/g, '/') return posterPath.replace(/\\/g, '/')
@@ -29,7 +29,7 @@ function getPosterPath (torrentSummary) {
// Expects a torrentSummary // Expects a torrentSummary
// Returns a torrentID: filename, magnet URI, or infohash // Returns a torrentID: filename, magnet URI, or infohash
function getTorrentID (torrentSummary) { function getTorrentID (torrentSummary) {
var s = torrentSummary const s = torrentSummary
if (s.torrentFileName) { // Load torrent file from disk if (s.torrentFileName) { // Load torrent file from disk
return getTorrentPath(s) return getTorrentPath(s)
} else { // Load torrent from DHT } else { // Load torrent from DHT
@@ -51,7 +51,7 @@ function getByKey (state, torrentKey) {
// TODO: make this assumption explicit, enforce it in the `create-torrent` // TODO: make this assumption explicit, enforce it in the `create-torrent`
// module. Store root folder explicitly to avoid hacky path processing below. // module. Store root folder explicitly to avoid hacky path processing below.
function getFileOrFolder (torrentSummary) { function getFileOrFolder (torrentSummary) {
var ts = torrentSummary const ts = torrentSummary
if (!ts.path || !ts.files || ts.files.length === 0) return null if (!ts.path || !ts.files || ts.files.length === 0) return null
return path.join(ts.path, ts.files[0].path.split('/')[0]) return path.join(ts.path, ts.files[0].path.split('/')[0])
} }

View File

@@ -28,27 +28,27 @@ const SubtitlesController = require('./controllers/subtitles-controller')
const TorrentListController = require('./controllers/torrent-list-controller') const TorrentListController = require('./controllers/torrent-list-controller')
const TorrentController = require('./controllers/torrent-controller') const TorrentController = require('./controllers/torrent-controller')
// Electron apps have two processes: a main process (node) runs first and starts
// a renderer process (essentially a Chrome window). We're in the renderer process,
// and this IPC channel receives from and sends messages to the main process
const ipcRenderer = electron.ipcRenderer
// Yo-yo pattern: state object lives here and percolates down thru all the views. // Yo-yo pattern: state object lives here and percolates down thru all the views.
// Events come back up from the views via dispatch(...) // Events come back up from the views via dispatch(...)
require('./lib/dispatcher').setDispatch(dispatch) require('./lib/dispatcher').setDispatch(dispatch)
// From dispatch(...), events are sent to one of the controllers // From dispatch(...), events are sent to one of the controllers
var controllers = null let controllers = null
// This dependency is the slowest-loading, so we lazy load it // This dependency is the slowest-loading, so we lazy load it
var Cast = null let Cast = null
// Electron apps have two processes: a main process (node) runs first and starts
// a renderer process (essentially a Chrome window). We're in the renderer process,
// and this IPC channel receives from and sends messages to the main process
var ipcRenderer = electron.ipcRenderer
// All state lives in state.js. `state.saved` is read from and written to a file. // All state lives in state.js. `state.saved` is read from and written to a file.
// All other state is ephemeral. First we load state.saved then initialize the app. // All other state is ephemeral. First we load state.saved then initialize the app.
var state let state
// Root React component // Root React component
var app let app
State.load(onState) State.load(onState)
@@ -264,7 +264,7 @@ function dispatch (action, ...args) {
console.log('dispatch: %s %o', action, args) console.log('dispatch: %s %o', action, args)
} }
var handler = dispatchHandlers[action] const handler = dispatchHandlers[action]
if (handler) handler(...args) if (handler) handler(...args)
else console.error('Missing dispatch handler: ' + action) else console.error('Missing dispatch handler: ' + action)
@@ -284,7 +284,7 @@ function setupIpc () {
ipcRenderer.on('fullscreenChanged', onFullscreenChanged) ipcRenderer.on('fullscreenChanged', onFullscreenChanged)
var tc = controllers.torrent const tc = controllers.torrent
ipcRenderer.on('wt-infohash', (e, ...args) => tc.torrentInfoHash(...args)) ipcRenderer.on('wt-infohash', (e, ...args) => tc.torrentInfoHash(...args))
ipcRenderer.on('wt-metadata', (e, ...args) => tc.torrentMetadata(...args)) ipcRenderer.on('wt-metadata', (e, ...args) => tc.torrentMetadata(...args))
ipcRenderer.on('wt-done', (e, ...args) => tc.torrentDone(...args)) ipcRenderer.on('wt-done', (e, ...args) => tc.torrentDone(...args))
@@ -311,7 +311,7 @@ function backToList () {
state.modal = null state.modal = null
state.location.backToFirst(function () { state.location.backToFirst(function () {
// If we were already on the torrent list, scroll to the top // If we were already on the torrent list, scroll to the top
var contentTag = document.querySelector('.content') const contentTag = document.querySelector('.content')
if (contentTag) contentTag.scrollTop = 0 if (contentTag) contentTag.scrollTop = 0
}) })
} }
@@ -358,18 +358,18 @@ function setDimensions (dimensions) {
state.window.wasMaximized = electron.remote.getCurrentWindow().isMaximized state.window.wasMaximized = electron.remote.getCurrentWindow().isMaximized
// Limit window size to screen size // Limit window size to screen size
var screenWidth = window.screen.width const screenWidth = window.screen.width
var screenHeight = window.screen.height const screenHeight = window.screen.height
var aspectRatio = dimensions.width / dimensions.height const aspectRatio = dimensions.width / dimensions.height
var scaleFactor = Math.min( const scaleFactor = Math.min(
Math.min(screenWidth / dimensions.width, 1), Math.min(screenWidth / dimensions.width, 1),
Math.min(screenHeight / dimensions.height, 1) Math.min(screenHeight / dimensions.height, 1)
) )
var width = Math.max( const width = Math.max(
Math.floor(dimensions.width * scaleFactor), Math.floor(dimensions.width * scaleFactor),
config.WINDOW_MIN_WIDTH config.WINDOW_MIN_WIDTH
) )
var height = Math.max( const height = Math.max(
Math.floor(dimensions.height * scaleFactor), Math.floor(dimensions.height * scaleFactor),
config.WINDOW_MIN_HEIGHT config.WINDOW_MIN_HEIGHT
) )
@@ -384,9 +384,9 @@ function setDimensions (dimensions) {
function onOpen (files) { function onOpen (files) {
if (!Array.isArray(files)) files = [ files ] if (!Array.isArray(files)) files = [ files ]
var url = state.location.url() const url = state.location.url()
var allTorrents = files.every(TorrentPlayer.isTorrent) const allTorrents = files.every(TorrentPlayer.isTorrent)
var allSubtitles = files.every(controllers.subtitles.isSubtitle) const allSubtitles = files.every(controllers.subtitles.isSubtitle)
if (allTorrents) { if (allTorrents) {
// Drop torrents onto the app: go to home screen, add torrents, no matter what // Drop torrents onto the app: go to home screen, add torrents, no matter what
@@ -422,7 +422,7 @@ function onError (err) {
function onPaste (e) { function onPaste (e) {
if (e.target.tagName.toLowerCase() === 'input') return if (e.target.tagName.toLowerCase() === 'input') return
var torrentIds = electron.clipboard.readText().split('\n') const torrentIds = electron.clipboard.readText().split('\n')
torrentIds.forEach(function (torrentId) { torrentIds.forEach(function (torrentId) {
torrentId = torrentId.trim() torrentId = torrentId.trim()
if (torrentId.length === 0) return if (torrentId.length === 0) return

View File

@@ -33,21 +33,21 @@ darkBaseTheme.palette.accent3Color = colors.redA100
class App extends React.Component { class App extends React.Component {
render () { render () {
var state = this.props.state const state = this.props.state
// Hide player controls while playing video, if the mouse stays still for a while // Hide player controls while playing video, if the mouse stays still for a while
// Never hide the controls when: // Never hide the controls when:
// * The mouse is over the controls or we're scrubbing (see CSS) // * The mouse is over the controls or we're scrubbing (see CSS)
// * The video is paused // * The video is paused
// * The video is playing remotely on Chromecast or Airplay // * The video is playing remotely on Chromecast or Airplay
var hideControls = state.location.url() === 'player' && const hideControls = state.location.url() === 'player' &&
state.playing.mouseStationarySince !== 0 && state.playing.mouseStationarySince !== 0 &&
new Date().getTime() - state.playing.mouseStationarySince > 2000 && new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
!state.playing.isPaused && !state.playing.isPaused &&
state.playing.location === 'local' && state.playing.location === 'local' &&
state.playing.playbackRate === 1 state.playing.playbackRate === 1
var cls = [ const cls = [
'view-' + state.location.url(), /* e.g. view-home, view-player */ 'view-' + state.location.url(), /* e.g. view-home, view-player */
'is-' + process.platform /* e.g. is-darwin, is-win32, is-linux */ 'is-' + process.platform /* e.g. is-darwin, is-win32, is-linux */
] ]
@@ -55,7 +55,7 @@ class App extends React.Component {
if (state.window.isFocused) cls.push('is-focused') if (state.window.isFocused) cls.push('is-focused')
if (hideControls) cls.push('hide-video-controls') if (hideControls) cls.push('hide-video-controls')
var vdom = ( const vdom = (
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}> <MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<div className={'app ' + cls.join(' ')}> <div className={'app ' + cls.join(' ')}>
<Header state={state} /> <Header state={state} />
@@ -70,12 +70,12 @@ class App extends React.Component {
} }
getErrorPopover () { getErrorPopover () {
var state = this.props.state const state = this.props.state
var now = new Date().getTime() const now = new Date().getTime()
var recentErrors = state.errors.filter((x) => now - x.time < 5000) const recentErrors = state.errors.filter((x) => now - x.time < 5000)
var hasErrors = recentErrors.length > 0 const hasErrors = recentErrors.length > 0
var errorElems = recentErrors.map(function (error, i) { const errorElems = recentErrors.map(function (error, i) {
return (<div key={i} className='error'>{error.message}</div>) return (<div key={i} className='error'>{error.message}</div>)
}) })
return ( return (
@@ -88,9 +88,9 @@ class App extends React.Component {
} }
getModal () { getModal () {
var state = this.props.state const state = this.props.state
if (!state.modal) return if (!state.modal) return
var ModalContents = Modals[state.modal.id] const ModalContents = Modals[state.modal.id]
return ( return (
<div key='modal' className='modal'> <div key='modal' className='modal'>
<div key='modal-background' className='modal-background' /> <div key='modal-background' className='modal-background' />
@@ -102,8 +102,8 @@ class App extends React.Component {
} }
getView () { getView () {
var state = this.props.state const state = this.props.state
var View = Views[state.location.url()] const View = Views[state.location.url()]
return (<View state={state} />) return (<View state={state} />)
} }
} }

View File

@@ -20,11 +20,11 @@ class CreateTorrentPage extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
var state = this.props.state const state = this.props.state
var info = state.location.current() const info = state.location.current()
// First, extract the base folder that the files are all in // First, extract the base folder that the files are all in
var pathPrefix = info.folderPath let pathPrefix = info.folderPath
if (!pathPrefix) { if (!pathPrefix) {
pathPrefix = info.files.map((x) => x.path).reduce(findCommonPrefix) pathPrefix = info.files.map((x) => x.path).reduce(findCommonPrefix)
if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) { if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) {
@@ -33,14 +33,14 @@ class CreateTorrentPage extends React.Component {
} }
// Then, exclude .DS_Store and other dotfiles // Then, exclude .DS_Store and other dotfiles
var files = info.files const files = info.files
.filter((f) => !containsDots(f.path, pathPrefix)) .filter((f) => !containsDots(f.path, pathPrefix))
.map((f) => ({name: f.name, path: f.path, size: f.size})) .map((f) => ({name: f.name, path: f.path, size: f.size}))
if (files.length === 0) return (<CreateTorrentErrorPage state={state} />) if (files.length === 0) return (<CreateTorrentErrorPage state={state} />)
// Then, use the name of the base folder (or sole file, for a single file torrent) // Then, use the name of the base folder (or sole file, for a single file torrent)
// as the default name. Show all files relative to the base folder. // as the default name. Show all files relative to the base folder.
var defaultName, basePath let defaultName, basePath
if (files.length === 1) { if (files.length === 1) {
// Single file torrent: /a/b/foo.jpg -> torrent name 'foo.jpg', path '/a/b' // Single file torrent: /a/b/foo.jpg -> torrent name 'foo.jpg', path '/a/b'
defaultName = files[0].name defaultName = files[0].name
@@ -52,7 +52,7 @@ class CreateTorrentPage extends React.Component {
} }
// Default trackers // Default trackers
var trackers = createTorrent.announceList.join('\n') const trackers = createTorrent.announceList.join('\n')
this.state = { this.state = {
comment: '', comment: '',
@@ -72,14 +72,14 @@ class CreateTorrentPage extends React.Component {
} }
render () { render () {
var files = this.state.files const files = this.state.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 const numFiles = files.length
var totalBytes = files const totalBytes = files
.map((f) => f.size) .map((f) => f.size)
.reduce((a, b) => a + b, 0) .reduce((a, b) => a + b, 0)
var torrentInfo = `${numFiles} files, ${prettyBytes(totalBytes)}` const torrentInfo = `${numFiles} files, ${prettyBytes(totalBytes)}`
return ( return (
<div className='create-torrent'> <div className='create-torrent'>
@@ -119,10 +119,10 @@ class CreateTorrentPage extends React.Component {
// * Comment // * Comment
renderAdvanced () { renderAdvanced () {
// Create file list // Create file list
var maxFileElems = 100 const maxFileElems = 100
var files = this.state.files const files = this.state.files
var fileElems = files.slice(0, maxFileElems).map((file, i) => { const fileElems = files.slice(0, maxFileElems).map((file, i) => {
var relativePath = path.relative(this.state.pathPrefix, file.path) const relativePath = path.relative(this.state.pathPrefix, file.path)
return (<div key={i}>{relativePath}</div>) return (<div key={i}>{relativePath}</div>)
}) })
if (files.length > maxFileElems) { if (files.length > maxFileElems) {
@@ -130,8 +130,8 @@ class CreateTorrentPage extends React.Component {
} }
// Align the text fields // Align the text fields
var textFieldStyle = { width: '' } const textFieldStyle = { width: '' }
var textareaStyle = { margin: 0 } const textareaStyle = { margin: 0 }
return ( return (
<div key='advanced' className='create-torrent-advanced'> <div key='advanced' className='create-torrent-advanced'>
@@ -178,11 +178,11 @@ class CreateTorrentPage extends React.Component {
} }
function handleSubmit () { function handleSubmit () {
var announceList = this.state.trackers const announceList = this.state.trackers
.split('\n') .split('\n')
.map((s) => s.trim()) .map((s) => s.trim())
.filter((s) => s !== '') .filter((s) => s !== '')
var options = { const options = {
// We can't let the user choose their own name if we want WebTorrent // We can't let the user choose their own name if we want WebTorrent
// to use the files in place rather than creating a new folder. // to use the files in place rather than creating a new folder.
name: this.state.defaultName, name: this.state.defaultName,
@@ -197,7 +197,8 @@ function handleSubmit () {
// Finds the longest common prefix // Finds the longest common prefix
function findCommonPrefix (a, b) { function findCommonPrefix (a, b) {
for (var i = 0; i < a.length && i < b.length; i++) { let i
for (i = 0; i < a.length && i < b.length; i++) {
if (a.charCodeAt(i) !== b.charCodeAt(i)) break if (a.charCodeAt(i) !== b.charCodeAt(i)) break
} }
if (i === a.length) return a if (i === a.length) return a
@@ -206,7 +207,7 @@ function findCommonPrefix (a, b) {
} }
function containsDots (path, pathPrefix) { function containsDots (path, pathPrefix) {
var suffix = path.substring(pathPrefix.length).replace(/\\/g, '/') const suffix = path.substring(pathPrefix.length).replace(/\\/g, '/')
return ('/' + suffix).includes('/.') return ('/' + suffix).includes('/.')
} }

View File

@@ -13,9 +13,9 @@ module.exports = class Player extends React.Component {
render () { render () {
// Show the video as large as will fit in the window, play immediately // Show the video as large as will fit in the window, play immediately
// If the video is on Chromecast or Airplay, show a title screen instead // If the video is on Chromecast or Airplay, show a title screen instead
var state = this.props.state const state = this.props.state
var showVideo = state.playing.location === 'local' const showVideo = state.playing.location === 'local'
var showControls = state.playing.location !== 'external' const showControls = state.playing.location !== 'external'
return ( return (
<div <div
className='player' className='player'
@@ -39,7 +39,7 @@ function renderMedia (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
// Get the <video> or <audio> tag // Get the <video> or <audio> tag
var mediaElement = document.querySelector(state.playing.type) const mediaElement = document.querySelector(state.playing.type)
if (mediaElement !== null) { if (mediaElement !== null) {
if (state.playing.isPaused && !mediaElement.paused) { if (state.playing.isPaused && !mediaElement.paused) {
mediaElement.pause() mediaElement.pause()
@@ -67,20 +67,20 @@ function renderMedia (state) {
} }
// Switch to the newly added subtitle track, if available // Switch to the newly added subtitle track, if available
var tracks = mediaElement.textTracks || [] const tracks = mediaElement.textTracks || []
for (var j = 0; j < tracks.length; j++) { for (let j = 0; j < tracks.length; j++) {
var isSelectedTrack = j === state.playing.subtitles.selectedIndex const isSelectedTrack = j === state.playing.subtitles.selectedIndex
tracks[j].mode = isSelectedTrack ? 'showing' : 'hidden' tracks[j].mode = isSelectedTrack ? 'showing' : 'hidden'
} }
// Save video position // Save video position
var file = state.getPlayingFileSummary() const file = state.getPlayingFileSummary()
file.currentTime = state.playing.currentTime = mediaElement.currentTime file.currentTime = state.playing.currentTime = mediaElement.currentTime
file.duration = state.playing.duration = mediaElement.duration file.duration = state.playing.duration = mediaElement.duration
// Save selected subtitle // Save selected subtitle
if (state.playing.subtitles.selectedIndex !== -1) { if (state.playing.subtitles.selectedIndex !== -1) {
var index = state.playing.subtitles.selectedIndex const index = state.playing.subtitles.selectedIndex
file.selectedSubtitle = state.playing.subtitles.tracks[index].filePath file.selectedSubtitle = state.playing.subtitles.tracks[index].filePath
} else if (file.selectedSubtitle != null) { } else if (file.selectedSubtitle != null) {
delete file.selectedSubtitle delete file.selectedSubtitle
@@ -90,11 +90,11 @@ function renderMedia (state) {
} }
// Add subtitles to the <video> tag // Add subtitles to the <video> tag
var trackTags = [] const trackTags = []
if (state.playing.subtitles.selectedIndex >= 0) { if (state.playing.subtitles.selectedIndex >= 0) {
for (var i = 0; i < state.playing.subtitles.tracks.length; i++) { for (let i = 0; i < state.playing.subtitles.tracks.length; i++) {
var track = state.playing.subtitles.tracks[i] const track = state.playing.subtitles.tracks[i]
var isSelected = state.playing.subtitles.selectedIndex === i const isSelected = state.playing.subtitles.selectedIndex === i
trackTags.push( trackTags.push(
<track <track
key={i} key={i}
@@ -107,8 +107,8 @@ function renderMedia (state) {
} }
// Create the <audio> or <video> tag // Create the <audio> or <video> tag
var MediaTagName = state.playing.type const MediaTagName = state.playing.type
var mediaTag = ( const mediaTag = (
<MediaTagName <MediaTagName
src={Playlist.getCurrentLocalURL(state)} src={Playlist.getCurrentLocalURL(state)}
onDoubleClick={dispatcher('toggleFullScreen')} onDoubleClick={dispatcher('toggleFullScreen')}
@@ -137,8 +137,8 @@ function renderMedia (state) {
// As soon as we know the video dimensions, resize the window // As soon as we know the video dimensions, resize the window
function onLoadedMetadata (e) { function onLoadedMetadata (e) {
if (state.playing.type !== 'video') return if (state.playing.type !== 'video') return
var video = e.target const video = e.target
var dimensions = { const dimensions = {
width: video.videoWidth, width: video.videoWidth,
height: video.videoHeight height: video.videoHeight
} }
@@ -155,7 +155,7 @@ function renderMedia (state) {
} }
function onCanPlay (e) { function onCanPlay (e) {
var elem = e.target const elem = e.target
if (state.playing.type === 'video' && if (state.playing.type === 'video' &&
elem.webkitVideoDecodedByteCount === 0) { elem.webkitVideoDecodedByteCount === 0) {
dispatch('mediaError', 'Video codec unsupported') dispatch('mediaError', 'Video codec unsupported')
@@ -169,15 +169,15 @@ function renderMedia (state) {
} }
function renderOverlay (state) { function renderOverlay (state) {
var elems = [] const elems = []
var audioMetadataElem = renderAudioMetadata(state) const audioMetadataElem = renderAudioMetadata(state)
var spinnerElem = renderLoadingSpinner(state) const spinnerElem = renderLoadingSpinner(state)
if (audioMetadataElem) elems.push(audioMetadataElem) if (audioMetadataElem) elems.push(audioMetadataElem)
if (spinnerElem) elems.push(spinnerElem) if (spinnerElem) elems.push(spinnerElem)
// Video fills the window, centered with black bars if necessary // Video fills the window, centered with black bars if necessary
// Audio gets a static poster image and a summary of the file metadata. // Audio gets a static poster image and a summary of the file metadata.
var style let style
if (state.playing.type === 'audio') { if (state.playing.type === 'audio') {
style = { backgroundImage: cssBackgroundImagePoster(state) } style = { backgroundImage: cssBackgroundImagePoster(state) }
} else if (elems.length !== 0) { } else if (elems.length !== 0) {
@@ -195,27 +195,27 @@ function renderOverlay (state) {
} }
function renderAudioMetadata (state) { function renderAudioMetadata (state) {
var fileSummary = state.getPlayingFileSummary() const fileSummary = state.getPlayingFileSummary()
if (!fileSummary.audioInfo) return if (!fileSummary.audioInfo) return
var info = fileSummary.audioInfo const info = fileSummary.audioInfo
// Get audio track info // Get audio track info
var title = info.title let title = info.title
if (!title) { if (!title) {
title = fileSummary.name title = fileSummary.name
} }
var artist = info.artist && info.artist[0] let artist = info.artist && info.artist[0]
var album = info.album let album = info.album
if (album && info.year && !album.includes(info.year)) { if (album && info.year && !album.includes(info.year)) {
album += ' (' + info.year + ')' album += ' (' + info.year + ')'
} }
var track let track
if (info.track && info.track.no && info.track.of) { if (info.track && info.track.no && info.track.of) {
track = info.track.no + ' of ' + info.track.of track = info.track.no + ' of ' + info.track.of
} }
// Show a small info box in the middle of the screen with title/album/etc // Show a small info box in the middle of the screen with title/album/etc
var elems = [] const elems = []
if (artist) { if (artist) {
elems.push(( elems.push((
<div key='artist' className='audio-artist'> <div key='artist' className='audio-artist'>
@@ -239,7 +239,7 @@ function renderAudioMetadata (state) {
} }
// Align the title with the other info, if available. Otherwise, center title // Align the title with the other info, if available. Otherwise, center title
var emptyLabel = (<label />) const emptyLabel = (<label />)
elems.unshift(( elems.unshift((
<div key='title' className='audio-title'> <div key='title' className='audio-title'>
{elems.length ? emptyLabel : undefined}{title} {elems.length ? emptyLabel : undefined}{title}
@@ -251,14 +251,14 @@ function renderAudioMetadata (state) {
function renderLoadingSpinner (state) { function renderLoadingSpinner (state) {
if (state.playing.isPaused) return if (state.playing.isPaused) return
var isProbablyStalled = state.playing.isStalled || const isProbablyStalled = state.playing.isStalled ||
(new Date().getTime() - state.playing.lastTimeUpdate > 2000) (new Date().getTime() - state.playing.lastTimeUpdate > 2000)
if (!isProbablyStalled) return if (!isProbablyStalled) return
var prog = state.getPlayingTorrentSummary().progress || {} const prog = state.getPlayingTorrentSummary().progress || {}
var fileProgress = 0 let fileProgress = 0
if (prog.files) { if (prog.files) {
var file = prog.files[state.playing.fileIndex] const file = prog.files[state.playing.fileIndex]
fileProgress = Math.floor(100 * file.numPiecesPresent / file.numPieces) fileProgress = Math.floor(100 * file.numPiecesPresent / file.numPieces)
} }
@@ -275,7 +275,7 @@ function renderLoadingSpinner (state) {
} }
function renderCastScreen (state) { function renderCastScreen (state) {
var castIcon, castType, isCast let castIcon, castType, isCast
if (state.playing.location.startsWith('chromecast')) { if (state.playing.location.startsWith('chromecast')) {
castIcon = 'cast_connected' castIcon = 'cast_connected'
castType = 'Chromecast' castType = 'Chromecast'
@@ -290,8 +290,8 @@ function renderCastScreen (state) {
isCast = true isCast = true
} else if (state.playing.location === 'external') { } else if (state.playing.location === 'external') {
// TODO: get the player name in a more reliable way // TODO: get the player name in a more reliable way
var playerPath = state.saved.prefs.externalPlayerPath const playerPath = state.saved.prefs.externalPlayerPath
var playerName = playerPath ? path.basename(playerPath).split('.')[0] : 'VLC' const playerName = playerPath ? path.basename(playerPath).split('.')[0] : 'VLC'
castIcon = 'tv' castIcon = 'tv'
castType = playerName castType = playerName
isCast = false isCast = false
@@ -301,15 +301,15 @@ function renderCastScreen (state) {
isCast = false isCast = false
} }
var isStarting = state.playing.location.endsWith('-pending') const isStarting = state.playing.location.endsWith('-pending')
var castName = state.playing.castName const castName = state.playing.castName
var castStatus let castStatus
if (isCast && isStarting) castStatus = 'Connecting to ' + castName + '...' if (isCast && isStarting) castStatus = 'Connecting to ' + castName + '...'
else if (isCast && !isStarting) castStatus = 'Connected to ' + castName else if (isCast && !isStarting) castStatus = 'Connected to ' + castName
else castStatus = '' else castStatus = ''
// Show a nice title image, if possible // Show a nice title image, if possible
var style = { const style = {
backgroundImage: cssBackgroundImagePoster(state) backgroundImage: cssBackgroundImagePoster(state)
} }
@@ -327,12 +327,12 @@ function renderCastScreen (state) {
function renderCastOptions (state) { function renderCastOptions (state) {
if (!state.devices.castMenu) return if (!state.devices.castMenu) return
var {location, devices} = state.devices.castMenu const {location, devices} = state.devices.castMenu
var player = state.devices[location] const player = state.devices[location]
var items = devices.map(function (device, ix) { const items = devices.map(function (device, ix) {
var isSelected = player.device === device const isSelected = player.device === device
var name = device.name const name = device.name
return ( return (
<li key={ix} onClick={dispatcher('selectCastDevice', ix)}> <li key={ix} onClick={dispatcher('selectCastDevice', ix)}>
<i className='icon'>{isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i> <i className='icon'>{isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
@@ -349,11 +349,11 @@ function renderCastOptions (state) {
} }
function renderSubtitleOptions (state) { function renderSubtitleOptions (state) {
var subtitles = state.playing.subtitles const subtitles = state.playing.subtitles
if (!subtitles.tracks.length || !subtitles.showMenu) return if (!subtitles.tracks.length || !subtitles.showMenu) return
var items = subtitles.tracks.map(function (track, ix) { const items = subtitles.tracks.map(function (track, ix) {
var isSelected = state.playing.subtitles.selectedIndex === ix const isSelected = state.playing.subtitles.selectedIndex === ix
return ( return (
<li key={ix} onClick={dispatcher('selectSubtitle', ix)}> <li key={ix} onClick={dispatcher('selectSubtitle', ix)}>
<i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i> <i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
@@ -362,8 +362,8 @@ function renderSubtitleOptions (state) {
) )
}) })
var noneSelected = state.playing.subtitles.selectedIndex === -1 const noneSelected = state.playing.subtitles.selectedIndex === -1
var noneClass = 'radio_button_' + (noneSelected ? 'checked' : 'unchecked') const noneClass = 'radio_button_' + (noneSelected ? 'checked' : 'unchecked')
return ( return (
<ul key='subtitle-options' className='options-list'> <ul key='subtitle-options' className='options-list'>
{items} {items}
@@ -376,17 +376,17 @@ function renderSubtitleOptions (state) {
} }
function renderPlayerControls (state) { function renderPlayerControls (state) {
var positionPercent = 100 * state.playing.currentTime / state.playing.duration const positionPercent = 100 * state.playing.currentTime / state.playing.duration
var playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 3px)' } const playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 3px)' }
var captionsClass = state.playing.subtitles.tracks.length === 0 const captionsClass = state.playing.subtitles.tracks.length === 0
? 'disabled' ? 'disabled'
: state.playing.subtitles.selectedIndex >= 0 : state.playing.subtitles.selectedIndex >= 0
? 'active' ? 'active'
: '' : ''
var prevClass = Playlist.hasPrevious(state) ? '' : 'disabled' const prevClass = Playlist.hasPrevious(state) ? '' : 'disabled'
var nextClass = Playlist.hasNext(state) ? '' : 'disabled' const nextClass = Playlist.hasNext(state) ? '' : 'disabled'
var elements = [ const elements = [
<div key='playback-bar' className='playback-bar'> <div key='playback-bar' className='playback-bar'>
{renderLoadingBar(state)} {renderLoadingBar(state)}
<div <div
@@ -444,24 +444,24 @@ function renderPlayerControls (state) {
} }
// If we've detected a Chromecast or AppleTV, the user can play video there // If we've detected a Chromecast or AppleTV, the user can play video there
var castTypes = ['chromecast', 'airplay', 'dlna'] const castTypes = ['chromecast', 'airplay', 'dlna']
var isCastingAnywhere = castTypes.some( const isCastingAnywhere = castTypes.some(
(castType) => state.playing.location.startsWith(castType)) (castType) => state.playing.location.startsWith(castType))
// Add the cast buttons. Icons for each cast type, connected/disconnected: // Add the cast buttons. Icons for each cast type, connected/disconnected:
var buttonIcons = { const buttonIcons = {
'chromecast': {true: 'cast_connected', false: 'cast'}, 'chromecast': {true: 'cast_connected', false: 'cast'},
'airplay': {true: 'airplay', false: 'airplay'}, 'airplay': {true: 'airplay', false: 'airplay'},
'dlna': {true: 'tv', false: 'tv'} 'dlna': {true: 'tv', false: 'tv'}
} }
castTypes.forEach(function (castType) { castTypes.forEach(function (castType) {
// Do we show this button (eg. the Chromecast button) at all? // Do we show this button (eg. the Chromecast button) at all?
var isCasting = state.playing.location.startsWith(castType) const isCasting = state.playing.location.startsWith(castType)
var player = state.devices[castType] const player = state.devices[castType]
if ((!player || player.getDevices().length === 0) && !isCasting) return if ((!player || player.getDevices().length === 0) && !isCasting) return
// Show the button. Three options for eg the Chromecast button: // Show the button. Three options for eg the Chromecast button:
var buttonClass, buttonHandler let buttonClass, buttonHandler
if (isCasting) { if (isCasting) {
// Option 1: we are currently connected to Chromecast. Button stops the cast. // Option 1: we are currently connected to Chromecast. Button stops the cast.
buttonClass = 'active' buttonClass = 'active'
@@ -475,7 +475,7 @@ function renderPlayerControls (state) {
buttonClass = '' buttonClass = ''
buttonHandler = dispatcher('toggleCastMenu', castType) buttonHandler = dispatcher('toggleCastMenu', castType)
} }
var buttonIcon = buttonIcons[castType][isCasting] const buttonIcon = buttonIcons[castType][isCasting]
elements.push(( elements.push((
<i <i
@@ -488,13 +488,13 @@ function renderPlayerControls (state) {
}) })
// Render volume slider // Render volume slider
var volume = state.playing.volume const volume = state.playing.volume
var volumeIcon = 'volume_' + ( const volumeIcon = 'volume_' + (
volume === 0 ? 'off' volume === 0 ? 'off'
: volume < 0.3 ? 'mute' : volume < 0.3 ? 'mute'
: volume < 0.6 ? 'down' : volume < 0.6 ? 'down'
: 'up') : 'up')
var volumeStyle = { const volumeStyle = {
background: '-webkit-gradient(linear, left top, right top, ' + background: '-webkit-gradient(linear, left top, right top, ' +
'color-stop(' + (volume * 100) + '%, #eee), ' + 'color-stop(' + (volume * 100) + '%, #eee), ' +
'color-stop(' + (volume * 100) + '%, #727272))' 'color-stop(' + (volume * 100) + '%, #727272))'
@@ -519,8 +519,8 @@ function renderPlayerControls (state) {
)) ))
// Show video playback progress // Show video playback progress
var currentTimeStr = formatTime(state.playing.currentTime) const currentTimeStr = formatTime(state.playing.currentTime)
var durationStr = formatTime(state.playing.duration) const durationStr = formatTime(state.playing.duration)
elements.push(( elements.push((
<span key='time' className='time float-left'> <span key='time' className='time float-left'>
{currentTimeStr} / {durationStr} {currentTimeStr} / {durationStr}
@@ -547,7 +547,7 @@ function renderPlayerControls (state) {
function handleDragStart (e) { function handleDragStart (e) {
// Prevent the cursor from changing, eg to a green + icon on Mac // Prevent the cursor from changing, eg to a green + icon on Mac
if (e.dataTransfer) { if (e.dataTransfer) {
var dt = e.dataTransfer const dt = e.dataTransfer
dt.effectAllowed = 'none' dt.effectAllowed = 'none'
} }
} }
@@ -556,9 +556,9 @@ function renderPlayerControls (state) {
function handleScrub (e) { function handleScrub (e) {
if (!e.clientX) return if (!e.clientX) return
dispatch('mediaMouseMoved') dispatch('mediaMouseMoved')
var windowWidth = document.querySelector('body').clientWidth const windowWidth = document.querySelector('body').clientWidth
var fraction = e.clientX / windowWidth const fraction = e.clientX / windowWidth
var position = fraction * state.playing.duration /* seconds */ const position = fraction * state.playing.duration /* seconds */
dispatch('skipTo', position) dispatch('skipTo', position)
} }
@@ -589,18 +589,18 @@ function renderPlayerControls (state) {
// Renders the loading bar. Shows which parts of the torrent are loaded, which // Renders the loading bar. Shows which parts of the torrent are loaded, which
// can be 'spongey' / non-contiguous // can be 'spongey' / non-contiguous
function renderLoadingBar (state) { function renderLoadingBar (state) {
var torrentSummary = state.getPlayingTorrentSummary() const torrentSummary = state.getPlayingTorrentSummary()
if (!torrentSummary.progress) { if (!torrentSummary.progress) {
return [] return []
} }
// Find all contiguous parts of the torrent which are loaded // Find all contiguous parts of the torrent which are loaded
var prog = torrentSummary.progress const prog = torrentSummary.progress
var fileProg = prog.files[state.playing.fileIndex] const fileProg = prog.files[state.playing.fileIndex]
var parts = [] const parts = []
var lastPiecePresent = false let lastPiecePresent = false
for (var i = fileProg.startPiece; i <= fileProg.endPiece; i++) { for (let i = fileProg.startPiece; i <= fileProg.endPiece; i++) {
var partPresent = Bitfield.prototype.get.call(prog.bitfield, i) const partPresent = Bitfield.prototype.get.call(prog.bitfield, i)
if (partPresent && !lastPiecePresent) { if (partPresent && !lastPiecePresent) {
parts.push({start: i - fileProg.startPiece, count: 1}) parts.push({start: i - fileProg.startPiece, count: 1})
} else if (partPresent) { } else if (partPresent) {
@@ -610,8 +610,8 @@ function renderLoadingBar (state) {
} }
// Output some bars to show which parts of the file are loaded // Output some bars to show which parts of the file are loaded
var loadingBarElems = parts.map(function (part, i) { const loadingBarElems = parts.map(function (part, i) {
var style = { const style = {
left: (100 * part.start / fileProg.numPieces) + '%', left: (100 * part.start / fileProg.numPieces) + '%',
width: (100 * part.count / fileProg.numPieces) + '%' width: (100 * part.count / fileProg.numPieces) + '%'
} }
@@ -623,8 +623,8 @@ function renderLoadingBar (state) {
// Returns the CSS background-image string for a poster image + dark vignette // Returns the CSS background-image string for a poster image + dark vignette
function cssBackgroundImagePoster (state) { function cssBackgroundImagePoster (state) {
var torrentSummary = state.getPlayingTorrentSummary() const torrentSummary = state.getPlayingTorrentSummary()
var posterPath = TorrentSummary.getPosterPath(torrentSummary) const posterPath = TorrentSummary.getPosterPath(torrentSummary)
if (!posterPath) return '' if (!posterPath) return ''
return cssBackgroundImageDarkGradient() + `, url('${posterPath}')` return cssBackgroundImageDarkGradient() + `, url('${posterPath}')`
} }
@@ -639,12 +639,12 @@ function formatTime (time) {
return '0:00' return '0:00'
} }
var hours = Math.floor(time / 3600) let hours = Math.floor(time / 3600)
var minutes = Math.floor(time % 3600 / 60) let minutes = Math.floor(time % 3600 / 60)
if (hours > 0) { if (hours > 0) {
minutes = zeroFill(2, minutes) minutes = zeroFill(2, minutes)
} }
var seconds = zeroFill(2, Math.floor(time % 60)) let seconds = zeroFill(2, Math.floor(time % 60))
return (hours > 0 ? hours + ':' : '') + minutes + ':' + seconds return (hours > 0 ? hours + ':' : '') + minutes + ':' + seconds
} }

View File

@@ -93,7 +93,7 @@ class PreferencesPage extends React.Component {
} }
setDefaultAppButton () { setDefaultAppButton () {
var isFileHandler = this.props.state.unsaved.prefs.isFileHandler const isFileHandler = this.props.state.unsaved.prefs.isFileHandler
if (isFileHandler) { if (isFileHandler) {
return ( return (
<Preference> <Preference>
@@ -117,7 +117,7 @@ class PreferencesPage extends React.Component {
} }
render () { render () {
var style = { const style = {
color: colors.grey400, color: colors.grey400,
marginLeft: 25, marginLeft: 25,
marginRight: 25 marginRight: 25
@@ -147,7 +147,7 @@ class PreferencesSection extends React.Component {
} }
render () { render () {
var style = { const style = {
marginBottom: 25, marginBottom: 25,
marginTop: 25 marginTop: 25
} }
@@ -162,7 +162,7 @@ class PreferencesSection extends React.Component {
class Preference extends React.Component { class Preference extends React.Component {
render () { render () {
var style = { marginBottom: 10 } const style = { marginBottom: 10 }
return (<div style={style}>{this.props.children}</div>) return (<div style={style}>{this.props.children}</div>)
} }
} }

View File

@@ -7,9 +7,9 @@ const {dispatcher} = require('../lib/dispatcher')
module.exports = class TorrentList extends React.Component { module.exports = class TorrentList extends React.Component {
render () { render () {
var state = this.props.state const state = this.props.state
var contents = [] const contents = []
if (state.downloadPathStatus === 'missing') { if (state.downloadPathStatus === 'missing') {
contents.push( contents.push(
<div key='torrent-missing-path'> <div key='torrent-missing-path'>
@@ -21,7 +21,7 @@ module.exports = class TorrentList extends React.Component {
</div> </div>
) )
} }
var torrentElems = state.saved.torrents.map( const torrentElems = state.saved.torrents.map(
(torrentSummary) => this.renderTorrent(torrentSummary) (torrentSummary) => this.renderTorrent(torrentSummary)
) )
contents.push(...torrentElems) contents.push(...torrentElems)
@@ -39,23 +39,23 @@ module.exports = class TorrentList extends React.Component {
} }
renderTorrent (torrentSummary) { renderTorrent (torrentSummary) {
var state = this.props.state const state = this.props.state
var infoHash = torrentSummary.infoHash const infoHash = torrentSummary.infoHash
var isSelected = infoHash && state.selectedInfoHash === infoHash const isSelected = infoHash && state.selectedInfoHash === infoHash
// Background image: show some nice visuals, like a frame from the movie, if possible // Background image: show some nice visuals, like a frame from the movie, if possible
var style = {} const style = {}
if (torrentSummary.posterFileName) { if (torrentSummary.posterFileName) {
var gradient = isSelected const gradient = isSelected
? 'linear-gradient(to bottom, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.4) 100%)' ? 'linear-gradient(to bottom, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.4) 100%)'
: 'linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 100%)' : 'linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 100%)'
var posterPath = TorrentSummary.getPosterPath(torrentSummary) const posterPath = TorrentSummary.getPosterPath(torrentSummary)
style.backgroundImage = gradient + `, url('${posterPath}')` style.backgroundImage = gradient + `, url('${posterPath}')`
} }
// Foreground: name of the torrent, basic info like size, play button, // Foreground: name of the torrent, basic info like size, play button,
// cast buttons if available, and delete // cast buttons if available, and delete
var classes = ['torrent'] const classes = ['torrent']
// playStatus turns the play button into a loading spinner or error icon // playStatus turns the play button into a loading spinner or error icon
if (torrentSummary.playStatus) classes.push(torrentSummary.playStatus) if (torrentSummary.playStatus) classes.push(torrentSummary.playStatus)
if (isSelected) classes.push('selected') if (isSelected) classes.push('selected')
@@ -77,13 +77,13 @@ module.exports = class TorrentList extends React.Component {
// Show name, download status, % complete // Show name, download status, % complete
renderTorrentMetadata (torrentSummary) { renderTorrentMetadata (torrentSummary) {
var name = torrentSummary.name || 'Loading torrent...' const name = torrentSummary.name || 'Loading torrent...'
var elements = [( const elements = [(
<div key='name' className='name ellipsis'>{name}</div> <div key='name' className='name ellipsis'>{name}</div>
)] )]
// If it's downloading/seeding then show progress info // If it's downloading/seeding then show progress info
var prog = torrentSummary.progress const prog = torrentSummary.progress
if (torrentSummary.error) { if (torrentSummary.error) {
elements.push( elements.push(
<div key='progress-info' className='ellipsis'> <div key='progress-info' className='ellipsis'>
@@ -107,18 +107,18 @@ module.exports = class TorrentList extends React.Component {
return (<div key='metadata' className='metadata'>{elements}</div>) return (<div key='metadata' className='metadata'>{elements}</div>)
function renderProgressBar () { function renderProgressBar () {
var progress = Math.floor(100 * prog.progress) const progress = Math.floor(100 * prog.progress)
return (<progress value={progress} max='100'>{progress}%</progress>) return (<progress value={progress} max='100'>{progress}%</progress>)
} }
function renderPercentProgress () { function renderPercentProgress () {
var progress = Math.floor(100 * prog.progress) const progress = Math.floor(100 * prog.progress)
return (<span key='percent-progress'>{progress}%</span>) return (<span key='percent-progress'>{progress}%</span>)
} }
function renderTotalProgress () { function renderTotalProgress () {
var downloaded = prettyBytes(prog.downloaded) const downloaded = prettyBytes(prog.downloaded)
var total = prettyBytes(prog.length || 0) const total = prettyBytes(prog.length || 0)
if (downloaded === total) { if (downloaded === total) {
return (<span key='total-progress'>{downloaded}</span>) return (<span key='total-progress'>{downloaded}</span>)
} else { } else {
@@ -128,7 +128,7 @@ module.exports = class TorrentList extends React.Component {
function renderPeers () { function renderPeers () {
if (prog.numPeers === 0) return if (prog.numPeers === 0) return
var count = prog.numPeers === 1 ? 'peer' : 'peers' const count = prog.numPeers === 1 ? 'peer' : 'peers'
return (<span key='peers'>{prog.numPeers} {count}</span>) return (<span key='peers'>{prog.numPeers} {count}</span>)
} }
@@ -143,22 +143,22 @@ module.exports = class TorrentList extends React.Component {
} }
function renderEta () { function renderEta () {
var downloaded = prog.downloaded const downloaded = prog.downloaded
var total = prog.length || 0 const total = prog.length || 0
var missing = total - downloaded const missing = total - downloaded
var downloadSpeed = prog.downloadSpeed const downloadSpeed = prog.downloadSpeed
if (downloadSpeed === 0 || missing === 0) return if (downloadSpeed === 0 || missing === 0) return
var rawEta = missing / downloadSpeed const rawEta = missing / downloadSpeed
var hours = Math.floor(rawEta / 3600) % 24 const hours = Math.floor(rawEta / 3600) % 24
var minutes = Math.floor(rawEta / 60) % 60 const minutes = Math.floor(rawEta / 60) % 60
var seconds = Math.floor(rawEta % 60) const seconds = Math.floor(rawEta % 60)
// Only display hours and minutes if they are greater than 0 but always // Only display hours and minutes if they are greater than 0 but always
// display minutes if hours is being displayed // display minutes if hours is being displayed
var hoursStr = hours ? hours + 'h' : '' const hoursStr = hours ? hours + 'h' : ''
var minutesStr = (hours || minutes) ? minutes + 'm' : '' const minutesStr = (hours || minutes) ? minutes + 'm' : ''
var secondsStr = seconds + 's' const secondsStr = seconds + 's'
return (<span>ETA: {hoursStr} {minutesStr} {secondsStr}</span>) return (<span>ETA: {hoursStr} {minutesStr} {secondsStr}</span>)
} }
@@ -167,9 +167,9 @@ module.exports = class TorrentList extends React.Component {
// Download button toggles between torrenting (DL/seed) and paused // Download button toggles between torrenting (DL/seed) and paused
// Play button starts streaming the torrent immediately, unpausing if needed // Play button starts streaming the torrent immediately, unpausing if needed
renderTorrentButtons (torrentSummary) { renderTorrentButtons (torrentSummary) {
var infoHash = torrentSummary.infoHash const infoHash = torrentSummary.infoHash
var playIcon, playTooltip, playClass let playIcon, playTooltip, playClass
if (torrentSummary.playStatus === 'timeout') { if (torrentSummary.playStatus === 'timeout') {
playIcon = 'warning' playIcon = 'warning'
playTooltip = 'Playback timed out. No seeds? No internet? Click to try again.' playTooltip = 'Playback timed out. No seeds? No internet? Click to try again.'
@@ -178,7 +178,7 @@ module.exports = class TorrentList extends React.Component {
playTooltip = 'Start streaming' playTooltip = 'Start streaming'
} }
var downloadIcon, downloadTooltip let downloadIcon, downloadTooltip
if (torrentSummary.status === 'seeding') { if (torrentSummary.status === 'seeding') {
downloadIcon = 'file_upload' downloadIcon = 'file_upload'
downloadTooltip = 'Seeding. Click to stop.' downloadTooltip = 'Seeding. Click to stop.'
@@ -191,7 +191,7 @@ module.exports = class TorrentList extends React.Component {
} }
// Only show the play/dowload buttons for torrents that contain playable media // Only show the play/dowload buttons for torrents that contain playable media
var playButton, downloadButton, positionElem let playButton, downloadButton, positionElem
if (!torrentSummary.error) { if (!torrentSummary.error) {
downloadButton = ( downloadButton = (
<i <i
@@ -205,11 +205,11 @@ module.exports = class TorrentList extends React.Component {
// Do we have a saved position? Show it using a radial progress bar on top // Do we have a saved position? Show it using a radial progress bar on top
// of the play button, unless already showing a spinner there: // of the play button, unless already showing a spinner there:
var willShowSpinner = torrentSummary.playStatus === 'requested' const willShowSpinner = torrentSummary.playStatus === 'requested'
var mostRecentFile = torrentSummary.files && const mostRecentFile = torrentSummary.files &&
torrentSummary.files[torrentSummary.mostRecentFileIndex] torrentSummary.files[torrentSummary.mostRecentFileIndex]
if (mostRecentFile && mostRecentFile.currentTime && !willShowSpinner) { if (mostRecentFile && mostRecentFile.currentTime && !willShowSpinner) {
var fraction = mostRecentFile.currentTime / mostRecentFile.duration const fraction = mostRecentFile.currentTime / mostRecentFile.duration
positionElem = this.renderRadialProgressBar(fraction, 'radial-progress-large') positionElem = this.renderRadialProgressBar(fraction, 'radial-progress-large')
playClass = 'resume-position' playClass = 'resume-position'
} }
@@ -245,9 +245,9 @@ module.exports = class TorrentList extends React.Component {
// Show files, per-file download status and play buttons, and so on // Show files, per-file download status and play buttons, and so on
renderTorrentDetails (torrentSummary) { renderTorrentDetails (torrentSummary) {
var filesElement let filesElement
if (torrentSummary.error || !torrentSummary.files) { if (torrentSummary.error || !torrentSummary.files) {
var message = '' let message = ''
if (torrentSummary.error === 'path-missing') { if (torrentSummary.error === 'path-missing') {
// Special case error: this torrent's download dir or file is missing // Special case error: this torrent's download dir or file is missing
message = 'Missing path: ' + TorrentSummary.getFileOrFolder(torrentSummary) message = 'Missing path: ' + TorrentSummary.getFileOrFolder(torrentSummary)
@@ -268,7 +268,7 @@ module.exports = class TorrentList extends React.Component {
) )
} else { } else {
// We do know the files. List them and show download stats for each one // We do know the files. List them and show download stats for each one
var fileRows = torrentSummary.files const fileRows = torrentSummary.files
.filter((file) => !file.path.includes('/.____padding_file/')) .filter((file) => !file.path.includes('/.____padding_file/'))
.map((file, index) => ({ file, index })) .map((file, index) => ({ file, index }))
.map((object) => this.renderFileRow(torrentSummary, object.file, object.index)) .map((object) => this.renderFileRow(torrentSummary, object.file, object.index))
@@ -295,28 +295,28 @@ module.exports = class TorrentList extends React.Component {
renderFileRow (torrentSummary, file, index) { renderFileRow (torrentSummary, file, index) {
// First, find out how much of the file we've downloaded // First, find out how much of the file we've downloaded
// Are we even torrenting it? // Are we even torrenting it?
var isSelected = torrentSummary.selections && torrentSummary.selections[index] const isSelected = torrentSummary.selections && torrentSummary.selections[index]
var isDone = false // Are we finished torrenting it? let isDone = false // Are we finished torrenting it?
var progress = '' let progress = ''
if (torrentSummary.progress && torrentSummary.progress.files && if (torrentSummary.progress && torrentSummary.progress.files &&
torrentSummary.progress.files[index]) { torrentSummary.progress.files[index]) {
var fileProg = torrentSummary.progress.files[index] const fileProg = torrentSummary.progress.files[index]
isDone = fileProg.numPiecesPresent === fileProg.numPieces isDone = fileProg.numPiecesPresent === fileProg.numPieces
progress = Math.round(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%' progress = Math.round(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%'
} }
// Second, for media files where we saved our position, show how far we got // Second, for media files where we saved our position, show how far we got
var positionElem let positionElem
if (file.currentTime) { if (file.currentTime) {
// Radial progress bar. 0% = start from 0:00, 270% = 3/4 of the way thru // Radial progress bar. 0% = start from 0:00, 270% = 3/4 of the way thru
positionElem = this.renderRadialProgressBar(file.currentTime / file.duration) positionElem = this.renderRadialProgressBar(file.currentTime / file.duration)
} }
// Finally, render the file as a table row // Finally, render the file as a table row
var isPlayable = TorrentPlayer.isPlayable(file) const isPlayable = TorrentPlayer.isPlayable(file)
var infoHash = torrentSummary.infoHash const infoHash = torrentSummary.infoHash
var icon let icon
var handleClick let handleClick
if (isPlayable) { if (isPlayable) {
icon = 'play_arrow' /* playable? add option to play */ icon = 'play_arrow' /* playable? add option to play */
handleClick = dispatcher('playFile', infoHash, index) handleClick = dispatcher('playFile', infoHash, index)
@@ -327,7 +327,7 @@ module.exports = class TorrentList extends React.Component {
: (e) => e.stopPropagation() // noop if file is not ready : (e) => e.stopPropagation() // noop if file is not ready
} }
// TODO: add a css 'disabled' class to indicate that a file cannot be opened/streamed // TODO: add a css 'disabled' class to indicate that a file cannot be opened/streamed
var rowClass = '' let rowClass = ''
if (!isSelected) rowClass = 'disabled' // File deselected, not being torrented if (!isSelected) rowClass = 'disabled' // File deselected, not being torrented
if (!isDone && !isPlayable) rowClass = 'disabled' // Can't open yet, can't stream if (!isDone && !isPlayable) rowClass = 'disabled' // Can't open yet, can't stream
return ( return (
@@ -354,9 +354,9 @@ module.exports = class TorrentList extends React.Component {
} }
renderRadialProgressBar (fraction, cssClass) { renderRadialProgressBar (fraction, cssClass) {
var rotation = 360 * fraction const rotation = 360 * fraction
var transformFill = {transform: 'rotate(' + (rotation / 2) + 'deg)'} const transformFill = {transform: 'rotate(' + (rotation / 2) + 'deg)'}
var transformFix = {transform: 'rotate(' + rotation + 'deg)'} const transformFix = {transform: 'rotate(' + rotation + 'deg)'}
return ( return (
<div key='radial-progress' className={'radial-progress ' + cssClass}> <div key='radial-progress' className={'radial-progress ' + cssClass}>
@@ -376,7 +376,7 @@ module.exports = class TorrentList extends React.Component {
} }
function getErrorMessage (torrentSummary) { function getErrorMessage (torrentSummary) {
var err = torrentSummary.error const err = torrentSummary.error
if (err === 'path-missing') { if (err === 'path-missing') {
return ( return (
<span> <span>

View File

@@ -2,26 +2,26 @@
// process from the main window. // process from the main window.
console.time('init') console.time('init')
var crypto = require('crypto') const crypto = require('crypto')
var deepEqual = require('deep-equal') const deepEqual = require('deep-equal')
var defaultAnnounceList = require('create-torrent').announceList const defaultAnnounceList = require('create-torrent').announceList
var electron = require('electron') const electron = require('electron')
var fs = require('fs-extra') const fs = require('fs-extra')
var musicmetadata = require('musicmetadata') const musicmetadata = require('musicmetadata')
var networkAddress = require('network-address') const networkAddress = require('network-address')
var path = require('path') const path = require('path')
var WebTorrent = require('webtorrent') const WebTorrent = require('webtorrent')
var zeroFill = require('zero-fill') const zeroFill = require('zero-fill')
var crashReporter = require('../crash-reporter') const crashReporter = require('../crash-reporter')
var config = require('../config') const config = require('../config')
var torrentPoster = require('./lib/torrent-poster') const torrentPoster = require('./lib/torrent-poster')
// Report when the process crashes // Report when the process crashes
crashReporter.init() crashReporter.init()
// Send & receive messages from the main window // Send & receive messages from the main window
var ipc = electron.ipcRenderer const ipc = electron.ipcRenderer
// Force use of webtorrent trackers on all torrents // Force use of webtorrent trackers on all torrents
global.WEBTORRENT_ANNOUNCE = defaultAnnounceList global.WEBTORRENT_ANNOUNCE = defaultAnnounceList
@@ -31,7 +31,7 @@ global.WEBTORRENT_ANNOUNCE = defaultAnnounceList
/** /**
* WebTorrent version. * WebTorrent version.
*/ */
var VERSION = require('../../package.json').version const VERSION = require('../../package.json').version
/** /**
* Version number in Azureus-style. Generated from major and minor semver version. * Version number in Azureus-style. Generated from major and minor semver version.
@@ -39,7 +39,7 @@ var VERSION = require('../../package.json').version
* '0.16.1' -> '0016' * '0.16.1' -> '0016'
* '1.2.5' -> '0102' * '1.2.5' -> '0102'
*/ */
var VERSION_STR = VERSION.match(/([0-9]+)/g) const VERSION_STR = VERSION.match(/([0-9]+)/g)
.slice(0, 2) .slice(0, 2)
.map((v) => zeroFill(2, v)) .map((v) => zeroFill(2, v))
.join('') .join('')
@@ -51,19 +51,19 @@ var VERSION_STR = VERSION.match(/([0-9]+)/g)
* For example: * For example:
* '-WW0102-'... * '-WW0102-'...
*/ */
var VERSION_PREFIX = '-WD' + VERSION_STR + '-' const VERSION_PREFIX = '-WD' + VERSION_STR + '-'
// Connect to the WebTorrent and BitTorrent networks. WebTorrent Desktop is a hybrid // Connect to the WebTorrent and BitTorrent networks. WebTorrent Desktop is a hybrid
// client, as explained here: https://webtorrent.io/faq // client, as explained here: https://webtorrent.io/faq
var client = window.client = new WebTorrent({ const client = window.client = new WebTorrent({
peerId: Buffer.from(VERSION_PREFIX + crypto.randomBytes(6).toString('hex')) peerId: Buffer.from(VERSION_PREFIX + crypto.randomBytes(6).toString('hex'))
}) })
// WebTorrent-to-HTTP streaming sever // WebTorrent-to-HTTP streaming sever
var server = null let server = null
// Used for diffing, so we only send progress updates when necessary // Used for diffing, so we only send progress updates when necessary
var prevProgress = null let prevProgress = null
init() init()
@@ -105,7 +105,7 @@ function init () {
function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections) { function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections) {
console.log('starting torrent %s: %s', torrentKey, torrentID) console.log('starting torrent %s: %s', torrentKey, torrentID)
var torrent = client.add(torrentID, { const torrent = client.add(torrentID, {
path: path, path: path,
fileModtimes: fileModtimes fileModtimes: fileModtimes
}) })
@@ -121,15 +121,15 @@ function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections)
} }
function stopTorrenting (infoHash) { function stopTorrenting (infoHash) {
var torrent = client.get(infoHash) const torrent = client.get(infoHash)
if (torrent) torrent.destroy() if (torrent) torrent.destroy()
} }
// Create a new torrent, start seeding // Create a new torrent, start seeding
function createTorrent (torrentKey, options) { function createTorrent (torrentKey, options) {
console.log('creating torrent', torrentKey, options) console.log('creating torrent', torrentKey, options)
var paths = options.files.map((f) => f.path) const paths = options.files.map((f) => f.path)
var torrent = client.seed(paths, options) const torrent = client.seed(paths, options)
torrent.key = torrentKey torrent.key = torrentKey
addTorrentEvents(torrent) addTorrentEvents(torrent)
ipc.send('wt-new-torrent') ipc.send('wt-new-torrent')
@@ -147,14 +147,14 @@ function addTorrentEvents (torrent) {
torrent.on('done', torrentDone) torrent.on('done', torrentDone)
function torrentMetadata () { function torrentMetadata () {
var info = getTorrentInfo(torrent) const info = getTorrentInfo(torrent)
ipc.send('wt-metadata', torrent.key, info) ipc.send('wt-metadata', torrent.key, info)
updateTorrentProgress() updateTorrentProgress()
} }
function torrentReady () { function torrentReady () {
var info = getTorrentInfo(torrent) const info = getTorrentInfo(torrent)
ipc.send('wt-ready', torrent.key, info) ipc.send('wt-ready', torrent.key, info)
ipc.send('wt-ready-' + torrent.infoHash, torrent.key, info) // TODO: hack ipc.send('wt-ready-' + torrent.infoHash, torrent.key, info) // TODO: hack
@@ -162,7 +162,7 @@ function addTorrentEvents (torrent) {
} }
function torrentDone () { function torrentDone () {
var info = getTorrentInfo(torrent) const info = getTorrentInfo(torrent)
ipc.send('wt-done', torrent.key, info) ipc.send('wt-done', torrent.key, info)
updateTorrentProgress() updateTorrentProgress()
@@ -198,9 +198,9 @@ function getTorrentFileInfo (file) {
// Every time we resolve a magnet URI, save the torrent file so that we never // Every time we resolve a magnet URI, save the torrent file so that we never
// have to download it again. Never ask the DHT the same question twice. // have to download it again. Never ask the DHT the same question twice.
function saveTorrentFile (torrentKey) { function saveTorrentFile (torrentKey) {
var torrent = getTorrent(torrentKey) const torrent = getTorrent(torrentKey)
checkIfTorrentFileExists(torrent.infoHash, function (torrentPath, exists) { checkIfTorrentFileExists(torrent.infoHash, function (torrentPath, exists) {
var fileName = torrent.infoHash + '.torrent' const fileName = torrent.infoHash + '.torrent'
if (exists) { if (exists) {
// We've already saved the file // We've already saved the file
return ipc.send('wt-file-saved', torrentKey, fileName) return ipc.send('wt-file-saved', torrentKey, fileName)
@@ -220,7 +220,7 @@ function saveTorrentFile (torrentKey) {
// Checks whether we've already resolved a given infohash to a torrent file // Checks whether we've already resolved a given infohash to a torrent file
// Calls back with (torrentPath, exists). Logs, does not call back on error // Calls back with (torrentPath, exists). Logs, does not call back on error
function checkIfTorrentFileExists (infoHash, cb) { function checkIfTorrentFileExists (infoHash, cb) {
var torrentPath = path.join(config.TORRENT_PATH, infoHash + '.torrent') const torrentPath = path.join(config.TORRENT_PATH, infoHash + '.torrent')
fs.exists(torrentPath, function (exists) { fs.exists(torrentPath, function (exists) {
cb(torrentPath, exists) cb(torrentPath, exists)
}) })
@@ -229,14 +229,14 @@ function checkIfTorrentFileExists (infoHash, cb) {
// Save a JPG that represents a torrent. // Save a JPG that represents a torrent.
// Auto chooses either a frame from a video file, an image, etc // Auto chooses either a frame from a video file, an image, etc
function generateTorrentPoster (torrentKey) { function generateTorrentPoster (torrentKey) {
var torrent = getTorrent(torrentKey) const torrent = getTorrent(torrentKey)
torrentPoster(torrent, function (err, buf, extension) { torrentPoster(torrent, function (err, buf, extension) {
if (err) return console.log('error generating poster: %o', err) if (err) return console.log('error generating poster: %o', err)
// save it for next time // save it for next time
fs.mkdirp(config.POSTER_PATH, function (err) { fs.mkdirp(config.POSTER_PATH, function (err) {
if (err) return console.log('error creating poster dir: %o', err) if (err) return console.log('error creating poster dir: %o', err)
var posterFileName = torrent.infoHash + extension const posterFileName = torrent.infoHash + extension
var posterFilePath = path.join(config.POSTER_PATH, posterFileName) const posterFilePath = path.join(config.POSTER_PATH, posterFileName)
fs.writeFile(posterFilePath, buf, function (err) { fs.writeFile(posterFilePath, buf, function (err) {
if (err) return console.log('error saving poster: %o', err) if (err) return console.log('error saving poster: %o', err)
// show the poster // show the poster
@@ -247,7 +247,7 @@ function generateTorrentPoster (torrentKey) {
} }
function updateTorrentProgress () { function updateTorrentProgress () {
var progress = getTorrentProgress() const progress = getTorrentProgress()
// TODO: diff torrent-by-torrent, not once for the whole update // TODO: diff torrent-by-torrent, not once for the whole update
if (prevProgress && deepEqual(progress, prevProgress, {strict: true})) { if (prevProgress && deepEqual(progress, prevProgress, {strict: true})) {
return /* don't send heavy object if it hasn't changed */ return /* don't send heavy object if it hasn't changed */
@@ -258,19 +258,19 @@ function updateTorrentProgress () {
function getTorrentProgress () { function getTorrentProgress () {
// First, track overall progress // First, track overall progress
var progress = client.progress const progress = client.progress
var hasActiveTorrents = client.torrents.some(function (torrent) { const hasActiveTorrents = client.torrents.some(function (torrent) {
return torrent.progress !== 1 return torrent.progress !== 1
}) })
// Track progress for every file in each torrent // Track progress for every file in each torrent
// TODO: ideally this would be tracked by WebTorrent, which could do it // TODO: ideally this would be tracked by WebTorrent, which could do it
// more efficiently than looping over torrent.bitfield // more efficiently than looping over torrent.bitfield
var torrentProg = client.torrents.map(function (torrent) { const torrentProg = client.torrents.map(function (torrent) {
var fileProg = torrent.files && torrent.files.map(function (file, index) { const fileProg = torrent.files && torrent.files.map(function (file, index) {
var numPieces = file._endPiece - file._startPiece + 1 const numPieces = file._endPiece - file._startPiece + 1
var numPiecesPresent = 0 let numPiecesPresent = 0
for (var piece = file._startPiece; piece <= file._endPiece; piece++) { for (let piece = file._startPiece; piece <= file._endPiece; piece++) {
if (torrent.bitfield.get(piece)) numPiecesPresent++ if (torrent.bitfield.get(piece)) numPiecesPresent++
} }
return { return {
@@ -302,7 +302,7 @@ function getTorrentProgress () {
} }
function startServer (infoHash) { function startServer (infoHash) {
var torrent = client.get(infoHash) const torrent = client.get(infoHash)
if (torrent.ready) startServerFromReadyTorrent(torrent) if (torrent.ready) startServerFromReadyTorrent(torrent)
else torrent.once('ready', () => startServerFromReadyTorrent(torrent)) else torrent.once('ready', () => startServerFromReadyTorrent(torrent))
} }
@@ -313,9 +313,9 @@ function startServerFromReadyTorrent (torrent, cb) {
// start the streaming torrent-to-http server // start the streaming torrent-to-http server
server = torrent.createServer() server = torrent.createServer()
server.listen(0, function () { server.listen(0, function () {
var port = server.address().port const port = server.address().port
var urlSuffix = ':' + port const urlSuffix = ':' + port
var info = { const info = {
torrentKey: torrent.key, torrentKey: torrent.key,
localURL: 'http://localhost' + urlSuffix, localURL: 'http://localhost' + urlSuffix,
networkURL: 'http://' + networkAddress() + urlSuffix networkURL: 'http://' + networkAddress() + urlSuffix
@@ -333,8 +333,8 @@ function stopServer () {
} }
function getAudioMetadata (infoHash, index) { function getAudioMetadata (infoHash, index) {
var torrent = client.get(infoHash) const torrent = client.get(infoHash)
var file = torrent.files[index] const file = torrent.files[index]
musicmetadata(file.createReadStream(), function (err, info) { musicmetadata(file.createReadStream(), function (err, info) {
if (err) return if (err) return
console.log('got audio metadata for %s: %o', file.name, info) console.log('got audio metadata for %s: %o', file.name, info)
@@ -344,7 +344,7 @@ function getAudioMetadata (infoHash, index) {
function selectFiles (torrentOrInfoHash, selections) { function selectFiles (torrentOrInfoHash, selections) {
// Get the torrent object // Get the torrent object
var torrent let torrent
if (typeof torrentOrInfoHash === 'string') { if (typeof torrentOrInfoHash === 'string') {
torrent = client.get(torrentOrInfoHash) torrent = client.get(torrentOrInfoHash)
} else { } else {
@@ -369,8 +369,8 @@ function selectFiles (torrentOrInfoHash, selections) {
torrent.deselect(0, torrent.pieces.length - 1, false) torrent.deselect(0, torrent.pieces.length - 1, false)
// Add selections (individual files) // Add selections (individual files)
for (var i = 0; i < selections.length; i++) { for (let i = 0; i < selections.length; i++) {
var file = torrent.files[i] const file = torrent.files[i]
if (selections[i]) { if (selections[i]) {
file.select() file.select()
} else { } else {
@@ -383,7 +383,7 @@ function selectFiles (torrentOrInfoHash, selections) {
// Gets a WebTorrent handle by torrentKey // Gets a WebTorrent handle by torrentKey
// Throws an Error if we're not currently torrenting anything w/ that key // Throws an Error if we're not currently torrenting anything w/ that key
function getTorrent (torrentKey) { function getTorrent (torrentKey) {
var ret = client.torrents.find((x) => x.key === torrentKey) const ret = client.torrents.find((x) => x.key === torrentKey)
if (!ret) throw new Error('missing torrent key ' + torrentKey) if (!ret) throw new Error('missing torrent key ' + torrentKey)
return ret return ret
} }