Merge branch 'master' into update-electron

# Conflicts:
#	package-lock.json
#	package.json
This commit is contained in:
Borewit
2019-07-21 10:42:32 +02:00
15 changed files with 408 additions and 499 deletions

View File

@@ -158,6 +158,18 @@ The Mac app can only be packaged from **macOS**.
The Linux app can be packaged from **any** platform. The Linux app can be packaged from **any** platform.
#### Recommended readings to start working in the app
Electron (Framework to make native apps for Windows, OSX and Linux in Javascript):
https://electronjs.org/docs/tutorial/quick-start
React.js (Framework to work with Frontend UI):
https://reactjs.org/docs/getting-started.html
Material UI (React components that implement Google's Material Design.):
https://material-ui.com/getting-started
### Privacy ### Privacy
WebTorrent Desktop collects some basic usage stats to help us make the app better. WebTorrent Desktop collects some basic usage stats to help us make the app better.

View File

@@ -198,16 +198,16 @@ function buildDarwin (cb) {
infoPlist.CFBundleDocumentTypes = [ infoPlist.CFBundleDocumentTypes = [
{ {
CFBundleTypeExtensions: [ 'torrent' ], CFBundleTypeExtensions: ['torrent'],
CFBundleTypeIconFile: path.basename(config.APP_FILE_ICON) + '.icns', CFBundleTypeIconFile: path.basename(config.APP_FILE_ICON) + '.icns',
CFBundleTypeName: 'BitTorrent Document', CFBundleTypeName: 'BitTorrent Document',
CFBundleTypeRole: 'Editor', CFBundleTypeRole: 'Editor',
LSHandlerRank: 'Owner', LSHandlerRank: 'Owner',
LSItemContentTypes: [ 'org.bittorrent.torrent' ] LSItemContentTypes: ['org.bittorrent.torrent']
}, },
{ {
CFBundleTypeName: 'Any', CFBundleTypeName: 'Any',
CFBundleTypeOSTypes: [ '****' ], CFBundleTypeOSTypes: ['****'],
CFBundleTypeRole: 'Editor', CFBundleTypeRole: 'Editor',
LSHandlerRank: 'Owner', LSHandlerRank: 'Owner',
LSTypeIsPackage: false LSTypeIsPackage: false
@@ -219,13 +219,13 @@ function buildDarwin (cb) {
CFBundleTypeRole: 'Editor', CFBundleTypeRole: 'Editor',
CFBundleURLIconFile: path.basename(config.APP_FILE_ICON) + '.icns', CFBundleURLIconFile: path.basename(config.APP_FILE_ICON) + '.icns',
CFBundleURLName: 'BitTorrent Magnet URL', CFBundleURLName: 'BitTorrent Magnet URL',
CFBundleURLSchemes: [ 'magnet' ] CFBundleURLSchemes: ['magnet']
}, },
{ {
CFBundleTypeRole: 'Editor', CFBundleTypeRole: 'Editor',
CFBundleURLIconFile: path.basename(config.APP_FILE_ICON) + '.icns', CFBundleURLIconFile: path.basename(config.APP_FILE_ICON) + '.icns',
CFBundleURLName: 'BitTorrent Stream-Magnet URL', CFBundleURLName: 'BitTorrent Stream-Magnet URL',
CFBundleURLSchemes: [ 'stream-magnet' ] CFBundleURLSchemes: ['stream-magnet']
} }
] ]
@@ -242,7 +242,7 @@ function buildDarwin (cb) {
UTTypeReferenceURL: 'http://www.bittorrent.org/beps/bep_0000.html', UTTypeReferenceURL: 'http://www.bittorrent.org/beps/bep_0000.html',
UTTypeTagSpecification: { UTTypeTagSpecification: {
'com.apple.ostype': 'TORR', 'com.apple.ostype': 'TORR',
'public.filename-extension': [ 'torrent' ], 'public.filename-extension': ['torrent'],
'public.mime-type': 'application/x-bittorrent' 'public.mime-type': 'application/x-bittorrent'
} }
} }

687
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,11 +16,11 @@
"arch": "^2.0.0", "arch": "^2.0.0",
"auto-launch": "^5.0.5", "auto-launch": "^5.0.5",
"bitfield": "^1.0.2", "bitfield": "^1.0.2",
"capture-frame": "^2.0.0", "capture-frame": "^3.0.0",
"chokidar": "^2.0.4", "chokidar": "^2.0.4",
"chromecasts": "^1.9.1", "chromecasts": "^1.9.1",
"cp-file": "^7.0.0", "cp-file": "^7.0.0",
"create-torrent": "^3.33.0", "create-torrent": "^4.0.0",
"debounce": "^1.0.0", "debounce": "^1.0.0",
"deep-equal": "^1.0.1", "deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0", "dlnacasts": "^0.1.0",
@@ -34,7 +34,7 @@
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"music-metadata": "^3.6.1", "music-metadata": "^3.6.1",
"network-address": "^1.1.0", "network-address": "^1.1.0",
"parse-torrent": "^6.0.1", "parse-torrent": "^7.0.0",
"prettier-bytes": "^1.0.1", "prettier-bytes": "^1.0.1",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.5.2", "react": "^16.5.2",
@@ -51,10 +51,10 @@
"zero-fill": "^2.2.3" "zero-fill": "^2.2.3"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^9.0.0", "babel-eslint": "^10.0.2",
"buble": "^0.19.6", "buble": "^0.19.6",
"cross-zip": "^2.0.1", "cross-zip": "^2.0.1",
"depcheck": "^0.7.2", "depcheck": "^0.8.0",
"electron": "^4.0.0", "electron": "^4.0.0",
"electron-osx-sign": "^0.4.11", "electron-osx-sign": "^0.4.11",
"electron-packager": "~8.5.1", "electron-packager": "~8.5.1",
@@ -70,7 +70,7 @@
"spectron": "^3.3.0", "spectron": "^3.3.0",
"standard": "*", "standard": "*",
"tape": "^4.9.1", "tape": "^4.9.1",
"walk-sync": "^1.1.3" "walk-sync": "^2.0.2"
}, },
"engines": { "engines": {
"node": ">=4.0.0" "node": ">=4.0.0"

View File

@@ -19,7 +19,7 @@ function openSeedFile () {
log('openSeedFile') log('openSeedFile')
const opts = { const opts = {
title: 'Select a file for the torrent.', title: 'Select a file for the torrent.',
properties: [ 'openFile' ] properties: ['openFile']
} }
showOpenSeed(opts) showOpenSeed(opts)
} }
@@ -35,11 +35,11 @@ function openSeedDirectory () {
const 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']
} }
: { : {
title: 'Select a folder for the torrent.', title: 'Select a folder for the torrent.',
properties: [ 'openDirectory' ] properties: ['openDirectory']
} }
showOpenSeed(opts) showOpenSeed(opts)
} }
@@ -54,11 +54,11 @@ function openFiles () {
const 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']
} }
: { : {
title: 'Select a file to add.', title: 'Select a file to add.',
properties: [ 'openFile' ] properties: ['openFile']
} }
setTitle(opts.title) setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) { electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
@@ -77,7 +77,7 @@ function openTorrentFile () {
const 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']
} }
setTitle(opts.title) setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) { electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {

View File

@@ -42,7 +42,7 @@ function installDarwin () {
function uninstallDarwin () {} function uninstallDarwin () {}
const 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)

View File

@@ -167,7 +167,7 @@ function onOpen (e, torrentId) {
// Electron issue: https://github.com/atom/electron/issues/4338 // Electron issue: https://github.com/atom/electron/issues/4338
setTimeout(() => windows.main.show(), 100) setTimeout(() => windows.main.show(), 100)
processArgv([ torrentId ]) processArgv([torrentId])
} else { } else {
argv.push(torrentId) argv.push(torrentId)
} }

View File

@@ -77,8 +77,8 @@ function onPlayerPlay () {
function onPlayerUpdate (state) { function onPlayerUpdate (state) {
if (!isEnabled()) return if (!isEnabled()) return
buttons[PREV].flags = [ state.hasPrevious ? 'enabled' : 'disabled' ] buttons[PREV].flags = [state.hasPrevious ? 'enabled' : 'disabled']
buttons[NEXT].flags = [ state.hasNext ? 'enabled' : 'disabled' ] buttons[NEXT].flags = [state.hasNext ? 'enabled' : 'disabled']
update() update()
} }

View File

@@ -32,7 +32,7 @@ class PathSelector extends React.Component {
handleClick () { handleClick () {
const 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)
remote.dialog.showOpenDialog( remote.dialog.showOpenDialog(

View File

@@ -15,8 +15,8 @@ module.exports = class SubtitlesController {
openSubtitles () { openSubtitles () {
remote.dialog.showOpenDialog({ remote.dialog.showOpenDialog({
title: 'Select a subtitles file.', title: 'Select a subtitles file.',
filters: [ { name: 'Subtitles', extensions: ['vtt', 'srt'] } ], filters: [{ name: 'Subtitles', extensions: ['vtt', 'srt'] }],
properties: [ 'openFile' ] properties: ['openFile']
}, (filenames) => { }, (filenames) => {
if (!Array.isArray(filenames)) return if (!Array.isArray(filenames)) return
this.addSubtitles(filenames, true) this.addSubtitles(filenames, true)

View File

@@ -235,100 +235,100 @@ function updateElectron () {
const dispatchHandlers = { const dispatchHandlers = {
// Torrent list: creating, deleting, selecting torrents // Torrent list: creating, deleting, selecting torrents
'openTorrentFile': () => ipcRenderer.send('openTorrentFile'), openTorrentFile: () => ipcRenderer.send('openTorrentFile'),
'openFiles': () => ipcRenderer.send('openFiles'), /* shows the open file dialog */ openFiles: () => ipcRenderer.send('openFiles'), /* shows the open file dialog */
'openTorrentAddress': () => { state.modal = { id: 'open-torrent-address-modal' } }, openTorrentAddress: () => { state.modal = { id: 'open-torrent-address-modal' } },
'addTorrent': (torrentId) => controllers.torrentList().addTorrent(torrentId), addTorrent: (torrentId) => controllers.torrentList().addTorrent(torrentId),
'showCreateTorrent': (paths) => controllers.torrentList().showCreateTorrent(paths), showCreateTorrent: (paths) => controllers.torrentList().showCreateTorrent(paths),
'createTorrent': (options) => controllers.torrentList().createTorrent(options), createTorrent: (options) => controllers.torrentList().createTorrent(options),
'toggleTorrent': (infoHash) => controllers.torrentList().toggleTorrent(infoHash), toggleTorrent: (infoHash) => controllers.torrentList().toggleTorrent(infoHash),
'pauseAllTorrents': () => controllers.torrentList().pauseAllTorrents(), pauseAllTorrents: () => controllers.torrentList().pauseAllTorrents(),
'resumeAllTorrents': () => controllers.torrentList().resumeAllTorrents(), resumeAllTorrents: () => controllers.torrentList().resumeAllTorrents(),
'toggleTorrentFile': (infoHash, index) => toggleTorrentFile: (infoHash, index) =>
controllers.torrentList().toggleTorrentFile(infoHash, index), controllers.torrentList().toggleTorrentFile(infoHash, index),
'confirmDeleteTorrent': (infoHash, deleteData) => confirmDeleteTorrent: (infoHash, deleteData) =>
controllers.torrentList().confirmDeleteTorrent(infoHash, deleteData), controllers.torrentList().confirmDeleteTorrent(infoHash, deleteData),
'deleteTorrent': (infoHash, deleteData) => deleteTorrent: (infoHash, deleteData) =>
controllers.torrentList().deleteTorrent(infoHash, deleteData), controllers.torrentList().deleteTorrent(infoHash, deleteData),
'toggleSelectTorrent': (infoHash) => toggleSelectTorrent: (infoHash) =>
controllers.torrentList().toggleSelectTorrent(infoHash), controllers.torrentList().toggleSelectTorrent(infoHash),
'openTorrentContextMenu': (infoHash) => openTorrentContextMenu: (infoHash) =>
controllers.torrentList().openTorrentContextMenu(infoHash), controllers.torrentList().openTorrentContextMenu(infoHash),
'startTorrentingSummary': (torrentKey) => startTorrentingSummary: (torrentKey) =>
controllers.torrentList().startTorrentingSummary(torrentKey), controllers.torrentList().startTorrentingSummary(torrentKey),
'saveTorrentFileAs': (torrentKey) => saveTorrentFileAs: (torrentKey) =>
controllers.torrentList().saveTorrentFileAs(torrentKey), controllers.torrentList().saveTorrentFileAs(torrentKey),
'prioritizeTorrent': (infoHash) => controllers.torrentList().prioritizeTorrent(infoHash), prioritizeTorrent: (infoHash) => controllers.torrentList().prioritizeTorrent(infoHash),
'resumePausedTorrents': () => controllers.torrentList().resumePausedTorrents(), resumePausedTorrents: () => controllers.torrentList().resumePausedTorrents(),
// Playback // Playback
'playFile': (infoHash, index) => controllers.playback().playFile(infoHash, index), playFile: (infoHash, index) => controllers.playback().playFile(infoHash, index),
'playPause': () => controllers.playback().playPause(), playPause: () => controllers.playback().playPause(),
'nextTrack': () => controllers.playback().nextTrack(), nextTrack: () => controllers.playback().nextTrack(),
'previousTrack': () => controllers.playback().previousTrack(), previousTrack: () => controllers.playback().previousTrack(),
'skip': (time) => controllers.playback().skip(time), skip: (time) => controllers.playback().skip(time),
'skipTo': (time) => controllers.playback().skipTo(time), skipTo: (time) => controllers.playback().skipTo(time),
'changePlaybackRate': (dir) => controllers.playback().changePlaybackRate(dir), changePlaybackRate: (dir) => controllers.playback().changePlaybackRate(dir),
'changeVolume': (delta) => controllers.playback().changeVolume(delta), changeVolume: (delta) => controllers.playback().changeVolume(delta),
'setVolume': (vol) => controllers.playback().setVolume(vol), setVolume: (vol) => controllers.playback().setVolume(vol),
'openItem': (infoHash, index) => controllers.playback().openItem(infoHash, index), openItem: (infoHash, index) => controllers.playback().openItem(infoHash, index),
// Subtitles // Subtitles
'openSubtitles': () => controllers.subtitles().openSubtitles(), openSubtitles: () => controllers.subtitles().openSubtitles(),
'selectSubtitle': (index) => controllers.subtitles().selectSubtitle(index), selectSubtitle: (index) => controllers.subtitles().selectSubtitle(index),
'toggleSubtitlesMenu': () => controllers.subtitles().toggleSubtitlesMenu(), toggleSubtitlesMenu: () => controllers.subtitles().toggleSubtitlesMenu(),
'checkForSubtitles': () => controllers.subtitles().checkForSubtitles(), checkForSubtitles: () => controllers.subtitles().checkForSubtitles(),
'addSubtitles': (files, autoSelect) => controllers.subtitles().addSubtitles(files, autoSelect), addSubtitles: (files, autoSelect) => controllers.subtitles().addSubtitles(files, autoSelect),
// Local media: <video>, <audio>, external players // Local media: <video>, <audio>, external players
'mediaStalled': () => controllers.media().mediaStalled(), mediaStalled: () => controllers.media().mediaStalled(),
'mediaError': (err) => controllers.media().mediaError(err), mediaError: (err) => controllers.media().mediaError(err),
'mediaSuccess': () => controllers.media().mediaSuccess(), mediaSuccess: () => controllers.media().mediaSuccess(),
'mediaTimeUpdate': () => controllers.media().mediaTimeUpdate(), mediaTimeUpdate: () => controllers.media().mediaTimeUpdate(),
'mediaMouseMoved': () => controllers.media().mediaMouseMoved(), mediaMouseMoved: () => controllers.media().mediaMouseMoved(),
'mediaControlsMouseEnter': () => controllers.media().controlsMouseEnter(), mediaControlsMouseEnter: () => controllers.media().controlsMouseEnter(),
'mediaControlsMouseLeave': () => controllers.media().controlsMouseLeave(), mediaControlsMouseLeave: () => controllers.media().controlsMouseLeave(),
'openExternalPlayer': () => controllers.media().openExternalPlayer(), openExternalPlayer: () => controllers.media().openExternalPlayer(),
'externalPlayerNotFound': () => controllers.media().externalPlayerNotFound(), externalPlayerNotFound: () => controllers.media().externalPlayerNotFound(),
// Remote casting: Chromecast, Airplay, etc // Remote casting: Chromecast, Airplay, etc
'toggleCastMenu': (deviceType) => lazyLoadCast().toggleMenu(deviceType), toggleCastMenu: (deviceType) => lazyLoadCast().toggleMenu(deviceType),
'selectCastDevice': (index) => lazyLoadCast().selectDevice(index), selectCastDevice: (index) => lazyLoadCast().selectDevice(index),
'stopCasting': () => lazyLoadCast().stop(), stopCasting: () => lazyLoadCast().stop(),
// Preferences screen // Preferences screen
'preferences': () => controllers.prefs().show(), preferences: () => controllers.prefs().show(),
'updatePreferences': (key, value) => controllers.prefs().update(key, value), updatePreferences: (key, value) => controllers.prefs().update(key, value),
'checkDownloadPath': checkDownloadPath, checkDownloadPath: checkDownloadPath,
'startFolderWatcher': () => controllers.folderWatcher().start(), startFolderWatcher: () => controllers.folderWatcher().start(),
'stopFolderWatcher': () => controllers.folderWatcher().stop(), stopFolderWatcher: () => controllers.folderWatcher().stop(),
// Update (check for new versions on Linux, where there's no auto updater) // Update (check for new versions on Linux, where there's no auto updater)
'updateAvailable': (version) => controllers.update().updateAvailable(version), updateAvailable: (version) => controllers.update().updateAvailable(version),
'skipVersion': (version) => controllers.update().skipVersion(version), skipVersion: (version) => controllers.update().skipVersion(version),
// Navigation between screens (back, forward, ESC, etc) // Navigation between screens (back, forward, ESC, etc)
'exitModal': () => { state.modal = null }, exitModal: () => { state.modal = null },
'backToList': backToList, backToList: backToList,
'escapeBack': escapeBack, escapeBack: escapeBack,
'back': () => state.location.back(), back: () => state.location.back(),
'forward': () => state.location.forward(), forward: () => state.location.forward(),
'cancel': () => state.location.cancel(), cancel: () => state.location.cancel(),
// Controlling the window // Controlling the window
'setDimensions': setDimensions, setDimensions: setDimensions,
'toggleFullScreen': (setTo) => ipcRenderer.send('toggleFullScreen', setTo), toggleFullScreen: (setTo) => ipcRenderer.send('toggleFullScreen', setTo),
'setTitle': (title) => { state.window.title = title }, setTitle: (title) => { state.window.title = title },
'resetTitle': () => { state.window.title = config.APP_WINDOW_TITLE }, resetTitle: () => { state.window.title = config.APP_WINDOW_TITLE },
// Everything else // Everything else
'onOpen': onOpen, onOpen: onOpen,
'error': onError, error: onError,
'uncaughtError': (proc, err) => telemetry.logUncaughtError(proc, err), uncaughtError: (proc, err) => telemetry.logUncaughtError(proc, err),
'stateSave': () => State.save(state), stateSave: () => State.save(state),
'stateSaveImmediate': () => State.saveImmediate(state), stateSaveImmediate: () => State.saveImmediate(state),
'update': () => {} // No-op, just trigger an update update: () => {} // No-op, just trigger an update
} }
// Events from the UI never modify state directly. Instead they call dispatch() // Events from the UI never modify state directly. Instead they call dispatch()
@@ -458,7 +458,7 @@ function setDimensions (dimensions) {
// Called when the user adds files (.torrent, files to seed, subtitles) to the app // Called when the user adds files (.torrent, files to seed, subtitles) to the app
// via any method (drag-drop, drag to app icon, command line) // via any method (drag-drop, drag to app icon, command line)
function onOpen (files) { function onOpen (files) {
if (!Array.isArray(files)) files = [ files ] if (!Array.isArray(files)) files = [files]
// File API seems to transform "magnet:?foo" in "magnet:///?foo" // File API seems to transform "magnet:?foo" in "magnet:///?foo"
// this is a sanitization // this is a sanitization

View File

@@ -12,10 +12,10 @@ const Header = require('../components/header')
const TorrentListPage = require('./torrent-list-page') const TorrentListPage = require('./torrent-list-page')
const Views = { const Views = {
'home': createGetter(() => TorrentListPage), home: createGetter(() => TorrentListPage),
'player': createGetter(() => require('./player-page')), player: createGetter(() => require('./player-page')),
'create-torrent': createGetter(() => require('./create-torrent-page')), 'create-torrent': createGetter(() => require('./create-torrent-page')),
'preferences': createGetter(() => require('./preferences-page')) preferences: createGetter(() => require('./preferences-page'))
} }
const Modals = { const Modals = {

View File

@@ -539,9 +539,9 @@ function renderPlayerControls (state) {
// Add the cast buttons. Icons for each cast type, connected/disconnected: // Add the cast buttons. Icons for each cast type, connected/disconnected:
const 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?

View File

@@ -37,7 +37,7 @@ class PreferencesPage extends React.Component {
<PathSelector <PathSelector
dialog={{ dialog={{
title: 'Select download directory', title: 'Select download directory',
properties: [ 'openDirectory' ] properties: ['openDirectory']
}} }}
onChange={this.handleDownloadPathChange} onChange={this.handleDownloadPathChange}
title='Download location' title='Download location'
@@ -98,7 +98,7 @@ class PreferencesPage extends React.Component {
<PathSelector <PathSelector
dialog={{ dialog={{
title: 'Select media player app', title: 'Select media player app',
properties: [ 'openFile' ] properties: ['openFile']
}} }}
displayValue={playerName} displayValue={playerName}
onChange={this.handleExternalPlayerPathChange} onChange={this.handleExternalPlayerPathChange}
@@ -151,7 +151,7 @@ class PreferencesPage extends React.Component {
<PathSelector <PathSelector
dialog={{ dialog={{
title: 'Select folder to watch for new torrents', title: 'Select folder to watch for new torrents',
properties: [ 'openDirectory' ] properties: ['openDirectory']
}} }}
displayValue={torrentsFolderPath || ''} displayValue={torrentsFolderPath || ''}
onChange={this.handletorrentsFolderPathChange} onChange={this.handletorrentsFolderPathChange}

View File

@@ -205,7 +205,7 @@ function compareTorrentFile (t, pathActual, fieldsExpected) {
function extractImportantFields (parsedTorrent) { function extractImportantFields (parsedTorrent) {
const { infoHash, name, announce, urlList, comment } = parsedTorrent const { infoHash, name, announce, urlList, comment } = parsedTorrent
const priv = parsedTorrent.private // private is a reserved word in JS const priv = parsedTorrent.private // private is a reserved word in JS
return { infoHash, name, announce, urlList, comment, 'private': priv } return { infoHash, name, announce, urlList, comment, private: priv }
} }
function copy (pathFrom, pathTo) { function copy (pathFrom, pathTo) {