From 03bc4cf9b1b9cfbc16242131e0f795651f3b63d5 Mon Sep 17 00:00:00 2001
From: Benjamin Tan
Date: Sun, 31 Jul 2016 16:29:38 +0800
Subject: [PATCH 01/28] Add User Tasks for Windows.
Closes #114.
---
src/main/index.js | 2 ++
src/main/user-tasks.js | 43 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
create mode 100644 src/main/user-tasks.js
diff --git a/src/main/index.js b/src/main/index.js
index c81517e1..20b5a3fe 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -17,6 +17,7 @@ var menu = require('./menu')
var squirrelWin32 = require('./squirrel-win32')
var tray = require('./tray')
var updater = require('./updater')
+var userTasks = require('./user-tasks')
var windows = require('./windows')
var shouldQuit = false
@@ -109,6 +110,7 @@ function delayedInit () {
handlers.install()
tray.init()
updater.init()
+ userTasks.init()
}
function onOpen (e, torrentId) {
diff --git a/src/main/user-tasks.js b/src/main/user-tasks.js
new file mode 100644
index 00000000..47e63f8a
--- /dev/null
+++ b/src/main/user-tasks.js
@@ -0,0 +1,43 @@
+module.exports = {
+ init
+}
+
+var electron = require('electron')
+
+var app = electron.app
+
+/**
+ * Add a user task menu to the app icon on right-click. (Windows)
+ */
+function init () {
+ if (process.platform !== 'win32') return
+ app.setUserTasks(getUserTasks())
+}
+
+function getUserTasks () {
+ return [
+ {
+ arguments: '-n',
+ title: 'Create New Torrent...',
+ description: 'Create a new torrent'
+ },
+ {
+ arguments: '-o',
+ title: 'Open Torrent File...',
+ description: 'Open a .torrent file'
+ },
+ {
+ arguments: '-u',
+ title: 'Open Torrent Address...',
+ description: 'Open a torrent from a URL'
+ }
+ ].map(getUserTasksItem)
+}
+
+function getUserTasksItem (item) {
+ return Object.assign(item, {
+ program: process.execPath,
+ iconPath: process.execPath,
+ iconIndex: 0
+ })
+}
From fc53c68dd931b419cf071443bec2f1219c1ec6b8 Mon Sep 17 00:00:00 2001
From: Benjamin Tan
Date: Sun, 31 Jul 2016 16:36:43 +0800
Subject: [PATCH 02/28] Use `rimraf` instead of `rm -rf` for Windows.
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 492e1a2b..8a53d849 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"scripts": {
"clean": "node ./bin/clean.js",
"open-config": "node ./bin/open-config.js",
- "package": "rm -rf build/ && jsx --es6module src/ build/ && node ./bin/package.js",
+ "package": "rimraf build/ && jsx --es6module src/ build/ && node ./bin/package.js",
"start": "jsx --es6module src/ build/ && electron .",
"test": "standard && node ./bin/check-deps.js",
"update-authors": "./bin/update-authors.sh"
From 91a4c0cff5915bd92dd8b939b26ff8a560cb5103 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Tue, 2 Aug 2016 19:11:06 -0700
Subject: [PATCH 03/28] electron-prebuilt@1.3.2
Changelog: https://github.com/electron/electron/releases/tag/v1.3.2
Nothing in the changelog fixes known WebTorrent Desktop issues.
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 8a53d849..d80c3115 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
"deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0",
"drag-drop": "^2.11.0",
- "electron-prebuilt": "1.3.1",
+ "electron-prebuilt": "1.3.2",
"fs-extra": "^0.30.0",
"hat": "0.0.3",
"iso-639-1": "^1.2.1",
From 87b9dba5685578f5ea51647523d9bd1fa1dcf728 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Wed, 3 Aug 2016 17:06:04 -0700
Subject: [PATCH 04/28] Fix "Cannot read property 'numPiecesPresent' of
undefined"
Fixes #695
---
src/renderer/views/torrent-list.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/renderer/views/torrent-list.js b/src/renderer/views/torrent-list.js
index 74afa8cf..0c9aa403 100644
--- a/src/renderer/views/torrent-list.js
+++ b/src/renderer/views/torrent-list.js
@@ -255,7 +255,8 @@ module.exports = class TorrentList extends React.Component {
var isSelected = torrentSummary.selections && torrentSummary.selections[index]
var isDone = false // Are we finished torrenting it?
var progress = ''
- if (torrentSummary.progress && torrentSummary.progress.files) {
+ if (torrentSummary.progress && torrentSummary.progress.files &&
+ torrentSummary.progress.files[index]) {
var fileProg = torrentSummary.progress.files[index]
isDone = fileProg.numPiecesPresent === fileProg.numPieces
progress = Math.round(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%'
From 67409214a4934fdc67bcb21251bfc5c519442f82 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Wed, 3 Aug 2016 20:26:46 -0700
Subject: [PATCH 05/28] Allow dragging magnet links (Fix #284)
---
package.json | 2 +-
src/renderer/main.js | 7 +++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/package.json b/package.json
index d80c3115..fc34ac6d 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"create-torrent": "^3.24.5",
"deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0",
- "drag-drop": "^2.11.0",
+ "drag-drop": "^2.12.1",
"electron-prebuilt": "1.3.2",
"fs-extra": "^0.30.0",
"hat": "0.0.3",
diff --git a/src/renderer/main.js b/src/renderer/main.js
index b131d997..2fc32c3e 100644
--- a/src/renderer/main.js
+++ b/src/renderer/main.js
@@ -90,8 +90,11 @@ function onState (err, _state) {
app = ReactDOM.render( , document.querySelector('#body'))
// OS integrations:
- // ...drag and drop a torrent or video file to play or seed
- dragDrop('body', onOpen)
+ // ...drag and drop files/text to start torrenting or seeding
+ dragDrop('body', {
+ onDrop: onOpen,
+ onDropText: onOpen
+ })
// ...same thing if you paste a torrent
document.addEventListener('paste', onPaste)
From 29f8ef6b72fa0b1663f48ab4e9d1361ee7b164bd Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 4 Aug 2016 21:04:49 -0700
Subject: [PATCH 06/28] Replace deprecated `react-tools` with `babel`
- Switch to babel, since react-tools has been deprecated since June 12,
2015. See
https://facebook.github.io/react/blog/2015/06/12/deprecating-jstransform
-and-react-tools.html
- Move babel command to "npm run build"
- Move commands for package into "bin/package.js"
---
.babelrc | 5 +++++
bin/check-deps.js | 2 +-
bin/package.js | 7 +++++++
package.json | 8 +++++---
4 files changed, 18 insertions(+), 4 deletions(-)
create mode 100644 .babelrc
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000..2e9146fe
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,5 @@
+{
+ "presets": [
+ "react"
+ ]
+}
diff --git a/bin/check-deps.js b/bin/check-deps.js
index f5e9e42c..fa8dd38a 100755
--- a/bin/check-deps.js
+++ b/bin/check-deps.js
@@ -45,7 +45,7 @@ var BUILT_IN_ELECTRON_MODULES = [ 'electron' ]
var BUILT_IN_DEPS = [].concat(BUILT_IN_NODE_MODULES, BUILT_IN_ELECTRON_MODULES)
-var EXECUTABLE_DEPS = ['gh-release', 'standard', 'react-tools']
+var EXECUTABLE_DEPS = ['gh-release', 'standard', 'babel-cli', 'babel-preset-react']
main()
diff --git a/bin/package.js b/bin/package.js
index 20f037ee..b91c39f1 100755
--- a/bin/package.js
+++ b/bin/package.js
@@ -19,6 +19,7 @@ var config = require('../src/config')
var pkg = require('../package.json')
var BUILD_NAME = config.APP_NAME + '-v' + config.APP_VERSION
+var BUILD_PATH = path.join(config.ROOT_PATH, 'build')
var DIST_PATH = path.join(config.ROOT_PATH, 'dist')
var argv = minimist(process.argv.slice(2), {
@@ -36,6 +37,12 @@ var argv = minimist(process.argv.slice(2), {
function build () {
rimraf.sync(DIST_PATH)
+ rimraf.sync(BUILD_PATH)
+
+ console.log('Babel: Building JSX...')
+ cp.execSync('npm run build', { NODE_ENV: 'production', stdio: 'inherit' })
+ console.log('Babel: Built JSX.')
+
var platform = argv._[0]
if (platform === 'darwin') {
buildDarwin(printDone)
diff --git a/package.json b/package.json
index fc34ac6d..18c74357 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,8 @@
"zero-fill": "^2.2.3"
},
"devDependencies": {
+ "babel-cli": "^6.11.4",
+ "babel-preset-react": "^6.11.1",
"cross-zip": "^2.0.1",
"electron-osx-sign": "^0.3.0",
"electron-packager": "^7.0.0",
@@ -55,7 +57,6 @@
"nobin-debian-installer": "^0.0.10",
"open": "0.0.5",
"plist": "^1.2.0",
- "react-tools": "^0.13.3",
"rimraf": "^2.5.2",
"run-series": "^1.1.4",
"standard": "^7.0.0"
@@ -85,10 +86,11 @@
"url": "git://github.com/feross/webtorrent-desktop.git"
},
"scripts": {
+ "build": "babel src -d build",
"clean": "node ./bin/clean.js",
"open-config": "node ./bin/open-config.js",
- "package": "rimraf build/ && jsx --es6module src/ build/ && node ./bin/package.js",
- "start": "jsx --es6module src/ build/ && electron .",
+ "package": "node ./bin/package.js",
+ "start": "npm run build && electron .",
"test": "standard && node ./bin/check-deps.js",
"update-authors": "./bin/update-authors.sh"
}
From 9b36f9cb220ab43364bc150b15dfeef9eec1f77f Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 4 Aug 2016 21:05:03 -0700
Subject: [PATCH 07/28] Ensure that build folder gets generated before npm
publish
So users using `npm install -g webtorrent-desktop` will always get a
working version.
---
package.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/package.json b/package.json
index 18c74357..cef10d6f 100644
--- a/package.json
+++ b/package.json
@@ -90,6 +90,7 @@
"clean": "node ./bin/clean.js",
"open-config": "node ./bin/open-config.js",
"package": "node ./bin/package.js",
+ "prepublish": "npm run build",
"start": "npm run build && electron .",
"test": "standard && node ./bin/check-deps.js",
"update-authors": "./bin/update-authors.sh"
From 7531ab46237227c53c781662fe2340a29513be46 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 4 Aug 2016 21:37:53 -0700
Subject: [PATCH 08/28] Simplify babel integration further
The "react" preset is composed of a bunch of plugins.
https://babeljs.io/docs/plugins/preset-react/
Turns out, we only need 2 of them, not all 5.
---
.babelrc | 5 +++--
bin/check-deps.js | 8 +++++++-
package.json | 3 ++-
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/.babelrc b/.babelrc
index 2e9146fe..9d3c6b01 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,5 +1,6 @@
{
- "presets": [
- "react"
+ "plugins": [
+ "syntax-jsx",
+ "transform-react-jsx"
]
}
diff --git a/bin/check-deps.js b/bin/check-deps.js
index fa8dd38a..f4a2dafc 100755
--- a/bin/check-deps.js
+++ b/bin/check-deps.js
@@ -45,7 +45,13 @@ var BUILT_IN_ELECTRON_MODULES = [ 'electron' ]
var BUILT_IN_DEPS = [].concat(BUILT_IN_NODE_MODULES, BUILT_IN_ELECTRON_MODULES)
-var EXECUTABLE_DEPS = ['gh-release', 'standard', 'babel-cli', 'babel-preset-react']
+var EXECUTABLE_DEPS = [
+ 'gh-release',
+ 'standard',
+ 'babel-cli',
+ 'babel-plugin-syntax-jsx',
+ 'babel-plugin-transform-react-jsx'
+]
main()
diff --git a/package.json b/package.json
index cef10d6f..8f30bf96 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,8 @@
},
"devDependencies": {
"babel-cli": "^6.11.4",
- "babel-preset-react": "^6.11.1",
+ "babel-plugin-syntax-jsx": "^6.13.0",
+ "babel-plugin-transform-react-jsx": "^6.8.0",
"cross-zip": "^2.0.1",
"electron-osx-sign": "^0.3.0",
"electron-packager": "^7.0.0",
From a8239895c6bd491de50198697584e336d6e70885 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 4 Aug 2016 21:41:37 -0700
Subject: [PATCH 09/28] babel: Add --quiet option
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 8f30bf96..d4724f6d 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"url": "git://github.com/feross/webtorrent-desktop.git"
},
"scripts": {
- "build": "babel src -d build",
+ "build": "babel --quiet src --out-dir build",
"clean": "node ./bin/clean.js",
"open-config": "node ./bin/open-config.js",
"package": "node ./bin/package.js",
From 9afed7fb1b7f3e6c794539dc5f6d58ef52184978 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 4 Aug 2016 21:58:34 -0700
Subject: [PATCH 10/28] Remove --dev flag, Run React in production mode when
Electron is in production mode
---
src/main/index.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/main/index.js b/src/main/index.js
index 20b5a3fe..898f977a 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -23,7 +23,11 @@ var windows = require('./windows')
var shouldQuit = false
var argv = sliceArgv(process.argv)
-if (!argv.includes('--dev')) process.env.NODE_ENV = 'production'
+if (config.IS_PRODUCTION) {
+ // When Electron is running in produdtion mode (packaged app), then run React
+ // in production mode too.
+ process.env.NODE_ENV = 'production'
+}
if (process.platform === 'win32') {
shouldQuit = squirrelWin32.handleEvent(argv[0])
From c1dd0b31cf4e914930e82cc149a2c23c55fe1a07 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 4 Aug 2016 21:59:01 -0700
Subject: [PATCH 11/28] package: Ignore src/ directory since only build/ is
used
@dcposch -- does this look reasonable?
---
bin/package.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bin/package.js b/bin/package.js
index b91c39f1..9f72e190 100755
--- a/bin/package.js
+++ b/bin/package.js
@@ -89,7 +89,7 @@ var all = {
// Pattern which specifies which files to ignore when copying files to create the
// package(s).
- ignore: /^\/dist|\/(appveyor.yml|\.appveyor.yml|\.github|appdmg|AUTHORS|CONTRIBUTORS|bench|benchmark|benchmark\.js|bin|bower\.json|component\.json|coverage|doc|docs|docs\.mli|dragdrop\.min\.js|example|examples|example\.html|example\.js|externs|ipaddr\.min\.js|Makefile|min|minimist|perf|rusha|simplepeer\.min\.js|simplewebsocket\.min\.js|static\/screenshot\.png|test|tests|test\.js|tests\.js|webtorrent\.min\.js|\.[^\/]*|.*\.md|.*\.markdown)$/,
+ ignore: /^\/src|^\/dist|\/(appveyor.yml|\.appveyor.yml|\.github|appdmg|AUTHORS|CONTRIBUTORS|bench|benchmark|benchmark\.js|bin|bower\.json|component\.json|coverage|doc|docs|docs\.mli|dragdrop\.min\.js|example|examples|example\.html|example\.js|externs|ipaddr\.min\.js|Makefile|min|minimist|perf|rusha|simplepeer\.min\.js|simplewebsocket\.min\.js|static\/screenshot\.png|test|tests|test\.js|tests\.js|webtorrent\.min\.js|\.[^\/]*|.*\.md|.*\.markdown)$/,
// The application name.
name: config.APP_NAME,
From c42eb789df3a01b288291266ca7947203e9e3746 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 16:37:25 -0700
Subject: [PATCH 12/28] fix typo
---
src/main/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/index.js b/src/main/index.js
index 898f977a..63a67b95 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -24,7 +24,7 @@ var shouldQuit = false
var argv = sliceArgv(process.argv)
if (config.IS_PRODUCTION) {
- // When Electron is running in produdtion mode (packaged app), then run React
+ // When Electron is running in production mode (packaged app), then run React
// in production mode too.
process.env.NODE_ENV = 'production'
}
From 4126d158211f2f7a0289e011a4bfc7c7976d175b Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 21:41:22 -0700
Subject: [PATCH 13/28] Move .babelrc file into src/
---
.babelrc => src/.babelrc | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename .babelrc => src/.babelrc (100%)
diff --git a/.babelrc b/src/.babelrc
similarity index 100%
rename from .babelrc
rename to src/.babelrc
From 14fcbfcced9d5c427db5187f6c67c04b2da68ed2 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 21:44:32 -0700
Subject: [PATCH 14/28] make logs consistent
---
src/main/announcement.js | 2 +-
src/main/updater.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/announcement.js b/src/main/announcement.js
index 275bc0de..9f7155d0 100644
--- a/src/main/announcement.js
+++ b/src/main/announcement.js
@@ -32,7 +32,7 @@ function init () {
function onResponse (err, res, data) {
if (err) return log(`Failed to retrieve announcement: ${err.message}`)
- if (res.statusCode !== 200) return log('No announcement exists')
+ if (res.statusCode !== 200) return log('No announcement available')
try {
data = JSON.parse(data.toString())
diff --git a/src/main/updater.js b/src/main/updater.js
index 9fe30eb6..d21ab4e2 100644
--- a/src/main/updater.js
+++ b/src/main/updater.js
@@ -63,7 +63,7 @@ function initDarwinWin32 () {
electron.autoUpdater.on(
'update-not-available',
- () => log('Update not available')
+ () => log('No update available')
)
electron.autoUpdater.on(
From 4e2b196b261b7e672d075bdc224e4b33a908ad46 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 22:06:58 -0700
Subject: [PATCH 15/28] CHANGELOG
---
CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5db417f9..3f23efd8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,17 +1,51 @@
# WebTorrent Desktop Version History
+## v0.10.0 - 2016-08-05
+
+### Added
+
+- Drag-and-drop magnet links (selected text) is now supported (#284)
+- Windows: Add "User Tasks" shortcuts to app icon in Start Menu (#114)
+- Linux: Show badge count for completed torrent downloads
+
+### Changed
+
+- Change WebTorrent Desktop peer ID prefix to 'WD' to distinguish from WebTorrent in the browser, 'WW' (#688)
+- Switch UI to React to improve UI rendering speed (#729)
+ - The primary bottleneck was actually `hyperx`, not `virtual-dom`.
+- Update Electron to 1.3.2 (#738) (#739) (#740) (#747) (#756)
+ - Mac 10.9: Fix the fullscreen button showing
+ - Mac 10.9: Fix window having border
+ - Mac 10.9: Fix occasional crash
+ - Mac: Update Squirrel.Mac to 0.2.1 (fixes situations in which updates would not get applied)
+ - Mac: Fix window not showing in Window menu
+ - Mac: Fix context menu always choosing first item by default
+ - Linux: Fix startup crashes (some Linux distros)
+ - Linux: Fix menubar not hiding after entering fullscreen (some Linux distros)
+- Improved location history (back/forward buttons) to fix rare exceptions (#687) (#748)
+ - Location history abstraction released independently as [`location-history`](https://www.npmjs.com/package/location-history)
+
+### Fixed
+
+- When streaming to VLC, set VLC window title to torrent file name (#746)
+- Fix "Cannot read property 'numPiecesPresent' of undefined" exception (#695)
+- Fix rare case where config file could not be completely written (#733)
+
## v0.9.0 - 2016-07-20
### Added
+
- Save selected subtitles
- Ask for confirmation before deleting torrents
- Support Debian Jessie
### Changed
+
- Only send telemetry in production
- Clean up the code. Split main.js, refactor lots of things
### Fixed
+
- Fix state.playing.jumpToTime behavior
- Remove torrent file and poster image when deleting a torrent
From fd433784bd24e6d7d3a3ec7056c25ee8a9ed4403 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 22:26:33 -0700
Subject: [PATCH 16/28] Add Smoke Tests to CONTRIBUTING.md
Fix #582
---
CONTRIBUTING.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a6899da9..048ab258 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -73,3 +73,23 @@ By making a contribution to this project, I certify that:
record of the contribution (including all personal information I submit with it,
including my sign-off) is maintained indefinitely and may be redistributed consistent
with this project or the open source license(s) involved.
+
+## Smoke Tests
+
+Before a release, check that the following basic use cases work correctly:
+
+1. Click "Play" to stream a built-in torrent (e.g. Sintel)
+ - Ensure that seeking to undownloaded region works and plays immediately.
+ - Ensure that sintel.mp4 gets downloaded to `~/Downloads`.
+
+2. Check that the auto-updater works
+ - Open the console and check for the line "No update available" to indicate
+
+3. Add a new .torrent file via drag-and-drop.
+ - Ensure that it gets added to the list and starts downloading
+
+4. Remove a torrent from the client
+ - Ensure that the file is removed from `~/Downloads`
+
+5. Create and seed a new a torrent via drag-and-drop.
+ - Ensure that the torrent gets created and seeding begins.
From 1d55c51a1604a1d728b4bb474281075ad41045ef Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 22:41:37 -0700
Subject: [PATCH 17/28] Improve AUTHORS.md rendering
---
AUTHORS.md | 49 ++++++++++++++++++++++---------------------
bin/update-authors.sh | 10 ++++-----
2 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/AUTHORS.md b/AUTHORS.md
index 034d67e2..b103fd34 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -2,29 +2,30 @@
#### Ordered by first contribution.
-- Feross Aboukhadijeh
-- DC
-- Nate Goldman
-- Chris Morris
-- Giuseppe Crinò
-- Romain Beaumont
-- Dan Flettre
-- Liam Gray
-- grunjol
-- Rémi Jouannet
-- Evan Miller
-- Alex
-- Diego Rodríguez Baquero
-- Karlo Luis Martinez Martos
-- gabriel
-- Rolando Guedes
-- Benjamin Tan
-- Mathias Rasmussen
-- Sergey Bargamon
-- Thomas Watson Steen
-- anonymlol
-- Gediminas Petrikas
-- Adam Gotlib
-- Rémi Jouannet
+- Feross Aboukhadijeh (feross@feross.org)
+- DC (dcposch@dcpos.ch)
+- Nate Goldman (nate@ngoldman.me)
+- Chris Morris (chris@chrismorris.org)
+- Giuseppe Crinò (giuscri@gmail.com)
+- Romain Beaumont (romain.rom1@gmail.com)
+- Dan Flettre (fletd01@yahoo.com)
+- Liam Gray (liam.r.gray@gmail.com)
+- grunjol (grunjol@users.noreply.github.com)
+- Rémi Jouannet (remijouannet@users.noreply.github.com)
+- Evan Miller (miller.evan815@gmail.com)
+- Alex (alxmorais8@msn.com)
+- Diego Rodríguez Baquero (diegorbaquero@gmail.com)
+- Karlo Luis Martinez Martos (karlo.luis.m@gmail.com)
+- gabriel (furstenheim@gmail.com)
+- Rolando Guedes (rolando.guedes@3gnt.net)
+- Benjamin Tan (demoneaux@gmail.com)
+- Mathias Rasmussen (mathiasvr@gmail.com)
+- Sergey Bargamon (sergey@bargamon.ru)
+- Thomas Watson Steen (w@tson.dk)
+- anonymlol (anonymlol7@gmail.com)
+- Gediminas Petrikas (gedas18@gmail.com)
+- Adam Gotlib (gotlib.adam+dev@gmail.com)
+- Rémi Jouannet (remijouannet@gmail.com)
+- Andrea Tupini (tupini07@gmail.com)
#### Generated by bin/update-authors.sh.
diff --git a/bin/update-authors.sh b/bin/update-authors.sh
index a6a6daac..4106eeb9 100755
--- a/bin/update-authors.sh
+++ b/bin/update-authors.sh
@@ -2,16 +2,16 @@
# Update AUTHORS.md based on git history.
-git log --reverse --format='%aN <%aE>' | perl -we '
+git log --reverse --format='%aN (%aE)' | perl -we '
BEGIN {
%seen = (), @authors = ();
}
while (<>) {
next if $seen{$_};
- next if //;
- next if //;
- next if //;
- next if //;
+ next if /(support\@greenkeeper.io)/;
+ next if /(ungoldman\@gmail.com)/;
+ next if /(dc\@DCs-MacBook.local)/;
+ next if /(rolandoguedes\@gmail.com)/;
$seen{$_} = push @authors, "- ", $_;
}
END {
From 11eb603930af0876e205d71dfe3c688eec5ab073 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 5 Aug 2016 22:53:49 -0700
Subject: [PATCH 18/28] 0.10.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index d4724f6d..0eedddf8 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "webtorrent-desktop",
"description": "WebTorrent, the streaming torrent client. For Mac, Windows, and Linux.",
- "version": "0.9.0",
+ "version": "0.10.0",
"author": {
"name": "WebTorrent, LLC",
"email": "feross@webtorrent.io",
From 8233faf5188e7b98d632306936c99c10e5326970 Mon Sep 17 00:00:00 2001
From: DC
Date: Wed, 10 Aug 2016 02:21:10 -0700
Subject: [PATCH 19/28] Pref: default torrent file handler
Before, the app made itself the default torrent file handler automatically, pissing off some of our users. Now, it's not by default, and you can change it in the prefs.
---
src/main/index.js | 2 -
src/main/ipc.js | 9 +++
src/renderer/controllers/prefs-controller.js | 4 ++
src/renderer/lib/migrations.js | 11 +++
src/renderer/views/preferences.js | 73 ++++++++++++++------
5 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/src/main/index.js b/src/main/index.js
index 63a67b95..b422a2dc 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -10,7 +10,6 @@ var config = require('../config')
var crashReporter = require('../crash-reporter')
var dialog = require('./dialog')
var dock = require('./dock')
-var handlers = require('./handlers')
var ipc = require('./ipc')
var log = require('./log')
var menu = require('./menu')
@@ -111,7 +110,6 @@ function init () {
function delayedInit () {
announcement.init()
dock.init()
- handlers.install()
tray.init()
updater.init()
userTasks.init()
diff --git a/src/main/ipc.js b/src/main/ipc.js
index eb4ba876..84f6d61b 100644
--- a/src/main/ipc.js
+++ b/src/main/ipc.js
@@ -8,6 +8,7 @@ var app = electron.app
var dialog = require('./dialog')
var dock = require('./dock')
+var handlers = require('./handlers')
var log = require('./log')
var menu = require('./menu')
var powerSaveBlocker = require('./power-save-blocker')
@@ -91,6 +92,14 @@ function init () {
ipc.on('showItemInFolder', (e, ...args) => shell.showItemInFolder(...args))
ipc.on('moveItemToTrash', (e, ...args) => shell.moveItemToTrash(...args))
+ /**
+ * File handlers
+ */
+ ipc.on('setDefaultFileHandler', (e, flag) => {
+ if (flag) handlers.install()
+ else handlers.uninstall()
+ })
+
/**
* Windows: Main
*/
diff --git a/src/renderer/controllers/prefs-controller.js b/src/renderer/controllers/prefs-controller.js
index 9ba400bf..0c19d2d1 100644
--- a/src/renderer/controllers/prefs-controller.js
+++ b/src/renderer/controllers/prefs-controller.js
@@ -1,5 +1,6 @@
const {dispatch} = require('../lib/dispatcher')
const State = require('../lib/state')
+const ipcRenderer = require('electron').ipcRenderer
// Controls the Preferences screen
module.exports = class PrefsController {
@@ -41,6 +42,9 @@ module.exports = class PrefsController {
// All unsaved prefs take effect atomically, and are saved to config.json
save () {
var state = this.state
+ if (state.unsaved.prefs.isFileHandler !== state.saved.prefs.isFileHandler) {
+ ipcRenderer.send('setDefaultFileHandler', state.unsaved.prefs.isFileHandler)
+ }
state.saved.prefs = Object.assign(state.saved.prefs || {}, state.unsaved.prefs)
State.save(state)
}
diff --git a/src/renderer/lib/migrations.js b/src/renderer/lib/migrations.js
index 7c1aa8a6..b284f4c6 100644
--- a/src/renderer/lib/migrations.js
+++ b/src/renderer/lib/migrations.js
@@ -25,6 +25,10 @@ function run (state) {
migrate_0_7_2(state.saved)
}
+ if (semver.lt(version, '0.11.0')) {
+ migrate_0_11_0(state.saved)
+ }
+
// Config is now on the new version
state.saved.version = config.APP_VERSION
}
@@ -93,3 +97,10 @@ function migrate_0_7_2 (saved) {
}
}
}
+
+function migrate_0_11_0 (saved) {
+ if (saved.prefs.isFileHandler === undefined) {
+ // The app used to make itself the default torrent file handler automatically
+ saved.prefs.isFileHandler = true
+ }
+}
diff --git a/src/renderer/views/preferences.js b/src/renderer/views/preferences.js
index 3caaac93..1518514a 100644
--- a/src/renderer/views/preferences.js
+++ b/src/renderer/views/preferences.js
@@ -22,7 +22,8 @@ function renderGeneralSection (state) {
description: '',
icon: 'settings'
}, [
- renderDownloadDirSelector(state)
+ renderDownloadDirSelector(state),
+ renderFileHandlers(state)
])
}
@@ -43,6 +44,29 @@ function renderDownloadDirSelector (state) {
})
}
+function renderFileHandlers (state) {
+ var definition = {
+ key: 'file-handlers',
+ label: 'Handle Torrent Files'
+ }
+ var buttonText = state.unsaved.prefs.isFileHandler
+ ? 'Remove default app for torrent files'
+ : 'Make WebTorrent the default app for torrent files'
+ var controls = [(
+
+ {buttonText}
+
+ )]
+ return renderControlGroup(definition, controls)
+
+ function toggleFileHandlers () {
+ var isFileHandler = state.unsaved.prefs.isFileHandler
+ dispatch('updatePreferences', 'isFileHandler', !isFileHandler)
+ }
+}
+
// Renders a prefs section.
// - definition should be {icon, title, description}
// - controls should be an array of vdom elements
@@ -73,25 +97,18 @@ function renderSection (definition, controls) {
// - value should be the current pref, a file or folder path
// - callback takes a new file or folder path
function renderFileSelector (definition, value, callback) {
- return (
-
-
-
- {definition.label}
- {definition.description}
-
-
-
-
- folder_open
-
-
-
-
- )
+ var controls = [(
+
+ ), (
+
+ folder_open
+
+ )]
+ return renderControlGroup(definition, controls)
+
function handleClick () {
dialog.showOpenDialog(remote.getCurrentWindow(), definition.options, function (filenames) {
if (!Array.isArray(filenames)) return
@@ -100,6 +117,22 @@ function renderFileSelector (definition, value, callback) {
}
}
+function renderControlGroup (definition, controls) {
+ return (
+
+
+
+ {definition.label}
+ {definition.description}
+
+
+ {controls}
+
+
+
+ )
+}
+
function setStateValue (property, value) {
dispatch('updatePreferences', property, value)
}
From 110e25af73e031d3cff23610fee459887cb1bbb9 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Wed, 10 Aug 2016 16:47:58 -0700
Subject: [PATCH 20/28] electron-prebuilt@1.3.3
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 0eedddf8..a976c471 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
"deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0",
"drag-drop": "^2.12.1",
- "electron-prebuilt": "1.3.2",
+ "electron-prebuilt": "1.3.3",
"fs-extra": "^0.30.0",
"hat": "0.0.3",
"iso-639-1": "^1.2.1",
From 3232e96f6e90d94b43b4610f76c503a5b4d04219 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Wed, 10 Aug 2016 16:48:32 -0700
Subject: [PATCH 21/28] Resize the window's content area
Fixes: https://github.com/feross/webtorrent-desktop/issues/565
This was trivial thanks to a new Electron API in 1.3.3
---
src/main/windows/main.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/main/windows/main.js b/src/main/windows/main.js
index bad4b522..df5d2cf4 100644
--- a/src/main/windows/main.js
+++ b/src/main/windows/main.js
@@ -141,7 +141,9 @@ function setBounds (bounds, maximize) {
bounds.y = Math.round(scr.bounds.y + scr.bounds.height / 2 - bounds.height / 2)
log('setBounds: centered to ' + JSON.stringify(bounds))
}
- main.win.setBounds(bounds, true)
+ // Resize the window's content area (so window border doesn't need to be taken
+ // into account)
+ main.win.setContentBounds(bounds, true)
} else {
log('setBounds: not setting bounds because of window maximization')
}
From 563e1ca0bac3fd202e17a753f5723fab37e8c6c8 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Thu, 11 Aug 2016 00:20:07 -0700
Subject: [PATCH 22/28] Support for instant.io links does not belong in
webtorrent core
---
src/renderer/controllers/torrent-list-controller.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/controllers/torrent-list-controller.js b/src/renderer/controllers/torrent-list-controller.js
index c259184d..802ad8b9 100644
--- a/src/renderer/controllers/torrent-list-controller.js
+++ b/src/renderer/controllers/torrent-list-controller.js
@@ -24,8 +24,8 @@ module.exports = class TorrentListController {
// Use path string instead of W3C File object
torrentId = torrentId.path
}
+
// Allow a instant.io link to be pasted
- // TODO: remove this once support is added to webtorrent core
if (typeof torrentId === 'string' && instantIoRegex.test(torrentId)) {
torrentId = torrentId.slice(torrentId.indexOf('#') + 1)
}
From 4d48b9e7c1cdface563b24f3df42ece6c4ee4f6d Mon Sep 17 00:00:00 2001
From: DC
Date: Wed, 10 Aug 2016 00:53:27 -0700
Subject: [PATCH 23/28] Fix screen stacking bug
You can no longer open a whole stack of Prefs windows, or Create Torrent windows
Simplifies and fixes behavior when dropping files onto the app or the dock icon. Before, you could use drag-drop to create stacks of Create Torrent windows. Now, you can only create torrents from the home screen.
Fixes #665
---
src/main/ipc.js | 5 +-
src/main/menu.js | 76 +++++++++----------
src/main/tray.js | 10 +--
src/main/windows/main.js | 8 +-
src/renderer/controllers/prefs-controller.js | 9 ++-
.../controllers/torrent-list-controller.js | 9 ++-
src/renderer/main.js | 37 ++++-----
.../views/create-torrent-error-page.js | 2 +-
src/renderer/views/create-torrent.js | 2 +-
src/renderer/views/preferences.js | 16 ++--
src/renderer/views/torrent-list.js | 1 +
src/renderer/views/update-available-modal.js | 8 +-
12 files changed, 91 insertions(+), 92 deletions(-)
diff --git a/src/main/ipc.js b/src/main/ipc.js
index 84f6d61b..c5b5db87 100644
--- a/src/main/ipc.js
+++ b/src/main/ipc.js
@@ -61,14 +61,14 @@ function init () {
*/
ipc.on('onPlayerOpen', function () {
- menu.onPlayerOpen()
+ menu.setPlayerOpen(true)
powerSaveBlocker.enable()
shortcuts.enable()
thumbar.enable()
})
ipc.on('onPlayerClose', function () {
- menu.onPlayerClose()
+ menu.setPlayerOpen(false)
powerSaveBlocker.disable()
shortcuts.disable()
thumbar.disable()
@@ -112,6 +112,7 @@ function init () {
ipc.on('setTitle', (e, ...args) => main.setTitle(...args))
ipc.on('show', () => main.show())
ipc.on('toggleFullScreen', (e, ...args) => main.toggleFullScreen(...args))
+ ipc.on('setAllowNav', (e, ...args) => menu.setAllowNav(...args))
/**
* VLC
diff --git a/src/main/menu.js b/src/main/menu.js
index d68a6dfc..9bad2926 100644
--- a/src/main/menu.js
+++ b/src/main/menu.js
@@ -1,11 +1,10 @@
module.exports = {
init,
- onPlayerClose,
- onPlayerOpen,
+ setPlayerOpen,
+ setWindowFocus,
+ setAllowNav,
onToggleAlwaysOnTop,
- onToggleFullScreen,
- onWindowBlur,
- onWindowFocus
+ onToggleFullScreen
}
var electron = require('electron')
@@ -24,26 +23,28 @@ function init () {
electron.Menu.setApplicationMenu(menu)
}
-function onPlayerClose () {
- getMenuItem('Play/Pause').enabled = false
- getMenuItem('Increase Volume').enabled = false
- getMenuItem('Decrease Volume').enabled = false
- getMenuItem('Step Forward').enabled = false
- getMenuItem('Step Backward').enabled = false
- getMenuItem('Increase Speed').enabled = false
- getMenuItem('Decrease Speed').enabled = false
- getMenuItem('Add Subtitles File...').enabled = false
+function setPlayerOpen (flag) {
+ getMenuItem('Play/Pause').enabled = flag
+ getMenuItem('Increase Volume').enabled = flag
+ getMenuItem('Decrease Volume').enabled = flag
+ getMenuItem('Step Forward').enabled = flag
+ getMenuItem('Step Backward').enabled = flag
+ getMenuItem('Increase Speed').enabled = flag
+ getMenuItem('Decrease Speed').enabled = flag
+ getMenuItem('Add Subtitles File...').enabled = flag
}
-function onPlayerOpen () {
- getMenuItem('Play/Pause').enabled = true
- getMenuItem('Increase Volume').enabled = true
- getMenuItem('Decrease Volume').enabled = true
- getMenuItem('Step Forward').enabled = true
- getMenuItem('Step Backward').enabled = true
- getMenuItem('Increase Speed').enabled = true
- getMenuItem('Decrease Speed').enabled = true
- getMenuItem('Add Subtitles File...').enabled = true
+function setWindowFocus (flag) {
+ getMenuItem('Full Screen').enabled = flag
+ getMenuItem('Float on Top').enabled = flag
+}
+
+// Disallow opening more screens on top of the current one.
+function setAllowNav (flag) {
+ getMenuItem('Preferences').enabled = flag
+ getMenuItem('Create New Torrent...').enabled = flag
+ var item = getMenuItem('Create New Torrent from File...')
+ if (item) item.enabled = flag
}
function onToggleAlwaysOnTop (flag) {
@@ -54,16 +55,6 @@ function onToggleFullScreen (flag) {
getMenuItem('Full Screen').checked = flag
}
-function onWindowBlur () {
- getMenuItem('Full Screen').enabled = false
- getMenuItem('Float on Top').enabled = false
-}
-
-function onWindowFocus () {
- getMenuItem('Full Screen').enabled = true
- getMenuItem('Float on Top').enabled = true
-}
-
function getMenuItem (label) {
for (var i = 0; i < menu.items.length; i++) {
var menuItem = menu.items[i].submenu.items.find(function (item) {
@@ -130,14 +121,6 @@ function getMenuTemplate () {
},
{
role: 'selectall'
- },
- {
- type: 'separator'
- },
- {
- label: 'Preferences',
- accelerator: 'CmdOrCtrl+,',
- click: () => windows.main.dispatch('preferences')
}
]
},
@@ -350,6 +333,17 @@ function getMenuTemplate () {
click: () => dialog.openSeedFile()
})
+ // Edit menu (Windows, Linux)
+ template[1].submenu.push(
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Preferences',
+ accelerator: 'CmdOrCtrl+,',
+ click: () => windows.main.dispatch('preferences')
+ })
+
// Help menu (Windows, Linux)
template[4].submenu.push(
{
diff --git a/src/main/tray.js b/src/main/tray.js
index 22a55b69..7816ff4b 100644
--- a/src/main/tray.js
+++ b/src/main/tray.js
@@ -1,8 +1,7 @@
module.exports = {
hasTray,
init,
- onWindowBlur,
- onWindowFocus
+ setWindowFocus
}
var electron = require('electron')
@@ -31,12 +30,7 @@ function hasTray () {
return !!tray
}
-function onWindowBlur () {
- if (!tray) return
- updateTrayMenu()
-}
-
-function onWindowFocus () {
+function setWindowFocus (flag) {
if (!tray) return
updateTrayMenu()
}
diff --git a/src/main/windows/main.js b/src/main/windows/main.js
index df5d2cf4..d60959b6 100644
--- a/src/main/windows/main.js
+++ b/src/main/windows/main.js
@@ -206,13 +206,13 @@ function toggleFullScreen (flag) {
}
function onWindowBlur () {
- menu.onWindowBlur()
- tray.onWindowBlur()
+ menu.setWindowFocus(false)
+ tray.setWindowFocus(false)
}
function onWindowFocus () {
- menu.onWindowFocus()
- tray.onWindowFocus()
+ menu.setWindowFocus(true)
+ tray.setWindowFocus(true)
}
function getIconPath () {
diff --git a/src/renderer/controllers/prefs-controller.js b/src/renderer/controllers/prefs-controller.js
index 0c19d2d1..d220c2b1 100644
--- a/src/renderer/controllers/prefs-controller.js
+++ b/src/renderer/controllers/prefs-controller.js
@@ -1,4 +1,3 @@
-const {dispatch} = require('../lib/dispatcher')
const State = require('../lib/state')
const ipcRenderer = require('electron').ipcRenderer
@@ -16,11 +15,15 @@ module.exports = class PrefsController {
url: 'preferences',
setup: function (cb) {
// initialize preferences
- dispatch('setTitle', 'Preferences')
+ state.window.title = 'Preferences'
state.unsaved = Object.assign(state.unsaved || {}, {prefs: state.saved.prefs || {}})
+ ipcRenderer.send('setAllowNav', false)
cb()
},
- destroy: () => this.save()
+ destroy: () => {
+ ipcRenderer.send('setAllowNav', true)
+ this.save()
+ }
})
}
diff --git a/src/renderer/controllers/torrent-list-controller.js b/src/renderer/controllers/torrent-list-controller.js
index 802ad8b9..5d5a8987 100644
--- a/src/renderer/controllers/torrent-list-controller.js
+++ b/src/renderer/controllers/torrent-list-controller.js
@@ -40,6 +40,11 @@ module.exports = class TorrentListController {
// Shows the Create Torrent page with options to seed a given file or folder
showCreateTorrent (files) {
+ // You can only create torrents from the home screen.
+ if (this.state.location.url() !== 'home') {
+ return dispatch('error', 'Please go back to the torrent list before creating a new torrent.')
+ }
+
// Files will either be an array of file objects, which we can send directly
// to the create-torrent screen
if (files.length === 0 || typeof files[0] !== 'string') {
@@ -67,9 +72,7 @@ module.exports = class TorrentListController {
var state = this.state
var torrentKey = state.nextTorrentKey++
ipcRenderer.send('wt-create-torrent', torrentKey, options)
- state.location.backToFirst(function () {
- state.location.clearForward('create-torrent')
- })
+ state.location.cancel()
}
// Starts downloading and/or seeding a given torrentSummary.
diff --git a/src/renderer/main.js b/src/renderer/main.js
index 2fc32c3e..181a7e63 100644
--- a/src/renderer/main.js
+++ b/src/renderer/main.js
@@ -223,6 +223,7 @@ const dispatchHandlers = {
'escapeBack': escapeBack,
'back': () => state.location.back(),
'forward': () => state.location.forward(),
+ 'cancel': () => state.location.cancel(),
// Controlling the window
'setDimensions': setDimensions,
@@ -360,25 +361,25 @@ function setDimensions (dimensions) {
function onOpen (files) {
if (!Array.isArray(files)) files = [ files ]
- if (state.modal) {
+ var url = state.location.url()
+ var allTorrents = files.every(TorrentPlayer.isTorrent)
+ var allSubtitles = files.every(controllers.subtitles.isSubtitle)
+
+ if (allTorrents) {
+ // Drop torrents onto the app: go to home screen, add torrents, no matter what
+ dispatch('backToList')
+ // All .torrent files? Add them.
+ files.forEach((file) => controllers.torrentList.addTorrent(file))
+ } else if (url === 'player' && allSubtitles) {
+ // Drop subtitles onto a playing video: add subtitles
+ controllers.subtitles.addSubtitles(files, true)
+ } else if (url === 'home') {
+ // Drop files onto home screen: show Create Torrent
state.modal = null
- }
-
- var subtitles = files.filter(controllers.subtitles.isSubtitle)
-
- if (state.location.url() === 'home' || subtitles.length === 0) {
- if (files.every(TorrentPlayer.isTorrent)) {
- if (state.location.url() !== 'home') {
- dispatch('backToList')
- }
- // All .torrent files? Add them.
- files.forEach((file) => controllers.torrentList.addTorrent(file))
- } else {
- // Show the Create Torrent screen. Let's seed those files.
- controllers.torrentList.showCreateTorrent(files)
- }
- } else if (state.location.url() === 'player') {
- controllers.subtitles.addSubtitles(subtitles, true)
+ controllers.torrentList.showCreateTorrent(files)
+ } else {
+ // Drop files onto any other screen: show error
+ return onError('Please go back to the torrent list before creating a new torrent.')
}
update()
diff --git a/src/renderer/views/create-torrent-error-page.js b/src/renderer/views/create-torrent-error-page.js
index b59a360f..3eff6db2 100644
--- a/src/renderer/views/create-torrent-error-page.js
+++ b/src/renderer/views/create-torrent-error-page.js
@@ -16,7 +16,7 @@ module.exports = class CreateTorrentErrorPage extends React.Component {
-
+
Cancel
diff --git a/src/renderer/views/create-torrent.js b/src/renderer/views/create-torrent.js
index 7fe4a308..8407aa3c 100644
--- a/src/renderer/views/create-torrent.js
+++ b/src/renderer/views/create-torrent.js
@@ -89,7 +89,7 @@ module.exports = class CreateTorrentPage extends React.Component {
- Cancel
+ Cancel
Create Torrent
diff --git a/src/renderer/views/preferences.js b/src/renderer/views/preferences.js
index 1518514a..a751e0d8 100644
--- a/src/renderer/views/preferences.js
+++ b/src/renderer/views/preferences.js
@@ -40,7 +40,7 @@ function renderDownloadDirSelector (state) {
},
state.unsaved.prefs.downloadPath,
function (filePath) {
- setStateValue('downloadPath', filePath)
+ dispatch('updatePreferences', 'downloadPath', filePath)
})
}
@@ -98,12 +98,18 @@ function renderSection (definition, controls) {
// - callback takes a new file or folder path
function renderFileSelector (definition, value, callback) {
var controls = [(
-
), (
-
+
folder_open
)]
@@ -132,7 +138,3 @@ function renderControlGroup (definition, controls) {
)
}
-
-function setStateValue (property, value) {
- dispatch('updatePreferences', property, value)
-}
diff --git a/src/renderer/views/torrent-list.js b/src/renderer/views/torrent-list.js
index 0c9aa403..4b85d2dd 100644
--- a/src/renderer/views/torrent-list.js
+++ b/src/renderer/views/torrent-list.js
@@ -44,6 +44,7 @@ module.exports = class TorrentList extends React.Component {
if (torrentSummary.playStatus) classes.push(torrentSummary.playStatus)
if (isSelected) classes.push('selected')
if (!infoHash) classes.push('disabled')
+ if (torrentSummary.torrrentKey) console.error('Missing torrentKey', torrentSummary)
return (
A new version of WebTorrent is available: v{state.modal.version}
We have an auto-updater for Windows and Mac. We don't have one for Linux yet, so you'll have to download the new version manually.
- Skip This Release
- Show Download Page
+ Skip This Release
+ Show Download Page
)
- function handleOK () {
+ function handleShow () {
electron.shell.openExternal('https://github.com/feross/webtorrent-desktop/releases')
dispatch('exitModal')
}
- function handleCancel () {
+ function handleSkip () {
dispatch('skipVersion', state.modal.version)
dispatch('exitModal')
}
From 75cc7383cba13ead8274f60b46af6f4a95ef5142 Mon Sep 17 00:00:00 2001
From: DC
Date: Fri, 12 Aug 2016 09:21:12 -0700
Subject: [PATCH 24/28] Create Torrent: make trackers editable again
Fixes #768
---
src/renderer/views/create-torrent.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/views/create-torrent.js b/src/renderer/views/create-torrent.js
index 8407aa3c..938b12ed 100644
--- a/src/renderer/views/create-torrent.js
+++ b/src/renderer/views/create-torrent.js
@@ -77,7 +77,7 @@ module.exports = class CreateTorrentPage extends React.Component {
Trackers:
-
+
Private:
From 09d6fa550adce28187aa86ee625935f383e90e64 Mon Sep 17 00:00:00 2001
From: DC
Date: Fri, 12 Aug 2016 09:31:28 -0700
Subject: [PATCH 25/28] Handle Save Torrent File As... -> Cancel
---
src/renderer/controllers/torrent-list-controller.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/renderer/controllers/torrent-list-controller.js b/src/renderer/controllers/torrent-list-controller.js
index 5d5a8987..bb39ce97 100644
--- a/src/renderer/controllers/torrent-list-controller.js
+++ b/src/renderer/controllers/torrent-list-controller.js
@@ -274,6 +274,7 @@ function saveTorrentFileAs (torrentSummary) {
]
}
electron.remote.dialog.showSaveDialog(electron.remote.getCurrentWindow(), opts, function (savePath) {
+ if (!savePath) return // They clicked Cancel
var torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
fs.readFile(torrentPath, function (err, torrentFile) {
if (err) return dispatch('error', err)
From 45d46d7ae826eb304f23d108087dc3bad93613a6 Mon Sep 17 00:00:00 2001
From: Feross Aboukhadijeh
Date: Fri, 12 Aug 2016 15:35:50 -0700
Subject: [PATCH 26/28] show title on 'create new torrent' page
---
src/renderer/controllers/playback-controller.js | 2 +-
src/renderer/controllers/torrent-list-controller.js | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/renderer/controllers/playback-controller.js b/src/renderer/controllers/playback-controller.js
index c80489af..302ade81 100644
--- a/src/renderer/controllers/playback-controller.js
+++ b/src/renderer/controllers/playback-controller.js
@@ -242,7 +242,7 @@ module.exports = class PlaybackController {
}
// otherwise, play the video
- dispatch('setTitle', torrentSummary.files[state.playing.fileIndex].name)
+ state.window.title = torrentSummary.files[state.playing.fileIndex].name
this.update()
ipcRenderer.send('onPlayerOpen')
diff --git a/src/renderer/controllers/torrent-list-controller.js b/src/renderer/controllers/torrent-list-controller.js
index 5d5a8987..808d5d72 100644
--- a/src/renderer/controllers/torrent-list-controller.js
+++ b/src/renderer/controllers/torrent-list-controller.js
@@ -50,7 +50,11 @@ module.exports = class TorrentListController {
if (files.length === 0 || typeof files[0] !== 'string') {
this.state.location.go({
url: 'create-torrent',
- files: files
+ files: files,
+ setup: (cb) => {
+ this.state.window.title = 'Create New Torrent'
+ cb(null)
+ }
})
return
}
From 1ec305162ef29c8925cf23c4de9f6e7d76448b2b Mon Sep 17 00:00:00 2001
From: DC
Date: Fri, 12 Aug 2016 20:54:57 -0700
Subject: [PATCH 27/28] Check for missing download path
Fixes #646
---
src/renderer/controllers/prefs-controller.js | 2 ++
src/renderer/main.js | 27 ++++++++++++++---
src/renderer/views/preferences.js | 4 +--
src/renderer/views/torrent-list.js | 32 ++++++++++++++++----
static/main.css | 7 +++++
5 files changed, 59 insertions(+), 13 deletions(-)
diff --git a/src/renderer/controllers/prefs-controller.js b/src/renderer/controllers/prefs-controller.js
index d220c2b1..97171c8a 100644
--- a/src/renderer/controllers/prefs-controller.js
+++ b/src/renderer/controllers/prefs-controller.js
@@ -1,4 +1,5 @@
const State = require('../lib/state')
+const {dispatch} = require('../lib/dispatcher')
const ipcRenderer = require('electron').ipcRenderer
// Controls the Preferences screen
@@ -50,5 +51,6 @@ module.exports = class PrefsController {
}
state.saved.prefs = Object.assign(state.saved.prefs || {}, state.unsaved.prefs)
State.save(state)
+ dispatch('checkDownloadPath')
}
}
diff --git a/src/renderer/main.js b/src/renderer/main.js
index 181a7e63..bfb1c4f0 100644
--- a/src/renderer/main.js
+++ b/src/renderer/main.js
@@ -7,6 +7,7 @@ const dragDrop = require('drag-drop')
const electron = require('electron')
const React = require('react')
const ReactDOM = require('react-dom')
+const fs = require('fs')
const config = require('../config')
const App = require('./views/app')
@@ -74,6 +75,12 @@ function onState (err, _state) {
}
})
+ // Calling update() updates the UI given the current state
+ // Do this at least once a second to give every file in every torrentSummary
+ // a progress bar and to keep the cursor in sync when playing a video
+ setInterval(update, 1000)
+ app = ReactDOM.render( , document.querySelector('#body'))
+
// Restart everything we were torrenting last time the app ran
resumeTorrents()
@@ -83,11 +90,8 @@ function onState (err, _state) {
// Listen for messages from the main process
setupIpc()
- // Calling update() updates the UI given the current state
- // Do this at least once a second to give every file in every torrentSummary
- // a progress bar and to keep the cursor in sync when playing a video
- setInterval(update, 1000)
- app = ReactDOM.render( , document.querySelector('#body'))
+ // Warn if the download dir is gone, eg b/c an external drive is unplugged
+ checkDownloadPath()
// OS integrations:
// ...drag and drop files/text to start torrenting or seeding
@@ -212,6 +216,7 @@ const dispatchHandlers = {
// Preferences screen
'preferences': () => controllers.prefs.show(),
'updatePreferences': (key, value) => controllers.prefs.update(key, value),
+ 'checkDownloadPath': checkDownloadPath,
// Update (check for new versions on Linux, where there's no auto updater)
'updateAvailable': (version) => controllers.update.updateAvailable(version),
@@ -433,3 +438,15 @@ function onFullscreenChanged (e, isFullScreen) {
update()
}
+
+function checkDownloadPath () {
+ state.downloadPathStatus = undefined
+ fs.stat(state.saved.prefs.downloadPath, function (err, stat) {
+ if (err) {
+ state.downloadPathStatus = 'missing'
+ return console.error(err)
+ }
+ if (stat.isDirectory()) state.downloadPathStatus = 'ok'
+ else state.downloadPathStatus = 'missing'
+ })
+}
diff --git a/src/renderer/views/preferences.js b/src/renderer/views/preferences.js
index a751e0d8..c4d2feba 100644
--- a/src/renderer/views/preferences.js
+++ b/src/renderer/views/preferences.js
@@ -22,12 +22,12 @@ function renderGeneralSection (state) {
description: '',
icon: 'settings'
}, [
- renderDownloadDirSelector(state),
+ renderDownloadPathSelector(state),
renderFileHandlers(state)
])
}
-function renderDownloadDirSelector (state) {
+function renderDownloadPathSelector (state) {
return renderFileSelector({
key: 'download-path',
label: 'Download Path',
diff --git a/src/renderer/views/torrent-list.js b/src/renderer/views/torrent-list.js
index 4b85d2dd..a4849906 100644
--- a/src/renderer/views/torrent-list.js
+++ b/src/renderer/views/torrent-list.js
@@ -8,16 +8,36 @@ const {dispatcher} = require('../lib/dispatcher')
module.exports = class TorrentList extends React.Component {
render () {
var state = this.props.state
- var torrentRows = state.saved.torrents.map(
- (torrentSummary) => this.renderTorrent(torrentSummary)
- )
- return (
-
- {torrentRows}
+ var contents
+ if (!state.downloadPathStatus) {
+ contents = ''
+ } else if (state.downloadPathStatus === 'missing') {
+ contents = (
+
+
Download path missing: {state.saved.prefs.downloadPath}
+
Check that all drives are connected?
+
Alternatively, choose a new download path in
+ Preferences
+
+
+ )
+ } else if (state.downloadPathStatus === 'ok') {
+ contents = state.saved.torrents.map(
+ (torrentSummary) => this.renderTorrent(torrentSummary)
+ )
+ contents.push(
Drop a torrent file here or paste a magnet link
+ )
+ } else {
+ throw new Error('Unhandled downloadPathStatus ' + state.downloadPathStatus)
+ }
+
+ return (
+
+ {contents}
)
}
diff --git a/static/main.css b/static/main.css
index d56c9838..902c4c4e 100644
--- a/static/main.css
+++ b/static/main.css
@@ -551,6 +551,13 @@ input[type='text'] {
line-height: 1.5em;
}
+/*
+ * TORRENT LIST: ERRORS
+ */
+.torrent-list p {
+ padding: 5px 20px;
+}
+
/*
* TORRENT LIST: DRAG-DROP TARGET
*/
From 0809e20a6e1de917a2f8315c2f1da3b9ef177a43 Mon Sep 17 00:00:00 2001
From: DC
Date: Sat, 13 Aug 2016 20:28:20 -0700
Subject: [PATCH 28/28] Check path for each torrent
---
.../controllers/playback-controller.js | 2 +-
.../controllers/torrent-list-controller.js | 28 +++--
src/renderer/lib/state.js | 3 +
src/renderer/main.js | 20 ++--
src/renderer/views/torrent-list.js | 107 ++++++++++++------
static/main.css | 8 +-
6 files changed, 110 insertions(+), 58 deletions(-)
diff --git a/src/renderer/controllers/playback-controller.js b/src/renderer/controllers/playback-controller.js
index c80489af..301354d4 100644
--- a/src/renderer/controllers/playback-controller.js
+++ b/src/renderer/controllers/playback-controller.js
@@ -188,7 +188,7 @@ module.exports = class PlaybackController {
}, 10000) /* give it a few seconds */
if (torrentSummary.status === 'paused') {
- dispatch('startTorrentingSummary', torrentSummary)
+ dispatch('startTorrentingSummary', torrentSummary.torrentKey)
ipcRenderer.once('wt-ready-' + torrentSummary.infoHash,
() => this.openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb))
} else {
diff --git a/src/renderer/controllers/torrent-list-controller.js b/src/renderer/controllers/torrent-list-controller.js
index bb39ce97..647ddf15 100644
--- a/src/renderer/controllers/torrent-list-controller.js
+++ b/src/renderer/controllers/torrent-list-controller.js
@@ -76,21 +76,25 @@ module.exports = class TorrentListController {
}
// Starts downloading and/or seeding a given torrentSummary.
- startTorrentingSummary (torrentSummary) {
- var s = torrentSummary
-
- // Backward compatibility for config files save before we had torrentKey
- if (!s.torrentKey) s.torrentKey = this.state.nextTorrentKey++
+ startTorrentingSummary (torrentKey) {
+ var s = TorrentSummary.getByKey(this.state, torrentKey)
+ if (!s) throw new Error('Missing key: ' + torrentKey)
// Use Downloads folder by default
if (!s.path) s.path = this.state.saved.prefs.downloadPath
- ipcRenderer.send('wt-start-torrenting',
- s.torrentKey,
- TorrentSummary.getTorrentID(s),
- s.path,
- s.fileModtimes,
- s.selections)
+ fs.stat(TorrentSummary.getFileOrFolder(s), function (err) {
+ if (err) {
+ s.error = 'path-missing'
+ return
+ }
+ ipcRenderer.send('wt-start-torrenting',
+ s.torrentKey,
+ TorrentSummary.getTorrentID(s),
+ s.path,
+ s.fileModtimes,
+ s.selections)
+ })
}
// TODO: use torrentKey, not infoHash
@@ -98,7 +102,7 @@ module.exports = class TorrentListController {
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
if (torrentSummary.status === 'paused') {
torrentSummary.status = 'new'
- this.startTorrentingSummary(torrentSummary)
+ this.startTorrentingSummary(torrentSummary.torrentKey)
sound.play('ENABLE')
} else {
torrentSummary.status = 'paused'
diff --git a/src/renderer/lib/state.js b/src/renderer/lib/state.js
index 3205e1df..04350337 100644
--- a/src/renderer/lib/state.js
+++ b/src/renderer/lib/state.js
@@ -200,6 +200,9 @@ function save (state, cb) {
if (key === 'playStatus') {
continue // Don't save whether a torrent is playing / pending
}
+ if (key === 'error') {
+ continue // Don't save error states
+ }
torrent[key] = x[key]
}
return torrent
diff --git a/src/renderer/main.js b/src/renderer/main.js
index bfb1c4f0..15fd2183 100644
--- a/src/renderer/main.js
+++ b/src/renderer/main.js
@@ -75,15 +75,15 @@ function onState (err, _state) {
}
})
+ // Restart everything we were torrenting last time the app ran
+ resumeTorrents()
+
// Calling update() updates the UI given the current state
// Do this at least once a second to give every file in every torrentSummary
// a progress bar and to keep the cursor in sync when playing a video
setInterval(update, 1000)
app = ReactDOM.render( , document.querySelector('#body'))
- // Restart everything we were torrenting last time the app ran
- resumeTorrents()
-
// Lazy-load other stuff, like the AppleTV module, later to keep startup fast
window.setTimeout(delayedInit, config.DELAYED_INIT)
@@ -179,8 +179,7 @@ const dispatchHandlers = {
'deleteTorrent': (infoHash, deleteData) => controllers.torrentList.deleteTorrent(infoHash, deleteData),
'toggleSelectTorrent': (infoHash) => controllers.torrentList.toggleSelectTorrent(infoHash),
'openTorrentContextMenu': (infoHash) => controllers.torrentList.openTorrentContextMenu(infoHash),
- 'startTorrentingSummary': (torrentSummary) =>
- controllers.torrentList.startTorrentingSummary(torrentSummary),
+ 'startTorrentingSummary': (torrentKey) => controllers.torrentList.startTorrentingSummary(torrentKey),
// Playback
'playFile': (infoHash, index) => controllers.playback.playFile(infoHash, index),
@@ -318,8 +317,14 @@ function escapeBack () {
// Starts all torrents that aren't paused on program startup
function resumeTorrents () {
state.saved.torrents
- .filter((torrentSummary) => torrentSummary.status !== 'paused')
- .forEach((torrentSummary) => controllers.torrentList.startTorrentingSummary(torrentSummary))
+ .map((torrentSummary) => {
+ // Torrent keys are ephemeral, reassigned each time the app runs.
+ // On startup, give all torrents a key, even the ones that are paused.
+ torrentSummary.torrentKey = state.nextTorrentKey++
+ return torrentSummary
+ })
+ .filter((s) => s.status !== 'paused')
+ .forEach((s) => controllers.torrentList.startTorrentingSummary(s.torrentKey))
}
// Set window dimensions to match video dimensions or fill the screen
@@ -440,7 +445,6 @@ function onFullscreenChanged (e, isFullScreen) {
}
function checkDownloadPath () {
- state.downloadPathStatus = undefined
fs.stat(state.saved.prefs.downloadPath, function (err, stat) {
if (err) {
state.downloadPathStatus = 'missing'
diff --git a/src/renderer/views/torrent-list.js b/src/renderer/views/torrent-list.js
index a4849906..50cf8bfe 100644
--- a/src/renderer/views/torrent-list.js
+++ b/src/renderer/views/torrent-list.js
@@ -9,31 +9,27 @@ module.exports = class TorrentList extends React.Component {
render () {
var state = this.props.state
- var contents
- if (!state.downloadPathStatus) {
- contents = ''
- } else if (state.downloadPathStatus === 'missing') {
- contents = (
-
+ var contents = []
+ if (state.downloadPathStatus === 'missing') {
+ contents.push(
+
Download path missing: {state.saved.prefs.downloadPath}
Check that all drives are connected?
-
Alternatively, choose a new download path in
- Preferences
+
Alternatively, choose a new download path
+ in Preferences
)
- } else if (state.downloadPathStatus === 'ok') {
- contents = state.saved.torrents.map(
- (torrentSummary) => this.renderTorrent(torrentSummary)
- )
- contents.push(
-
- Drop a torrent file here or paste a magnet link
-
- )
- } else {
- throw new Error('Unhandled downloadPathStatus ' + state.downloadPathStatus)
}
+ var torrentElems = state.saved.torrents.map(
+ (torrentSummary) => this.renderTorrent(torrentSummary)
+ )
+ contents.push(...torrentElems)
+ contents.push(
+
+ Drop a torrent file here or paste a magnet link
+
+ )
return (
@@ -64,7 +60,7 @@ module.exports = class TorrentList extends React.Component {
if (torrentSummary.playStatus) classes.push(torrentSummary.playStatus)
if (isSelected) classes.push('selected')
if (!infoHash) classes.push('disabled')
- if (torrentSummary.torrrentKey) console.error('Missing torrentKey', torrentSummary)
+ if (!torrentSummary.torrentKey) throw new Error('Missing torrentKey')
return (
+ {getErrorMessage(torrentSummary)}
+
+ )
+ } else if (torrentSummary.status !== 'paused' && prog) {
+ elements.push(
{renderPercentProgress()}
{renderTotalProgress()}
@@ -98,7 +100,7 @@ module.exports = class TorrentList extends React.Component {
{renderUploadSpeed()}
{renderEta()}
- ))
+ )
}
return (
{elements}
)
@@ -195,8 +197,9 @@ module.exports = class TorrentList extends React.Component {
}
// Only show the play button for torrents that contain playable media
- var playButton
- if (TorrentPlayer.isPlayableTorrentSummary(torrentSummary)) {
+ var playButton, downloadButton
+ var noErrors = !torrentSummary.error
+ if (noErrors && TorrentPlayer.isPlayableTorrentSummary(torrentSummary)) {
playButton = (
)
}
-
- return (
-
- {positionElem}
- {playButton}
+ if (noErrors) {
+ downloadButton = (
{downloadIcon}
+ )
+ }
+
+ return (
+
+ {positionElem}
+ {playButton}
+ {downloadButton}
{message}
)
+ if (torrentSummary.error || !torrentSummary.files) {
+ var message = ''
+ if (torrentSummary.error === 'path-missing') {
+ // Special case error: this torrent's download dir or file is missing
+ message = 'Missing path: ' + TorrentSummary.getFileOrFolder(torrentSummary)
+ } else if (torrentSummary.error) {
+ // General error for this torrent: just show the message
+ message = torrentSummary.error.message || torrentSummary.error
+ } else if (torrentSummary.status === 'paused') {
+ // No file info, no infohash, and we're not trying to download from the DHT
+ message = 'Failed to load torrent info. Click the download button to try again...'
+ } else {
+ // No file info, no infohash, trying to load from the DHT
+ message = 'Downloading torrent info...'
+ }
+ filesElement = (
+
+ {message}
+
+ )
} else {
// We do know the files. List them and show download stats for each one
var fileRows = torrentSummary.files
@@ -349,3 +371,16 @@ module.exports = class TorrentList extends React.Component {
)
}
}
+
+function getErrorMessage (torrentSummary) {
+ var err = torrentSummary.error
+ if (err === 'path-missing') {
+ return (
+
+ Path missing.
+ Fix and restart the app, or delete the torrent.
+
+ )
+ }
+ return 'Error'
+}
diff --git a/static/main.css b/static/main.css
index 902c4c4e..a2b1a8b7 100644
--- a/static/main.css
+++ b/static/main.css
@@ -554,8 +554,14 @@ input[type='text'] {
/*
* TORRENT LIST: ERRORS
*/
+
.torrent-list p {
- padding: 5px 20px;
+ margin: 10px 20px;
+}
+
+.torrent-list a {
+ color: #99f;
+ text-decoration: none;
}
/*