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.
#### 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
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 = [
{
CFBundleTypeExtensions: [ 'torrent' ],
CFBundleTypeExtensions: ['torrent'],
CFBundleTypeIconFile: path.basename(config.APP_FILE_ICON) + '.icns',
CFBundleTypeName: 'BitTorrent Document',
CFBundleTypeRole: 'Editor',
LSHandlerRank: 'Owner',
LSItemContentTypes: [ 'org.bittorrent.torrent' ]
LSItemContentTypes: ['org.bittorrent.torrent']
},
{
CFBundleTypeName: 'Any',
CFBundleTypeOSTypes: [ '****' ],
CFBundleTypeOSTypes: ['****'],
CFBundleTypeRole: 'Editor',
LSHandlerRank: 'Owner',
LSTypeIsPackage: false
@@ -219,13 +219,13 @@ function buildDarwin (cb) {
CFBundleTypeRole: 'Editor',
CFBundleURLIconFile: path.basename(config.APP_FILE_ICON) + '.icns',
CFBundleURLName: 'BitTorrent Magnet URL',
CFBundleURLSchemes: [ 'magnet' ]
CFBundleURLSchemes: ['magnet']
},
{
CFBundleTypeRole: 'Editor',
CFBundleURLIconFile: path.basename(config.APP_FILE_ICON) + '.icns',
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',
UTTypeTagSpecification: {
'com.apple.ostype': 'TORR',
'public.filename-extension': [ 'torrent' ],
'public.filename-extension': ['torrent'],
'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",
"auto-launch": "^5.0.5",
"bitfield": "^1.0.2",
"capture-frame": "^2.0.0",
"capture-frame": "^3.0.0",
"chokidar": "^2.0.4",
"chromecasts": "^1.9.1",
"cp-file": "^7.0.0",
"create-torrent": "^3.33.0",
"create-torrent": "^4.0.0",
"debounce": "^1.0.0",
"deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0",
@@ -34,7 +34,7 @@
"mkdirp": "^0.5.1",
"music-metadata": "^3.6.1",
"network-address": "^1.1.0",
"parse-torrent": "^6.0.1",
"parse-torrent": "^7.0.0",
"prettier-bytes": "^1.0.1",
"prop-types": "^15.6.2",
"react": "^16.5.2",
@@ -51,10 +51,10 @@
"zero-fill": "^2.2.3"
},
"devDependencies": {
"babel-eslint": "^9.0.0",
"babel-eslint": "^10.0.2",
"buble": "^0.19.6",
"cross-zip": "^2.0.1",
"depcheck": "^0.7.2",
"depcheck": "^0.8.0",
"electron": "^4.0.0",
"electron-osx-sign": "^0.4.11",
"electron-packager": "~8.5.1",
@@ -70,7 +70,7 @@
"spectron": "^3.3.0",
"standard": "*",
"tape": "^4.9.1",
"walk-sync": "^1.1.3"
"walk-sync": "^2.0.2"
},
"engines": {
"node": ">=4.0.0"

View File

@@ -19,7 +19,7 @@ function openSeedFile () {
log('openSeedFile')
const opts = {
title: 'Select a file for the torrent.',
properties: [ 'openFile' ]
properties: ['openFile']
}
showOpenSeed(opts)
}
@@ -35,11 +35,11 @@ function openSeedDirectory () {
const opts = process.platform === 'darwin'
? {
title: 'Select a file or folder for the torrent.',
properties: [ 'openFile', 'openDirectory' ]
properties: ['openFile', 'openDirectory']
}
: {
title: 'Select a folder for the torrent.',
properties: [ 'openDirectory' ]
properties: ['openDirectory']
}
showOpenSeed(opts)
}
@@ -54,11 +54,11 @@ function openFiles () {
const opts = process.platform === 'darwin'
? {
title: 'Select a file or folder to add.',
properties: [ 'openFile', 'openDirectory' ]
properties: ['openFile', 'openDirectory']
}
: {
title: 'Select a file to add.',
properties: [ 'openFile' ]
properties: ['openFile']
}
setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
@@ -77,7 +77,7 @@ function openTorrentFile () {
const opts = {
title: 'Select a .torrent file.',
filters: [{ name: 'Torrent Files', extensions: ['torrent'] }],
properties: [ 'openFile', 'multiSelections' ]
properties: ['openFile', 'multiSelections']
}
setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {

View File

@@ -42,7 +42,7 @@ function installDarwin () {
function uninstallDarwin () {}
const EXEC_COMMAND = [ process.execPath, '--' ]
const EXEC_COMMAND = [process.execPath, '--']
if (!config.IS_PRODUCTION) {
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
setTimeout(() => windows.main.show(), 100)
processArgv([ torrentId ])
processArgv([torrentId])
} else {
argv.push(torrentId)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -539,9 +539,9 @@ function renderPlayerControls (state) {
// Add the cast buttons. Icons for each cast type, connected/disconnected:
const buttonIcons = {
'chromecast': { true: 'cast_connected', false: 'cast' },
'airplay': { true: 'airplay', false: 'airplay' },
'dlna': { true: 'tv', false: 'tv' }
chromecast: { true: 'cast_connected', false: 'cast' },
airplay: { true: 'airplay', false: 'airplay' },
dlna: { true: 'tv', false: 'tv' }
}
castTypes.forEach(function (castType) {
// Do we show this button (eg. the Chromecast button) at all?

View File

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

View File

@@ -205,7 +205,7 @@ function compareTorrentFile (t, pathActual, fieldsExpected) {
function extractImportantFields (parsedTorrent) {
const { infoHash, name, announce, urlList, comment } = parsedTorrent
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) {