Compare commits
233 Commits
modernify
...
renovate_n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00a0ecac58 | ||
|
|
0a2ea1e09d | ||
|
|
be77363515 | ||
|
|
b1a1c5c01b | ||
|
|
6b60360ce1 | ||
|
|
56e92101b0 | ||
|
|
2a5c67f9e3 | ||
|
|
ef39f41e96 | ||
|
|
d317ea3ff8 | ||
|
|
787e4c441b | ||
|
|
ef116d01b7 | ||
|
|
0a5be1f166 | ||
|
|
4a35518da7 | ||
|
|
8f3301cd1e | ||
|
|
97b10558f6 | ||
|
|
e61501f13f | ||
|
|
b1d1778479 | ||
|
|
9cca2d39c3 | ||
|
|
fcee4017d7 | ||
|
|
2890419d6d | ||
|
|
0fe3dd977f | ||
|
|
9ba088f76f | ||
|
|
1a7404ee8a | ||
|
|
f1de7606a5 | ||
|
|
d4b493cebe | ||
|
|
1df3d025bd | ||
|
|
61b7681fd1 | ||
|
|
ac7f16e71c | ||
|
|
b363dca77f | ||
|
|
16cabd19ff | ||
|
|
390b4ad7ec | ||
|
|
b3dc3292b7 | ||
|
|
244a242bdc | ||
|
|
241f3cb9a3 | ||
|
|
aa4fb3d08e | ||
|
|
ebaf9cf848 | ||
|
|
df05db5583 | ||
|
|
1ccfa404d2 | ||
|
|
bc19caf8ee | ||
|
|
36c24a4940 | ||
|
|
1cefcff3da | ||
|
|
1eb61201d6 | ||
|
|
3e514f9cf6 | ||
|
|
b8f1d950f2 | ||
|
|
a85effc8ec | ||
|
|
cf846979b0 | ||
|
|
9f630c9bfb | ||
|
|
1d66b6d069 | ||
|
|
6b83ed34b9 | ||
|
|
a0aeae7e91 | ||
|
|
99e3058676 | ||
|
|
20d1d8a224 | ||
|
|
0b34ff1148 | ||
|
|
4120fcf4af | ||
|
|
7ea277ccf6 | ||
|
|
77a981178b | ||
|
|
ea19545ec6 | ||
|
|
6f6ccb029c | ||
|
|
43b2d28fb5 | ||
|
|
f20d24ac3c | ||
|
|
b1332ee76b | ||
|
|
34b8f3fb64 | ||
|
|
b4f98e91ff | ||
|
|
ebb8d23ef3 | ||
|
|
e5bf6745bf | ||
|
|
686f63b35f | ||
|
|
4ed5f3ff5f | ||
|
|
af8379012a | ||
|
|
1c53102e12 | ||
|
|
1a074b65e6 | ||
|
|
2052adde7d | ||
|
|
eed9eebd45 | ||
|
|
e36eacd05a | ||
|
|
9c7cffa1a3 | ||
|
|
94d2bd7807 | ||
|
|
5efbf7e5c9 | ||
|
|
fce078defe | ||
|
|
10f355ba0f | ||
|
|
9d8293b970 | ||
|
|
73b8b54ae8 | ||
|
|
bc49dbc41d | ||
|
|
69b1ff58d0 | ||
|
|
cf48311fcb | ||
|
|
c919af1fd9 | ||
|
|
cdc5ac6538 | ||
|
|
05881478b5 | ||
|
|
fb279010d0 | ||
|
|
e54f61c480 | ||
|
|
ab9468f84f | ||
|
|
0f20c0acd1 | ||
|
|
a4ef6cb562 | ||
|
|
21c260dc13 | ||
|
|
0df520c5ba | ||
|
|
707461a264 | ||
|
|
a22f94df80 | ||
|
|
a60e817e0c | ||
|
|
f1865dda4f | ||
|
|
8cdc6b1307 | ||
|
|
660facf8c2 | ||
|
|
fee5b42813 | ||
|
|
ddb8500082 | ||
|
|
cc6af9829e | ||
|
|
cfba6b503a | ||
|
|
04c766bb53 | ||
|
|
2389a1aa35 | ||
|
|
430b4c409a | ||
|
|
810952f234 | ||
|
|
ae4a8e40f8 | ||
|
|
ea100dda36 | ||
|
|
46cbce00ca | ||
|
|
00ebbc7e17 | ||
|
|
8109ce5410 | ||
|
|
9200070269 | ||
|
|
16ab96e4ac | ||
|
|
d8632f6386 | ||
|
|
5558bad0de | ||
|
|
0f5b7fd80e | ||
|
|
6a288efb57 | ||
|
|
f07a307b0d | ||
|
|
cb1de722fe | ||
|
|
45036451c7 | ||
|
|
58a4f7a34a | ||
|
|
9082c6f63e | ||
|
|
9fb8a2ae09 | ||
|
|
0e501b498e | ||
|
|
85e0c5709e | ||
|
|
cee88a7e24 | ||
|
|
f503a46447 | ||
|
|
1cdd54e421 | ||
|
|
73be2513ad | ||
|
|
e9eb22a530 | ||
|
|
d17f287ba2 | ||
|
|
06b904b837 | ||
|
|
807c6aebdd | ||
|
|
ab54a7cfb3 | ||
|
|
77d4eed9fc | ||
|
|
9c73638d1b | ||
|
|
3dd7ebb34b | ||
|
|
c943f39f6b | ||
|
|
401698e616 | ||
|
|
c85b3e4fd1 | ||
|
|
be15ee073d | ||
|
|
d838e6276d | ||
|
|
35af086fad | ||
|
|
cf9fbf2b0e | ||
|
|
ef2225c8a5 | ||
|
|
ffacb6085d | ||
|
|
20a84359cd | ||
|
|
a3d123537f | ||
|
|
30fb222fb9 | ||
|
|
4c2a08dd52 | ||
|
|
406c568c1e | ||
|
|
a86424b7df | ||
|
|
f6ffc16964 | ||
|
|
05e8a0d284 | ||
|
|
1dc38afc85 | ||
|
|
ca73b3c286 | ||
|
|
bad30e8f1a | ||
|
|
56036e89af | ||
|
|
bb7a9bb018 | ||
|
|
f9ba0750d6 | ||
|
|
d98299268f | ||
|
|
601d01fe85 | ||
|
|
b24cc29523 | ||
|
|
dd06ac7cc5 | ||
|
|
4097c5ee18 | ||
|
|
240128943c | ||
|
|
6d8a2a0b9e | ||
|
|
6433da4901 | ||
|
|
96b27fa1cb | ||
|
|
9134620fe7 | ||
|
|
1ff1c035b7 | ||
|
|
58e165eb30 | ||
|
|
4fdafc91c1 | ||
|
|
7ef740ebe0 | ||
|
|
138ece60fd | ||
|
|
a2d0cc09eb | ||
|
|
a701d44d25 | ||
|
|
4a67d1c679 | ||
|
|
450ecedad4 | ||
|
|
55ea243862 | ||
|
|
319a27399e | ||
|
|
f532d15222 | ||
|
|
3b4a2da2be | ||
|
|
c464074c92 | ||
|
|
4945ba9073 | ||
|
|
a4b7cfea3f | ||
|
|
d0ed20f10b | ||
|
|
8964d9f349 | ||
|
|
e1525a64fc | ||
|
|
3a0415578a | ||
|
|
3dc023828d | ||
|
|
3d01225b6d | ||
|
|
0feb97275c | ||
|
|
036ac72e3c | ||
|
|
f097a1ed52 | ||
|
|
16485f29c8 | ||
|
|
0b2cb410bd | ||
|
|
330b4adb0e | ||
|
|
32818c60a4 | ||
|
|
a55d7e897d | ||
|
|
bd34106a31 | ||
|
|
85fb83fb67 | ||
|
|
0cfce0ff26 | ||
|
|
65147eb53a | ||
|
|
5b6d29efcb | ||
|
|
c5c53646eb | ||
|
|
0927cedfa0 | ||
|
|
22962e9b7c | ||
|
|
13932b0567 | ||
|
|
ed38a55711 | ||
|
|
e55d9b6d15 | ||
|
|
e15ae42c32 | ||
|
|
a71808445e | ||
|
|
b742b10553 | ||
|
|
e8e9314486 | ||
|
|
0b16be24c1 | ||
|
|
a90df37123 | ||
|
|
fc7608fa87 | ||
|
|
82a61e9da4 | ||
|
|
2d0c1d597f | ||
|
|
4a9566665e | ||
|
|
fad7a21287 | ||
|
|
7893da9426 | ||
|
|
f0ddc79fcc | ||
|
|
f92afd3f10 | ||
|
|
9ce6c3b461 | ||
|
|
b404b44aa1 | ||
|
|
8c38377e38 | ||
|
|
eda83e858d | ||
|
|
a6639aadcf | ||
|
|
2cc62e26b3 | ||
|
|
e42a515199 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -12,8 +12,8 @@ jobs:
|
||||
node:
|
||||
- '16'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm install
|
||||
|
||||
24
.github/workflows/package.yml
vendored
24
.github/workflows/package.yml
vendored
@@ -5,11 +5,11 @@ jobs:
|
||||
package_linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
${{ runner.os }}-node-
|
||||
- run: npm install
|
||||
- run: npm run package -- linux
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux
|
||||
path: |
|
||||
@@ -27,11 +27,11 @@ jobs:
|
||||
package_macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
${{ runner.os }}-node-
|
||||
- run: npm install
|
||||
- run: npm run package -- darwin
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos
|
||||
path: |
|
||||
@@ -48,11 +48,11 @@ jobs:
|
||||
package_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
${{ runner.os }}-node-
|
||||
- run: npm install
|
||||
- run: npm run package -- win32
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows
|
||||
path: |
|
||||
|
||||
6
.github/workflows/stale.yml
vendored
6
.github/workflows/stale.yml
vendored
@@ -12,12 +12,12 @@ jobs:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
- uses: actions/stale@v6
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?'
|
||||
stale-pr-message: 'Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?'
|
||||
exempt-issue-labels: accepted,blocked,bug,dependency,enhancement,'help wanted',question,security,meta
|
||||
exempt-pr-labels: accepted,blocked,bug,dependency,enhancement,'help wanted',question,security,meta
|
||||
exempt-issue-labels: accepted,blocked,dependency,security,meta
|
||||
exempt-pr-labels: accepted,blocked,bug,dependency,security,meta
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://discord.gg/cnXkm4Z"><img src="https://img.shields.io/discord/612575111718895616" alt="discord"></a>
|
||||
<a href="https://travis-ci.org/webtorrent/webtorrent-desktop"><img src="https://img.shields.io/travis/webtorrent/webtorrent-desktop/master.svg" alt="travis"></a>
|
||||
<a href="https://github.com/webtorrent/webtorrent-desktop/actions/workflows/ci.yml"><img src="https://github.com/webtorrent/webtorrent-desktop/actions/workflows/ci.yml/badge.svg" alt="GitHub CI action"></a>
|
||||
<a href="https://github.com/webtorrent/webtorrent-desktop/releases"><img src="https://img.shields.io/github/release/webtorrent/webtorrent-desktop.svg" alt="github release version"></a>
|
||||
<a href="https://github.com/webtorrent/webtorrent-desktop/releases"><img src="https://img.shields.io/github/downloads/webtorrent/webtorrent-desktop/total.svg" alt="github release downloads"></a>
|
||||
<a href="https://standardjs.com"><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Standard - JavaScript Style Guide"></a>
|
||||
@@ -147,7 +147,7 @@ to be installed. For example on Mac, first install
|
||||
[XQuartz](http://www.xquartz.org/), then run:
|
||||
|
||||
```
|
||||
brew install wine mono
|
||||
$ brew install wine mono
|
||||
```
|
||||
|
||||
(Requires the [Homebrew](http://brew.sh/) package manager.)
|
||||
|
||||
14746
package-lock.json
generated
14746
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
70
package.json
70
package.json
@@ -21,68 +21,68 @@
|
||||
"url": "https://github.com/webtorrent/webtorrent-desktop/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.0.1",
|
||||
"@electron/remote": "2.1.3",
|
||||
"airplayer": "github:webtorrent/airplayer#fix-security",
|
||||
"application-config": "2.0.0",
|
||||
"arch": "2.2.0",
|
||||
"auto-launch": "5.0.5",
|
||||
"bitfield": "4.0.0",
|
||||
"bitfield": "4.1.0",
|
||||
"capture-frame": "4.0.0",
|
||||
"chokidar": "3.5.2",
|
||||
"chokidar": "3.5.3",
|
||||
"chromecasts": "1.10.2",
|
||||
"create-torrent": "5.0.1",
|
||||
"create-torrent": "5.0.9",
|
||||
"debounce": "1.2.1",
|
||||
"dlnacasts": "0.1.0",
|
||||
"drag-drop": "7.2.0",
|
||||
"es6-error": "4.1.1",
|
||||
"fn-getter": "1.0.0",
|
||||
"iso-639-1": "2.1.9",
|
||||
"iso-639-1": "2.1.15",
|
||||
"languagedetect": "2.0.0",
|
||||
"location-history": "1.1.2",
|
||||
"material-ui": "0.20.2",
|
||||
"music-metadata": "7.11.4",
|
||||
"music-metadata": "7.14.0",
|
||||
"network-address": "1.1.2",
|
||||
"parse-torrent": "9.1.4",
|
||||
"parse-torrent": "9.1.5",
|
||||
"prettier-bytes": "1.0.4",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"rimraf": "3.0.2",
|
||||
"rimraf": "4.4.0",
|
||||
"run-parallel": "1.2.0",
|
||||
"semver": "7.3.5",
|
||||
"semver": "7.5.2",
|
||||
"simple-concat": "1.0.1",
|
||||
"simple-get": "4.0.0",
|
||||
"simple-get": "4.0.1",
|
||||
"srt-to-vtt": "1.1.3",
|
||||
"vlc-command": "1.2.0",
|
||||
"webtorrent": "1.5.6",
|
||||
"webtorrent": "1.9.7",
|
||||
"winreg": "1.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.15.7",
|
||||
"@babel/core": "7.15.8",
|
||||
"@babel/eslint-parser": "7.15.8",
|
||||
"@babel/plugin-transform-react-jsx": "7.14.9",
|
||||
"@babel/cli": "7.28.6",
|
||||
"@babel/core": "7.29.0",
|
||||
"@babel/eslint-parser": "7.28.6",
|
||||
"@babel/plugin-transform-react-jsx": "7.28.6",
|
||||
"cross-zip": "4.0.0",
|
||||
"depcheck": "1.4.2",
|
||||
"electron": "15.1.2",
|
||||
"electron-notarize": "1.1.1",
|
||||
"electron-osx-sign": "0.5.0",
|
||||
"electron-packager": "15.4.0",
|
||||
"electron-winstaller": "5.0.0",
|
||||
"gh-release": "6.0.1",
|
||||
"minimist": "1.2.5",
|
||||
"nodemon": "2.0.13",
|
||||
"open": "8.3.0",
|
||||
"plist": "3.0.4",
|
||||
"pngjs": "6.0.0",
|
||||
"depcheck": "1.4.7",
|
||||
"electron": "27.3.11",
|
||||
"electron-notarize": "1.2.2",
|
||||
"electron-osx-sign": "0.6.0",
|
||||
"electron-packager": "17.1.2",
|
||||
"electron-winstaller": "5.4.0",
|
||||
"gh-release": "7.0.2",
|
||||
"minimist": "1.2.8",
|
||||
"nodemon": "2.0.22",
|
||||
"open": "8.4.2",
|
||||
"plist": "3.1.0",
|
||||
"pngjs": "7.0.0",
|
||||
"run-series": "1.1.9",
|
||||
"spectron": "15.0.0",
|
||||
"standard": "16.0.4",
|
||||
"tape": "5.3.1"
|
||||
"spectron": "19.0.0",
|
||||
"standard": "17.0.0",
|
||||
"tape": "5.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0",
|
||||
"npm": "^7.10.0 || ^8.0.0"
|
||||
"node": "^16.0.0 || ^18.0.0",
|
||||
"npm": "^7.10.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
|
||||
},
|
||||
"homepage": "https://webtorrent.io",
|
||||
"keywords": [
|
||||
@@ -99,8 +99,8 @@
|
||||
"main": "index.js",
|
||||
"optionalDependencies": {
|
||||
"appdmg": "^0.6.0",
|
||||
"electron-installer-debian": "^3.1.0",
|
||||
"electron-installer-redhat": "^3.3.0"
|
||||
"electron-installer-debian": "^3.2.0",
|
||||
"electron-installer-redhat": "^3.4.0"
|
||||
},
|
||||
"private": true,
|
||||
"productName": "WebTorrent",
|
||||
|
||||
@@ -82,7 +82,7 @@ function openTorrentFile () {
|
||||
const selectedPaths = dialog.showOpenDialogSync(windows.main.win, opts)
|
||||
resetTitle()
|
||||
if (!Array.isArray(selectedPaths)) return
|
||||
selectedPaths.forEach(function (selectedPath) {
|
||||
selectedPaths.forEach(selectedPath => {
|
||||
windows.main.dispatch('addTorrent', selectedPath)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -110,13 +110,13 @@ function init () {
|
||||
|
||||
ipc.init()
|
||||
|
||||
app.once('ipcReady', function () {
|
||||
app.once('ipcReady', () => {
|
||||
log('Command line args:', argv)
|
||||
processArgv(argv)
|
||||
console.timeEnd('init')
|
||||
})
|
||||
|
||||
app.on('before-quit', function (e) {
|
||||
app.on('before-quit', e => {
|
||||
if (app.isQuitting) return
|
||||
|
||||
app.isQuitting = true
|
||||
@@ -129,7 +129,7 @@ function init () {
|
||||
}, 4000) // quit after 4 secs, at most
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
app.on('activate', () => {
|
||||
if (isReady) windows.main.show()
|
||||
})
|
||||
}
|
||||
@@ -207,7 +207,7 @@ function sliceArgv (argv) {
|
||||
|
||||
function processArgv (argv) {
|
||||
const torrentIds = []
|
||||
argv.forEach(function (arg) {
|
||||
argv.forEach(arg => {
|
||||
if (arg === '-n' || arg === '-o' || arg === '-u') {
|
||||
// Critical path: Only load the 'dialog' package if it is needed
|
||||
const dialog = require('./dialog')
|
||||
|
||||
@@ -21,16 +21,16 @@ function setModule (name, module) {
|
||||
}
|
||||
|
||||
function init () {
|
||||
ipcMain.once('ipcReady', function (e) {
|
||||
ipcMain.once('ipcReady', e => {
|
||||
app.ipcReady = true
|
||||
app.emit('ipcReady')
|
||||
})
|
||||
|
||||
ipcMain.once('ipcReadyWebTorrent', function (e) {
|
||||
ipcMain.once('ipcReadyWebTorrent', e => {
|
||||
app.ipcReadyWebTorrent = true
|
||||
log('sending %d queued messages from the main win to the webtorrent window',
|
||||
messageQueueMainToWebTorrent.length)
|
||||
messageQueueMainToWebTorrent.forEach(function (message) {
|
||||
messageQueueMainToWebTorrent.forEach(message => {
|
||||
windows.webtorrent.send(message.name, ...message.args)
|
||||
log('webtorrent: sent queued %s', message.name)
|
||||
})
|
||||
@@ -66,7 +66,7 @@ function init () {
|
||||
* Player Events
|
||||
*/
|
||||
|
||||
ipcMain.on('onPlayerOpen', function () {
|
||||
ipcMain.on('onPlayerOpen', () => {
|
||||
const powerSaveBlocker = require('./power-save-blocker')
|
||||
const shortcuts = require('./shortcuts')
|
||||
const thumbar = require('./thumbar')
|
||||
@@ -77,14 +77,14 @@ function init () {
|
||||
thumbar.enable()
|
||||
})
|
||||
|
||||
ipcMain.on('onPlayerUpdate', function (e, ...args) {
|
||||
ipcMain.on('onPlayerUpdate', (e, ...args) => {
|
||||
const thumbar = require('./thumbar')
|
||||
|
||||
menu.onPlayerUpdate(...args)
|
||||
thumbar.onPlayerUpdate(...args)
|
||||
})
|
||||
|
||||
ipcMain.on('onPlayerClose', function () {
|
||||
ipcMain.on('onPlayerClose', () => {
|
||||
const powerSaveBlocker = require('./power-save-blocker')
|
||||
const shortcuts = require('./shortcuts')
|
||||
const thumbar = require('./thumbar')
|
||||
@@ -95,7 +95,7 @@ function init () {
|
||||
thumbar.disable()
|
||||
})
|
||||
|
||||
ipcMain.on('onPlayerPlay', function () {
|
||||
ipcMain.on('onPlayerPlay', () => {
|
||||
const powerSaveBlocker = require('./power-save-blocker')
|
||||
const thumbar = require('./thumbar')
|
||||
|
||||
@@ -103,7 +103,7 @@ function init () {
|
||||
thumbar.onPlayerPlay()
|
||||
})
|
||||
|
||||
ipcMain.on('onPlayerPause', function () {
|
||||
ipcMain.on('onPlayerPause', () => {
|
||||
const powerSaveBlocker = require('./power-save-blocker')
|
||||
const thumbar = require('./thumbar')
|
||||
|
||||
@@ -115,7 +115,7 @@ function init () {
|
||||
* Folder Watcher Events
|
||||
*/
|
||||
|
||||
ipcMain.on('startFolderWatcher', function () {
|
||||
ipcMain.on('startFolderWatcher', () => {
|
||||
if (!modules.folderWatcher) {
|
||||
log('IPC ERR: folderWatcher module is not defined.')
|
||||
return
|
||||
@@ -124,7 +124,7 @@ function init () {
|
||||
modules.folderWatcher.start()
|
||||
})
|
||||
|
||||
ipcMain.on('stopFolderWatcher', function () {
|
||||
ipcMain.on('stopFolderWatcher', () => {
|
||||
if (!modules.folderWatcher) {
|
||||
log('IPC ERR: folderWatcher module is not defined.')
|
||||
return
|
||||
@@ -190,10 +190,10 @@ function init () {
|
||||
* External Media Player
|
||||
*/
|
||||
|
||||
ipcMain.on('checkForExternalPlayer', function (e, path) {
|
||||
ipcMain.on('checkForExternalPlayer', (e, path) => {
|
||||
const externalPlayer = require('./external-player')
|
||||
|
||||
externalPlayer.checkInstall(path, function (err) {
|
||||
externalPlayer.checkInstall(path, err => {
|
||||
windows.main.send('checkForExternalPlayer', !err)
|
||||
})
|
||||
})
|
||||
@@ -219,7 +219,7 @@ function init () {
|
||||
*/
|
||||
|
||||
const oldEmit = ipcMain.emit
|
||||
ipcMain.emit = function (name, e, ...args) {
|
||||
ipcMain.emit = (name, e, ...args) => {
|
||||
// Relay messages between the main window and the WebTorrent hidden window
|
||||
if (name.startsWith('wt-') && !app.isQuitting) {
|
||||
console.dir(e.sender.getTitle())
|
||||
|
||||
@@ -68,11 +68,9 @@ function onToggleFullScreen (flag) {
|
||||
}
|
||||
|
||||
function getMenuItem (label) {
|
||||
for (let i = 0; i < menu.items.length; i++) {
|
||||
const menuItem = menu.items[i].submenu.items.find(function (item) {
|
||||
return item.label === label
|
||||
})
|
||||
if (menuItem) return menuItem
|
||||
for (const menuItem of menu.items) {
|
||||
const submenuItem = menuItem.submenu.items.find(item => item.label === label)
|
||||
if (submenuItem) return submenuItem
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@ function showItemInFolder (path) {
|
||||
*/
|
||||
function moveItemToTrash (path) {
|
||||
log(`moveItemToTrash: ${path}`)
|
||||
shell.moveItemToTrash(path)
|
||||
shell.trashItem(path)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const handlers = require('./handlers')
|
||||
const EXE_NAME = path.basename(process.execPath)
|
||||
const UPDATE_EXE = path.join(process.execPath, '..', '..', 'Update.exe')
|
||||
|
||||
const run = function (args, done) {
|
||||
const run = (args, done) => {
|
||||
spawn(UPDATE_EXE, args, { detached: true })
|
||||
.on('close', done)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ function setWindowFocus (flag) {
|
||||
}
|
||||
|
||||
function initLinux () {
|
||||
checkLinuxTraySupport(function (err) {
|
||||
checkLinuxTraySupport(err => {
|
||||
if (!err) createTray()
|
||||
})
|
||||
}
|
||||
@@ -50,7 +50,7 @@ function checkLinuxTraySupport (cb) {
|
||||
const cp = require('child_process')
|
||||
|
||||
// Check that libappindicator libraries are installed in system.
|
||||
cp.exec('ldconfig -p | grep libappindicator', function (err, stdout) {
|
||||
cp.exec('ldconfig -p | grep libappindicator', (err, stdout) => {
|
||||
if (err) return cb(err)
|
||||
cb(null)
|
||||
})
|
||||
|
||||
@@ -37,7 +37,7 @@ function init () {
|
||||
|
||||
win.loadURL(config.WINDOW_ABOUT)
|
||||
|
||||
win.once('ready-to-show', function () {
|
||||
win.once('ready-to-show', () => {
|
||||
win.show()
|
||||
// No menu on the About window
|
||||
// Hack: BrowserWindow removeMenu method not working on electron@7
|
||||
@@ -45,7 +45,7 @@ function init () {
|
||||
win.setMenuBarVisibility(false)
|
||||
})
|
||||
|
||||
win.once('closed', function () {
|
||||
win.once('closed', () => {
|
||||
about.win = null
|
||||
})
|
||||
}
|
||||
|
||||
@@ -91,11 +91,11 @@ function init (state, options) {
|
||||
})
|
||||
|
||||
win.on('move', debounce(e => {
|
||||
send('windowBoundsChanged', e.sender.getBounds())
|
||||
send('windowBoundsChanged', main.win.getBounds())
|
||||
}, 1000))
|
||||
|
||||
win.on('resize', debounce(e => {
|
||||
send('windowBoundsChanged', e.sender.getBounds())
|
||||
send('windowBoundsChanged', main.win.getBounds())
|
||||
}, 1000))
|
||||
|
||||
win.on('close', e => {
|
||||
|
||||
@@ -38,7 +38,7 @@ function init () {
|
||||
win.loadURL(config.WINDOW_WEBTORRENT)
|
||||
|
||||
// Prevent killing the WebTorrent process
|
||||
win.on('close', function (e) {
|
||||
win.on('close', e => {
|
||||
if (app.isQuitting) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ class Header extends React.Component {
|
||||
onMouseMove={dispatcher('mediaMouseMoved')}
|
||||
onMouseEnter={dispatcher('mediaControlsMouseEnter')}
|
||||
onMouseLeave={dispatcher('mediaControlsMouseLeave')}
|
||||
role='navigation'
|
||||
>
|
||||
{this.getTitle()}
|
||||
<div className='nav left float-left'>
|
||||
@@ -18,6 +19,9 @@ class Header extends React.Component {
|
||||
className={'icon back ' + (loc.hasBack() ? '' : 'disabled')}
|
||||
title='Back'
|
||||
onClick={dispatcher('back')}
|
||||
role='button'
|
||||
aria-disabled={!loc.hasBack()}
|
||||
aria-label='Back'
|
||||
>
|
||||
chevron_left
|
||||
</i>
|
||||
@@ -25,6 +29,9 @@ class Header extends React.Component {
|
||||
className={'icon forward ' + (loc.hasForward() ? '' : 'disabled')}
|
||||
title='Forward'
|
||||
onClick={dispatcher('forward')}
|
||||
role='button'
|
||||
aria-disabled={!loc.hasForward()}
|
||||
aria-label='Forward'
|
||||
>
|
||||
chevron_right
|
||||
</i>
|
||||
@@ -50,6 +57,7 @@ class Header extends React.Component {
|
||||
className='icon add'
|
||||
title='Add torrent'
|
||||
onClick={dispatcher('openFiles')}
|
||||
role='button'
|
||||
>
|
||||
add
|
||||
</i>
|
||||
|
||||
@@ -23,7 +23,7 @@ module.exports = class MediaController {
|
||||
telemetry.logPlayAttempt('error')
|
||||
state.playing.location = 'error'
|
||||
ipcRenderer.send('checkForExternalPlayer', state.saved.prefs.externalPlayerPath)
|
||||
ipcRenderer.once('checkForExternalPlayer', function (e, isInstalled) {
|
||||
ipcRenderer.once('checkForExternalPlayer', (e, isInstalled) => {
|
||||
state.modal = {
|
||||
id: 'unsupported-media-modal',
|
||||
error,
|
||||
@@ -56,7 +56,7 @@ module.exports = class MediaController {
|
||||
const state = this.state
|
||||
state.playing.location = 'external'
|
||||
|
||||
const onServerRunning = function () {
|
||||
const onServerRunning = () => {
|
||||
state.playing.isReady = true
|
||||
telemetry.logPlayAttempt('external')
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ module.exports = class PrefsController {
|
||||
const state = this.state
|
||||
state.location.go({
|
||||
url: 'preferences',
|
||||
setup: function (cb) {
|
||||
setup (cb) {
|
||||
// initialize preferences
|
||||
state.window.title = 'Preferences'
|
||||
ipcRenderer.send('setAllowNav', false)
|
||||
|
||||
@@ -37,12 +37,11 @@ module.exports = class SubtitlesController {
|
||||
|
||||
// Read the files concurrently, then add all resulting subtitle tracks
|
||||
const tasks = files.map((file) => (cb) => loadSubtitle(file, cb))
|
||||
parallel(tasks, function (err, tracks) {
|
||||
parallel(tasks, (err, tracks) => {
|
||||
if (err) return dispatch('error', err)
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
// No dupes allowed
|
||||
const track = tracks[i]
|
||||
// No dupes allowed
|
||||
tracks.forEach((track, i) => {
|
||||
let trackIndex = subtitles.tracks.findIndex((t) =>
|
||||
track.filePath === t.filePath)
|
||||
|
||||
@@ -55,7 +54,7 @@ module.exports = class SubtitlesController {
|
||||
if (autoSelect && (i === 0 || isSystemLanguage(track.language))) {
|
||||
subtitles.selectedIndex = trackIndex
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Finally, make sure no two tracks have the same label
|
||||
relabelSubtitles(subtitles)
|
||||
@@ -94,7 +93,7 @@ function loadSubtitle (file, cb) {
|
||||
|
||||
const vttStream = fs.createReadStream(filePath).pipe(srtToVtt())
|
||||
|
||||
concat(vttStream, function (err, buf) {
|
||||
concat(vttStream, (err, buf) => {
|
||||
if (err) return dispatch('error', 'Can\'t parse subtitles file.')
|
||||
|
||||
// Detect what language the subtitles are in
|
||||
@@ -127,7 +126,7 @@ function isSystemLanguage (language) {
|
||||
// Labels each track by language, eg 'German', 'English', 'English 2', ...
|
||||
function relabelSubtitles (subtitles) {
|
||||
const counts = {}
|
||||
subtitles.tracks.forEach(function (track) {
|
||||
subtitles.tracks.forEach(track => {
|
||||
const lang = track.language
|
||||
counts[lang] = (counts[lang] || 0) + 1
|
||||
track.label = counts[lang] > 1 ? (lang + ' ' + counts[lang]) : lang
|
||||
|
||||
@@ -177,7 +177,7 @@ function showDoneNotification (torrent) {
|
||||
silent: true
|
||||
})
|
||||
|
||||
notif.onclick = function () {
|
||||
notif.onclick = () => {
|
||||
ipcRenderer.send('show')
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ module.exports = class TorrentListController {
|
||||
if (!fileOrFolder) return start()
|
||||
|
||||
// Existing torrent: check that the path is still there
|
||||
fs.stat(fileOrFolder, function (err) {
|
||||
fs.stat(fileOrFolder, err => {
|
||||
if (err) {
|
||||
s.error = 'path-missing'
|
||||
dispatch('backToList')
|
||||
@@ -113,6 +113,10 @@ module.exports = class TorrentListController {
|
||||
}
|
||||
}
|
||||
|
||||
setGlobalTrackers (globalTrackers) {
|
||||
ipcRenderer.send('wt-set-global-trackers', globalTrackers)
|
||||
}
|
||||
|
||||
// TODO: use torrentKey, not infoHash
|
||||
toggleTorrent (infoHash) {
|
||||
const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||
@@ -156,9 +160,7 @@ module.exports = class TorrentListController {
|
||||
|
||||
prioritizeTorrent (infoHash) {
|
||||
this.state.saved.torrents
|
||||
.filter((torrent) => { // We're interested in active torrents only.
|
||||
return (['downloading', 'seeding'].indexOf(torrent.status) !== -1)
|
||||
})
|
||||
.filter(torrent => ['downloading', 'seeding'].includes(torrent.status)) // Active torrents only.
|
||||
.forEach((torrent) => { // Pause all active torrents except the one that started playing.
|
||||
if (infoHash === torrent.infoHash) return
|
||||
|
||||
@@ -331,9 +333,9 @@ module.exports = class TorrentListController {
|
||||
if (!savePath) return // They clicked Cancel
|
||||
console.log('Saving torrent ' + torrentKey + ' to ' + savePath)
|
||||
const torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
|
||||
fs.readFile(torrentPath, function (err, torrentFile) {
|
||||
fs.readFile(torrentPath, (err, torrentFile) => {
|
||||
if (err) return dispatch('error', err)
|
||||
fs.writeFile(savePath, torrentFile, function (err) {
|
||||
fs.writeFile(savePath, torrentFile, err => {
|
||||
if (err) return dispatch('error', err)
|
||||
})
|
||||
})
|
||||
@@ -346,8 +348,8 @@ function findFilesRecursive (paths, cb_) {
|
||||
if (paths.length > 1) {
|
||||
let numComplete = 0
|
||||
const ret = []
|
||||
paths.forEach(function (path) {
|
||||
findFilesRecursive([path], function (fileObjs) {
|
||||
paths.forEach(path => {
|
||||
findFilesRecursive([path], fileObjs => {
|
||||
ret.push(...fileObjs)
|
||||
if (++numComplete === paths.length) {
|
||||
ret.sort((a, b) => a.path < b.path ? -1 : Number(a.path > b.path))
|
||||
@@ -359,7 +361,7 @@ function findFilesRecursive (paths, cb_) {
|
||||
}
|
||||
|
||||
const fileOrFolder = paths[0]
|
||||
fs.stat(fileOrFolder, function (err, stat) {
|
||||
fs.stat(fileOrFolder, (err, stat) => {
|
||||
if (err) return dispatch('error', err)
|
||||
|
||||
// Files: return name, path, and size
|
||||
@@ -374,7 +376,7 @@ function findFilesRecursive (paths, cb_) {
|
||||
|
||||
// Folders: recurse, make a list of all the files
|
||||
const folderPath = fileOrFolder
|
||||
fs.readdir(folderPath, function (err, fileNames) {
|
||||
fs.readdir(folderPath, (err, fileNames) => {
|
||||
if (err) return dispatch('error', err)
|
||||
const paths = fileNames.map((fileName) => path.join(folderPath, fileName))
|
||||
findFilesRecursive(paths, cb_)
|
||||
@@ -384,7 +386,7 @@ function findFilesRecursive (paths, cb_) {
|
||||
|
||||
function deleteFile (path) {
|
||||
if (!path) return
|
||||
fs.unlink(path, function (err) {
|
||||
fs.unlink(path, err => {
|
||||
if (err) dispatch('error', err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,17 +54,17 @@ function init (appState, callback) {
|
||||
state.devices.airplay = airplayPlayer()
|
||||
|
||||
// Listen for devices: Chromecast, DLNA and Airplay
|
||||
chromecasts.on('update', function (device) {
|
||||
chromecasts.on('update', device => {
|
||||
// TODO: how do we tell if there are *no longer* any Chromecasts available?
|
||||
// From looking at the code, chromecasts.players only grows, never shrinks
|
||||
state.devices.chromecast.addDevice(device)
|
||||
})
|
||||
|
||||
dlnacasts.on('update', function (device) {
|
||||
dlnacasts.on('update', device => {
|
||||
state.devices.dlna.addDevice(device)
|
||||
})
|
||||
|
||||
airplayer.on('update', function (device) {
|
||||
airplayer.on('update', device => {
|
||||
state.devices.airplay.addDevice(device)
|
||||
})
|
||||
}
|
||||
@@ -116,7 +116,7 @@ function chromecastPlayer () {
|
||||
}
|
||||
|
||||
function addDevice (device) {
|
||||
device.on('error', function (err) {
|
||||
device.on('error', err => {
|
||||
if (device !== ret.device) return
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -125,7 +125,7 @@ function chromecastPlayer () {
|
||||
})
|
||||
update()
|
||||
})
|
||||
device.on('disconnect', function () {
|
||||
device.on('disconnect', () => {
|
||||
if (device !== ret.device) return
|
||||
state.playing.location = 'local'
|
||||
update()
|
||||
@@ -144,8 +144,8 @@ function chromecastPlayer () {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Transfer-Encoding': 'chunked'
|
||||
})
|
||||
res.end(Buffer.from(selectedSubtitle.buffer.substr(21), 'base64'))
|
||||
}).listen(0, function () {
|
||||
res.end(Buffer.from(selectedSubtitle.buffer.slice(21), 'base64'))
|
||||
}).listen(0, () => {
|
||||
const port = ret.subServer.address().port
|
||||
const subtitlesUrl = 'http://' + state.server.networkAddress + ':' + port + '/'
|
||||
callback(subtitlesUrl)
|
||||
@@ -155,13 +155,13 @@ function chromecastPlayer () {
|
||||
|
||||
function open () {
|
||||
const torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash)
|
||||
serveSubtitles(function (subtitlesUrl) {
|
||||
serveSubtitles(subtitlesUrl => {
|
||||
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, {
|
||||
type: 'video/mp4',
|
||||
title: config.APP_NAME + ' - ' + torrentSummary.name,
|
||||
subtitles: subtitlesUrl ? [subtitlesUrl] : [],
|
||||
autoSubtitles: !!subtitlesUrl
|
||||
}, function (err) {
|
||||
}, err => {
|
||||
if (err) {
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -221,7 +221,7 @@ function airplayPlayer () {
|
||||
return ret
|
||||
|
||||
function addDevice (player) {
|
||||
player.on('event', function (event) {
|
||||
player.on('event', event => {
|
||||
switch (event.state) {
|
||||
case 'loading':
|
||||
break
|
||||
@@ -243,7 +243,7 @@ function airplayPlayer () {
|
||||
}
|
||||
|
||||
function open () {
|
||||
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, function (err, res) {
|
||||
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, (err, res) => {
|
||||
if (err) {
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -270,7 +270,7 @@ function airplayPlayer () {
|
||||
}
|
||||
|
||||
function status () {
|
||||
ret.device.playbackInfo(function (err, res, status) {
|
||||
ret.device.playbackInfo((err, res, status) => {
|
||||
if (err) {
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -317,7 +317,7 @@ function dlnaPlayer (player) {
|
||||
}
|
||||
|
||||
function addDevice (device) {
|
||||
device.on('error', function (err) {
|
||||
device.on('error', err => {
|
||||
if (device !== ret.device) return
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -326,7 +326,7 @@ function dlnaPlayer (player) {
|
||||
})
|
||||
update()
|
||||
})
|
||||
device.on('disconnect', function () {
|
||||
device.on('disconnect', () => {
|
||||
if (device !== ret.device) return
|
||||
state.playing.location = 'local'
|
||||
update()
|
||||
@@ -339,7 +339,7 @@ function dlnaPlayer (player) {
|
||||
type: 'video/mp4',
|
||||
title: config.APP_NAME + ' - ' + torrentSummary.name,
|
||||
seek: state.playing.currentTime > 10 ? state.playing.currentTime : 0
|
||||
}, function (err) {
|
||||
}, err => {
|
||||
if (err) {
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -374,7 +374,7 @@ function dlnaPlayer (player) {
|
||||
}
|
||||
|
||||
function volume (volume, callback) {
|
||||
ret.device.volume(volume, function (err) {
|
||||
ret.device.volume(volume, err => {
|
||||
// quick volume update
|
||||
state.playing.volume = volume
|
||||
callback(err)
|
||||
@@ -396,7 +396,7 @@ function handleStatus (err, status) {
|
||||
|
||||
// Start polling cast device state, whenever we're connected
|
||||
function startStatusInterval () {
|
||||
statusInterval = setInterval(function () {
|
||||
statusInterval = setInterval(() => {
|
||||
const player = getPlayer()
|
||||
if (player) player.status()
|
||||
}, 1000)
|
||||
@@ -454,7 +454,7 @@ function selectDevice (index) {
|
||||
function stop () {
|
||||
const player = getPlayer()
|
||||
if (player) {
|
||||
player.stop(function () {
|
||||
player.stop(() => {
|
||||
player.device = null
|
||||
stoppedCasting()
|
||||
})
|
||||
@@ -522,6 +522,6 @@ function setVolume (volume) {
|
||||
if (player) player.volume(volume, castCallback)
|
||||
}
|
||||
|
||||
function castCallback () {
|
||||
console.log('%s callback: %o', state.playing.location, arguments)
|
||||
function castCallback (...args) {
|
||||
console.log('%s callback: %o', state.playing.location, args)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
const dispatchers = {}
|
||||
let _dispatch = function () {}
|
||||
let _dispatch = () => {}
|
||||
|
||||
function setDispatch (dispatch) {
|
||||
_dispatch = dispatch
|
||||
@@ -23,7 +23,7 @@ function dispatcher (...args) {
|
||||
const str = JSON.stringify(args)
|
||||
let handler = dispatchers[str]
|
||||
if (!handler) {
|
||||
handler = dispatchers[str] = function (e) {
|
||||
handler = dispatchers[str] = e => {
|
||||
// Do not propagate click to elements below the button
|
||||
e.stopPropagation()
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ function migrate_0_7_0 (saved) {
|
||||
const { copyFileSync } = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
saved.torrents.forEach(function (ts) {
|
||||
saved.torrents.forEach(ts => {
|
||||
const infoHash = ts.infoHash
|
||||
|
||||
// Replace torrentPath with torrentFileName
|
||||
@@ -134,7 +134,7 @@ function migrate_0_12_0 (saved) {
|
||||
'02767050e0be2fd4db9a2ad6c12416ac806ed6ed.torrent',
|
||||
'3ba219a8634bf7bae3d848192b2da75ae995589d.torrent'
|
||||
]
|
||||
saved.torrents.forEach(function (torrentSummary) {
|
||||
saved.torrents.forEach(torrentSummary => {
|
||||
if (!defaultTorrentFiles.includes(torrentSummary.torrentFileName)) return
|
||||
const fileOrFolder = TorrentSummary.getFileOrFolder(torrentSummary)
|
||||
if (!fileOrFolder) return
|
||||
@@ -148,16 +148,16 @@ function migrate_0_12_0 (saved) {
|
||||
}
|
||||
|
||||
function migrate_0_14_0 (saved) {
|
||||
saved.torrents.forEach(function (ts) {
|
||||
saved.torrents.forEach(ts => {
|
||||
delete ts.defaultPlayFileIndex
|
||||
})
|
||||
}
|
||||
|
||||
function migrate_0_17_0 (saved) {
|
||||
// Fix a sad, sad bug that resulted in 100MB+ config.json files
|
||||
saved.torrents.forEach(function (ts) {
|
||||
saved.torrents.forEach(ts => {
|
||||
if (!ts.files) return
|
||||
ts.files.forEach(function (file) {
|
||||
ts.files.forEach(file => {
|
||||
if (!file.audioInfo || !file.audioInfo.picture) return
|
||||
// This contained a Buffer, which 30x'd in size when serialized to JSON
|
||||
delete file.audioInfo.picture
|
||||
@@ -179,9 +179,7 @@ function migrate_0_17_2 (saved) {
|
||||
const OLD_HASH = '3ba219a8634bf7bae3d848192b2da75ae995589d'
|
||||
const NEW_HASH = 'a88fda5954e89178c372716a6a78b8180ed4dad3'
|
||||
|
||||
const ts = saved.torrents.find((ts) => {
|
||||
return ts.infoHash === OLD_HASH
|
||||
})
|
||||
const ts = saved.torrents.find(ts => ts.infoHash === OLD_HASH)
|
||||
|
||||
if (!ts) return // Wired CD torrent does not exist
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ const path = require('path')
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const config = require('../../config')
|
||||
const defaultAnnounceList = require('create-torrent').announceList.map((arr) => arr[0])
|
||||
|
||||
const SAVE_DEBOUNCE_INTERVAL = 1000
|
||||
|
||||
@@ -12,13 +13,13 @@ const State = module.exports = Object.assign(new EventEmitter(), {
|
||||
getDefaultPlayState,
|
||||
load,
|
||||
// state.save() calls are rate-limited. Use state.saveImmediate() to skip limit.
|
||||
save: function () {
|
||||
save (...args) {
|
||||
// Perf optimization: Lazy-require debounce (and it's dependencies)
|
||||
const debounce = require('debounce')
|
||||
// After first State.save() invokation, future calls go straight to the
|
||||
// debounced function
|
||||
State.save = debounce(saveImmediate, SAVE_DEBOUNCE_INTERVAL)
|
||||
State.save(...arguments)
|
||||
State.save(...args)
|
||||
},
|
||||
saveImmediate
|
||||
})
|
||||
@@ -79,6 +80,7 @@ function getDefaultState () {
|
||||
getPlayingTorrentSummary,
|
||||
getPlayingFileSummary,
|
||||
getExternalPlayerName,
|
||||
getGlobalTrackers,
|
||||
shouldHidePlayerControls
|
||||
}
|
||||
}
|
||||
@@ -129,7 +131,8 @@ function setupStateSaved () {
|
||||
soundNotifications: true,
|
||||
autoAddTorrents: false,
|
||||
torrentsFolderPath: '',
|
||||
highestPlaybackPriority: true
|
||||
highestPlaybackPriority: true,
|
||||
globalTrackers: defaultAnnounceList
|
||||
},
|
||||
torrents: config.DEFAULT_TORRENTS.map(createTorrentObject),
|
||||
torrentsToResume: [],
|
||||
@@ -198,8 +201,15 @@ function shouldHidePlayerControls () {
|
||||
new Date().getTime() - this.playing.mouseStationarySince > 2000 &&
|
||||
!this.playing.mouseInControls &&
|
||||
!this.playing.isPaused &&
|
||||
this.playing.location === 'local' &&
|
||||
this.playing.playbackRate === 1
|
||||
this.playing.location === 'local'
|
||||
}
|
||||
|
||||
function getGlobalTrackers () {
|
||||
const trackers = this.saved.prefs.globalTrackers
|
||||
if (!trackers) {
|
||||
return defaultAnnounceList
|
||||
}
|
||||
return trackers
|
||||
}
|
||||
|
||||
async function load (cb) {
|
||||
@@ -242,7 +252,7 @@ async function saveImmediate (state, cb) {
|
||||
// reading the torrent file or file(s) to seed & don't have an infohash
|
||||
copy.torrents = copy.torrents
|
||||
.filter((x) => x.infoHash)
|
||||
.map(function (x) {
|
||||
.map(x => {
|
||||
const torrent = {}
|
||||
for (const key in x) {
|
||||
if (key === 'progress' || key === 'torrentKey') {
|
||||
|
||||
@@ -50,7 +50,7 @@ function send (state) {
|
||||
json: true
|
||||
}
|
||||
|
||||
get.post(opts, function (err, res) {
|
||||
get.post(opts, (err, res) => {
|
||||
if (err) return console.error('Error sending telemetry', err)
|
||||
if (res.statusCode !== 200) {
|
||||
return console.error(`Error sending telemetry, status code: ${res.statusCode}`)
|
||||
@@ -106,15 +106,14 @@ function getTorrentStats (state) {
|
||||
}
|
||||
|
||||
// First, count torrents & total file size
|
||||
for (let i = 0; i < count; i++) {
|
||||
const t = state.saved.torrents[i]
|
||||
const stat = byStatus[t.status]
|
||||
if (!t || !t.files || !stat) continue
|
||||
for (const torrent of state.saved.torrents) {
|
||||
const stat = byStatus[torrent.status]
|
||||
if (!torrent || !torrent.files || !stat) continue
|
||||
stat.count++
|
||||
for (let j = 0; j < t.files.length; j++) {
|
||||
const f = t.files[j]
|
||||
if (!f || !f.length) continue
|
||||
const fileSizeMB = f.length / (1 << 20)
|
||||
|
||||
for (const file of torrent.files) {
|
||||
if (!file || !file.length) continue
|
||||
const fileSizeMB = file.length / (1 << 20)
|
||||
sizeMB += fileSizeMB
|
||||
stat.sizeMB += fileSizeMB
|
||||
}
|
||||
@@ -145,7 +144,7 @@ function roundPow2 (n) {
|
||||
if (n <= 0) return 0
|
||||
// Otherwise, return 1, 2, 4, 8, etc by rounding in log space
|
||||
const log2 = Math.log(n) / Math.log(2)
|
||||
return Math.pow(2, Math.round(log2))
|
||||
return 2 ** Math.round(log2)
|
||||
}
|
||||
|
||||
// An uncaught error happened in the main process or in one of the windows
|
||||
|
||||
@@ -9,20 +9,14 @@ const msgNoSuitablePoster = 'Cannot generate a poster from any files in the torr
|
||||
|
||||
function torrentPoster (torrent, cb) {
|
||||
// First, try to use a poster image if available
|
||||
const posterFile = torrent.files.filter(function (file) {
|
||||
return /^poster\.(jpg|png|gif)$/.test(file.name)
|
||||
})[0]
|
||||
const posterFile = torrent.files.filter(file => /^poster\.(jpg|png|gif)$/.test(file.name))[0]
|
||||
if (posterFile) return extractPoster(posterFile, cb)
|
||||
|
||||
// 'score' each media type based on total size present in torrent
|
||||
const bestScore = ['audio', 'video', 'image'].map(mediaType => {
|
||||
return {
|
||||
type: mediaType,
|
||||
size: calculateDataLengthByExtension(torrent, mediaExtensions[mediaType])
|
||||
}
|
||||
}).sort((a, b) => { // sort descending on size
|
||||
return b.size - a.size
|
||||
})[0]
|
||||
const bestScore = ['audio', 'video', 'image'].map(mediaType => ({
|
||||
type: mediaType,
|
||||
size: calculateDataLengthByExtension(torrent, mediaExtensions[mediaType])
|
||||
})).sort((a, b) => b.size - a.size)[0] // sort descending on size
|
||||
|
||||
if (bestScore.size === 0) {
|
||||
// Admit defeat, no video, audio or image had a significant presence
|
||||
@@ -51,9 +45,7 @@ function calculateDataLengthByExtension (torrent, extensions) {
|
||||
if (files.length === 0) return 0
|
||||
return files
|
||||
.map(file => file.length)
|
||||
.reduce((a, b) => {
|
||||
return a + b
|
||||
})
|
||||
.reduce((a, b) => a + b)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,9 +57,7 @@ function calculateDataLengthByExtension (torrent, extensions) {
|
||||
function getLargestFileByExtension (torrent, extensions) {
|
||||
const files = filterOnExtension(torrent, extensions)
|
||||
if (files.length === 0) return undefined
|
||||
return files.reduce((a, b) => {
|
||||
return a.length > b.length ? a : b
|
||||
})
|
||||
return files.reduce((a, b) => a.length > b.length ? a : b)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,12 +105,10 @@ function torrentPosterFromAudio (torrent, cb) {
|
||||
|
||||
if (imageFiles.length === 0) return cb(new Error(msgNoSuitablePoster))
|
||||
|
||||
const bestCover = imageFiles.map(file => {
|
||||
return {
|
||||
file,
|
||||
score: scoreAudioCoverFile(file)
|
||||
}
|
||||
}).reduce((a, b) => {
|
||||
const bestCover = imageFiles.map(file => ({
|
||||
file,
|
||||
score: scoreAudioCoverFile(file)
|
||||
})).reduce((a, b) => {
|
||||
if (a.score > b.score) {
|
||||
return a
|
||||
}
|
||||
@@ -190,5 +178,5 @@ function torrentPosterFromImage (torrent, cb) {
|
||||
|
||||
function extractPoster (file, cb) {
|
||||
const extname = path.extname(file.name)
|
||||
file.getBuffer((err, buf) => { return cb(err, buf, extname) })
|
||||
file.getBuffer((err, buf) => cb(err, buf, extname))
|
||||
}
|
||||
|
||||
@@ -104,9 +104,7 @@ function onState (err, _state) {
|
||||
const TorrentController = require('./controllers/torrent-controller')
|
||||
return new TorrentController(state)
|
||||
}),
|
||||
torrentList: createGetter(() => {
|
||||
return new TorrentListController(state)
|
||||
}),
|
||||
torrentList: createGetter(() => new TorrentListController(state)),
|
||||
update: createGetter(() => {
|
||||
const UpdateController = require('./controllers/update-controller')
|
||||
return new UpdateController(state)
|
||||
@@ -126,6 +124,9 @@ function onState (err, _state) {
|
||||
}
|
||||
})
|
||||
|
||||
// Give global trackers
|
||||
setGlobalTrackers()
|
||||
|
||||
// Restart everything we were torrenting last time the app ran
|
||||
resumeTorrents()
|
||||
|
||||
@@ -155,11 +156,11 @@ function onState (err, _state) {
|
||||
// Add YouTube style hotkey shortcuts
|
||||
window.addEventListener('keydown', onKeydown)
|
||||
|
||||
const debouncedFullscreenToggle = debounce(function () {
|
||||
const debouncedFullscreenToggle = debounce(() => {
|
||||
dispatch('toggleFullScreen')
|
||||
}, 1000, true)
|
||||
|
||||
document.addEventListener('wheel', function (event) {
|
||||
document.addEventListener('wheel', event => {
|
||||
// ctrlKey detects pinch to zoom, http://crbug.com/289887
|
||||
if (event.ctrlKey) {
|
||||
event.preventDefault()
|
||||
@@ -316,6 +317,7 @@ const dispatchHandlers = {
|
||||
preferences: () => controllers.prefs().show(),
|
||||
updatePreferences: (key, value) => controllers.prefs().update(key, value),
|
||||
checkDownloadPath,
|
||||
updateGlobalTrackers: (trackers) => setGlobalTrackers(trackers),
|
||||
startFolderWatcher: () => controllers.folderWatcher().start(),
|
||||
stopFolderWatcher: () => controllers.folderWatcher().stop(),
|
||||
|
||||
@@ -400,7 +402,7 @@ function setupIpc () {
|
||||
function backToList () {
|
||||
// Exit any modals and screens with a back button
|
||||
state.modal = null
|
||||
state.location.backToFirst(function () {
|
||||
state.location.backToFirst(() => {
|
||||
// If we were already on the torrent list, scroll to the top
|
||||
const contentTag = document.querySelector('.content')
|
||||
if (contentTag) contentTag.scrollTop = 0
|
||||
@@ -418,6 +420,10 @@ function escapeBack () {
|
||||
}
|
||||
}
|
||||
|
||||
function setGlobalTrackers () {
|
||||
controllers.torrentList().setGlobalTrackers(state.getGlobalTrackers())
|
||||
}
|
||||
|
||||
// Starts all torrents that aren't paused on program startup
|
||||
function resumeTorrents () {
|
||||
state.saved.torrents
|
||||
@@ -590,7 +596,7 @@ function onWindowBoundsChanged (e, newBounds) {
|
||||
}
|
||||
|
||||
function checkDownloadPath () {
|
||||
fs.stat(state.saved.prefs.downloadPath, function (err, stat) {
|
||||
fs.stat(state.saved.prefs.downloadPath, (err, stat) => {
|
||||
if (err) {
|
||||
state.downloadPathStatus = 'missing'
|
||||
return console.error(err)
|
||||
|
||||
@@ -86,9 +86,7 @@ class App extends React.Component {
|
||||
const recentErrors = state.errors.filter((x) => now - x.time < 5000)
|
||||
const hasErrors = recentErrors.length > 0
|
||||
|
||||
const errorElems = recentErrors.map(function (error, i) {
|
||||
return (<div key={i} className='error'>{error.message}</div>)
|
||||
})
|
||||
const errorElems = recentErrors.map((error, i) => <div key={i} className='error'>{error.message}</div>)
|
||||
return (
|
||||
<div
|
||||
key='errors'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* globals MediaMetadata */
|
||||
|
||||
const React = require('react')
|
||||
const BitField = require('bitfield').default
|
||||
const prettyBytes = require('prettier-bytes')
|
||||
@@ -35,6 +37,7 @@ module.exports = class Player extends React.Component {
|
||||
tag.pause()
|
||||
tag.src = ''
|
||||
tag.load()
|
||||
navigator.mediaSession.metadata = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +54,28 @@ function renderMedia (state) {
|
||||
// Get the <video> or <audio> tag
|
||||
const mediaElement = document.querySelector(state.playing.type)
|
||||
if (mediaElement !== null) {
|
||||
if (navigator.mediaSession.metadata === null && mediaElement.played.length !== 0) {
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: state.playing.fileName
|
||||
})
|
||||
navigator.mediaSession.setActionHandler('pause', () => {
|
||||
dispatch('playPause')
|
||||
})
|
||||
navigator.mediaSession.setActionHandler('play', () => {
|
||||
dispatch('playPause')
|
||||
})
|
||||
if (Playlist.hasNext(state)) {
|
||||
navigator.mediaSession.setActionHandler('nexttrack', () => {
|
||||
dispatch('nextTrack')
|
||||
})
|
||||
}
|
||||
if (Playlist.hasPrevious(state)) {
|
||||
navigator.mediaSession.setActionHandler('previoustrack', () => {
|
||||
dispatch('previousTrack')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (state.playing.isPaused && !mediaElement.paused) {
|
||||
mediaElement.pause()
|
||||
} else if (!state.playing.isPaused && mediaElement.paused) {
|
||||
@@ -109,8 +134,7 @@ function renderMedia (state) {
|
||||
// Add subtitles to the <video> tag
|
||||
const trackTags = []
|
||||
if (state.playing.subtitles.selectedIndex >= 0) {
|
||||
for (let i = 0; i < state.playing.subtitles.tracks.length; i++) {
|
||||
const track = state.playing.subtitles.tracks[i]
|
||||
state.playing.subtitles.tracks.forEach((track, i) => {
|
||||
const isSelected = state.playing.subtitles.selectedIndex === i
|
||||
trackTags.push(
|
||||
<track
|
||||
@@ -121,7 +145,7 @@ function renderMedia (state) {
|
||||
src={track.buffer}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Create the <audio> or <video> tag
|
||||
@@ -200,7 +224,7 @@ function renderMedia (state) {
|
||||
}
|
||||
}
|
||||
|
||||
function onEnded (e) {
|
||||
function onEnded () {
|
||||
if (Playlist.hasNext(state)) {
|
||||
dispatch('nextTrack')
|
||||
} else {
|
||||
@@ -504,7 +528,7 @@ function renderCastOptions (state) {
|
||||
const { location, devices } = state.devices.castMenu
|
||||
const player = state.devices[location]
|
||||
|
||||
const items = devices.map(function (device, ix) {
|
||||
const items = devices.map((device, ix) => {
|
||||
const isSelected = player.device === device
|
||||
const name = device.name
|
||||
return (
|
||||
@@ -527,7 +551,7 @@ function renderSubtitleOptions (state) {
|
||||
const subtitles = state.playing.subtitles
|
||||
if (!subtitles.tracks.length || !subtitles.showMenu) return
|
||||
|
||||
const items = subtitles.tracks.map(function (track, ix) {
|
||||
const items = subtitles.tracks.map((track, ix) => {
|
||||
const isSelected = state.playing.subtitles.selectedIndex === ix
|
||||
return (
|
||||
<li key={ix} onClick={dispatcher('selectSubtitle', ix)}>
|
||||
@@ -554,7 +578,7 @@ function renderAudioTrackOptions (state) {
|
||||
const audioTracks = state.playing.audioTracks
|
||||
if (!audioTracks.tracks.length || !audioTracks.showMenu) return
|
||||
|
||||
const items = audioTracks.tracks.map(function (track, ix) {
|
||||
const items = audioTracks.tracks.map((track, ix) => {
|
||||
const isSelected = state.playing.audioTracks.selectedIndex === ix
|
||||
return (
|
||||
<li key={ix} onClick={dispatcher('selectAudioTrack', ix)}>
|
||||
@@ -611,6 +635,8 @@ function renderPlayerControls (state) {
|
||||
key='skip-previous'
|
||||
className={'icon skip-previous float-left ' + prevClass}
|
||||
onClick={dispatcher('previousTrack')}
|
||||
role='button'
|
||||
aria-label='Previous track'
|
||||
>
|
||||
skip_previous
|
||||
</i>,
|
||||
@@ -619,6 +645,8 @@ function renderPlayerControls (state) {
|
||||
key='play'
|
||||
className='icon play-pause float-left'
|
||||
onClick={dispatcher('playPause')}
|
||||
role='button'
|
||||
aria-label={state.playing.isPaused ? 'Play' : 'Pause'}
|
||||
>
|
||||
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
||||
</i>,
|
||||
@@ -627,6 +655,8 @@ function renderPlayerControls (state) {
|
||||
key='skip-next'
|
||||
className={'icon skip-next float-left ' + nextClass}
|
||||
onClick={dispatcher('nextTrack')}
|
||||
role='button'
|
||||
aria-label='Next track'
|
||||
>
|
||||
skip_next
|
||||
</i>,
|
||||
@@ -635,6 +665,8 @@ function renderPlayerControls (state) {
|
||||
key='fullscreen'
|
||||
className='icon fullscreen float-right'
|
||||
onClick={dispatcher('toggleFullScreen')}
|
||||
role='button'
|
||||
aria-label={state.window.isFullScreen ? 'Exit full screen' : 'Enter full screen'}
|
||||
>
|
||||
{state.window.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}
|
||||
</i>
|
||||
@@ -647,6 +679,8 @@ function renderPlayerControls (state) {
|
||||
key='subtitles'
|
||||
className={'icon closed-caption float-right ' + captionsClass}
|
||||
onClick={handleSubtitles}
|
||||
role='button'
|
||||
aria-label='Closed captions'
|
||||
>
|
||||
closed_caption
|
||||
</i>
|
||||
@@ -672,7 +706,7 @@ function renderPlayerControls (state) {
|
||||
airplay: { true: 'airplay', false: 'airplay' },
|
||||
dlna: { true: 'tv', false: 'tv' }
|
||||
}
|
||||
castTypes.forEach(function (castType) {
|
||||
castTypes.forEach(castType => {
|
||||
// Do we show this button (eg. the Chromecast button) at all?
|
||||
const isCasting = state.playing.location.startsWith(castType)
|
||||
const player = state.devices[castType]
|
||||
@@ -728,6 +762,8 @@ function renderPlayerControls (state) {
|
||||
<i
|
||||
className='icon volume-icon float-left'
|
||||
onMouseDown={handleVolumeMute}
|
||||
role='button'
|
||||
aria-label='Mute'
|
||||
>
|
||||
{volumeIcon}
|
||||
</i>
|
||||
@@ -779,7 +815,7 @@ function renderPlayerControls (state) {
|
||||
dispatch('preview', e.clientX)
|
||||
}
|
||||
|
||||
function clearPreview (e) {
|
||||
function clearPreview () {
|
||||
if (state.playing.type !== 'video') return
|
||||
dispatch('clearPreview')
|
||||
}
|
||||
@@ -795,7 +831,7 @@ function renderPlayerControls (state) {
|
||||
}
|
||||
|
||||
// Handles volume muting and Unmuting
|
||||
function handleVolumeMute (e) {
|
||||
function handleVolumeMute () {
|
||||
if (state.playing.volume === 0.0) {
|
||||
dispatch('setVolume', 1.0)
|
||||
} else {
|
||||
@@ -817,7 +853,7 @@ function renderPlayerControls (state) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleAudioTracks (e) {
|
||||
function handleAudioTracks () {
|
||||
dispatch('toggleAudioTracksMenu')
|
||||
}
|
||||
|
||||
@@ -914,7 +950,7 @@ function renderLoadingBar (state) {
|
||||
}
|
||||
|
||||
// Output some bars to show which parts of the file are loaded
|
||||
const loadingBarElems = parts.map(function (part, i) {
|
||||
const loadingBarElems = parts.map((part, i) => {
|
||||
const style = {
|
||||
left: (100 * part.start / fileProg.numPieces) + '%',
|
||||
width: (100 * part.count / fileProg.numPieces) + '%'
|
||||
|
||||
@@ -4,6 +4,7 @@ const PropTypes = require('prop-types')
|
||||
const colors = require('material-ui/styles/colors')
|
||||
const Checkbox = require('material-ui/Checkbox').default
|
||||
const RaisedButton = require('material-ui/RaisedButton').default
|
||||
const TextField = require('material-ui/TextField').default
|
||||
const Heading = require('../components/heading')
|
||||
const PathSelector = require('../components/path-selector')
|
||||
|
||||
@@ -28,6 +29,15 @@ class PreferencesPage extends React.Component {
|
||||
|
||||
this.handleSoundNotificationsChange =
|
||||
this.handleSoundNotificationsChange.bind(this)
|
||||
|
||||
this.handleSetGlobalTrackers =
|
||||
this.handleSetGlobalTrackers.bind(this)
|
||||
|
||||
const globalTrackers = this.props.state.getGlobalTrackers().join('\n')
|
||||
|
||||
this.state = {
|
||||
globalTrackers
|
||||
}
|
||||
}
|
||||
|
||||
downloadPathSelector () {
|
||||
@@ -229,6 +239,39 @@ class PreferencesPage extends React.Component {
|
||||
dispatch('updatePreferences', 'isFileHandler', true)
|
||||
}
|
||||
|
||||
setGlobalTrackers () {
|
||||
// Align the text fields
|
||||
const textFieldStyle = { width: '100%' }
|
||||
const textareaStyle = { margin: 0 }
|
||||
|
||||
return (
|
||||
<Preference>
|
||||
<TextField
|
||||
className='torrent-trackers control'
|
||||
style={textFieldStyle}
|
||||
textareaStyle={textareaStyle}
|
||||
multiLine
|
||||
rows={2}
|
||||
rowsMax={10}
|
||||
value={this.state.globalTrackers}
|
||||
onChange={this.handleSetGlobalTrackers}
|
||||
/>
|
||||
</Preference>
|
||||
)
|
||||
}
|
||||
|
||||
handleSetGlobalTrackers (e, globalTrackers) {
|
||||
this.setState({ globalTrackers })
|
||||
|
||||
const announceList = globalTrackers
|
||||
.split('\n')
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s !== '')
|
||||
|
||||
dispatch('updatePreferences', 'globalTrackers', announceList)
|
||||
dispatch('updateGlobalTrackers', announceList)
|
||||
}
|
||||
|
||||
render () {
|
||||
const style = {
|
||||
color: colors.grey400,
|
||||
@@ -254,6 +297,9 @@ class PreferencesPage extends React.Component {
|
||||
{this.setStartupCheckbox()}
|
||||
{this.soundNotificationsCheckbox()}
|
||||
</PreferencesSection>
|
||||
<PreferencesSection title='Trackers'>
|
||||
{this.setGlobalTrackers()}
|
||||
</PreferencesSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ console.time('init')
|
||||
|
||||
const crypto = require('crypto')
|
||||
const util = require('util')
|
||||
const defaultAnnounceList = require('create-torrent').announceList
|
||||
const { ipcRenderer } = require('electron')
|
||||
const fs = require('fs')
|
||||
const mm = require('music-metadata')
|
||||
@@ -16,11 +15,6 @@ const config = require('../config')
|
||||
const { TorrentKeyNotFoundError } = require('./lib/errors')
|
||||
const torrentPoster = require('./lib/torrent-poster')
|
||||
|
||||
// Force use of webtorrent trackers on all torrents
|
||||
globalThis.WEBTORRENT_ANNOUNCE = defaultAnnounceList
|
||||
.map((arr) => arr[0])
|
||||
.filter((url) => url.indexOf('wss://') === 0 || url.indexOf('ws://') === 0)
|
||||
|
||||
/**
|
||||
* WebTorrent version.
|
||||
*/
|
||||
@@ -65,6 +59,8 @@ init()
|
||||
function init () {
|
||||
listenToClientEvents()
|
||||
|
||||
ipcRenderer.on('wt-set-global-trackers', (e, globalTrackers) =>
|
||||
setGlobalTrackers(globalTrackers))
|
||||
ipcRenderer.on('wt-start-torrenting', (e, torrentKey, torrentID, path, fileModtimes, selections) =>
|
||||
startTorrenting(torrentKey, torrentID, path, fileModtimes, selections))
|
||||
ipcRenderer.on('wt-stop-torrenting', (e, infoHash) =>
|
||||
@@ -79,7 +75,7 @@ function init () {
|
||||
getAudioMetadata(infoHash, index))
|
||||
ipcRenderer.on('wt-start-server', (e, infoHash) =>
|
||||
startServer(infoHash))
|
||||
ipcRenderer.on('wt-stop-server', (e) =>
|
||||
ipcRenderer.on('wt-stop-server', () =>
|
||||
stopServer())
|
||||
ipcRenderer.on('wt-select-files', (e, infoHash, selections) =>
|
||||
selectFiles(infoHash, selections))
|
||||
@@ -99,6 +95,11 @@ function listenToClientEvents () {
|
||||
client.on('error', (err) => ipcRenderer.send('wt-error', null, err.message))
|
||||
}
|
||||
|
||||
// Sets the default trackers
|
||||
function setGlobalTrackers (globalTrackers) {
|
||||
globalThis.WEBTORRENT_ANNOUNCE = globalTrackers
|
||||
}
|
||||
|
||||
// Starts a given TorrentID, which can be an infohash, magnet URI, etc.
|
||||
// Returns a WebTorrent object. See https://git.io/vik9M
|
||||
function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections) {
|
||||
@@ -165,7 +166,7 @@ function addTorrentEvents (torrent) {
|
||||
|
||||
updateTorrentProgress()
|
||||
|
||||
torrent.getFileModtimes(function (err, fileModtimes) {
|
||||
torrent.getFileModtimes((err, fileModtimes) => {
|
||||
if (err) return onError(err)
|
||||
ipcRenderer.send('wt-file-modtimes', torrent.key, fileModtimes)
|
||||
})
|
||||
@@ -200,7 +201,7 @@ function saveTorrentFile (torrentKey) {
|
||||
const torrent = getTorrent(torrentKey)
|
||||
const torrentPath = path.join(config.TORRENT_PATH, torrent.infoHash + '.torrent')
|
||||
|
||||
fs.access(torrentPath, fs.constants.R_OK, function (err) {
|
||||
fs.access(torrentPath, fs.constants.R_OK, err => {
|
||||
const fileName = torrent.infoHash + '.torrent'
|
||||
if (!err) {
|
||||
// We've already saved the file
|
||||
@@ -208,8 +209,8 @@ function saveTorrentFile (torrentKey) {
|
||||
}
|
||||
|
||||
// Otherwise, save the .torrent file, under the app config folder
|
||||
fs.mkdir(config.TORRENT_PATH, { recursive: true }, function (_) {
|
||||
fs.writeFile(torrentPath, torrent.torrentFile, function (err) {
|
||||
fs.mkdir(config.TORRENT_PATH, { recursive: true }, _ => {
|
||||
fs.writeFile(torrentPath, torrent.torrentFile, err => {
|
||||
if (err) return console.log('error saving torrent file %s: %o', torrentPath, err)
|
||||
console.log('saved torrent file %s', torrentPath)
|
||||
return ipcRenderer.send('wt-file-saved', torrentKey, fileName)
|
||||
@@ -222,14 +223,14 @@ function saveTorrentFile (torrentKey) {
|
||||
// Auto chooses either a frame from a video file, an image, etc
|
||||
function generateTorrentPoster (torrentKey) {
|
||||
const torrent = getTorrent(torrentKey)
|
||||
torrentPoster(torrent, function (err, buf, extension) {
|
||||
torrentPoster(torrent, (err, buf, extension) => {
|
||||
if (err) return console.log('error generating poster: %o', err)
|
||||
// save it for next time
|
||||
fs.mkdir(config.POSTER_PATH, { recursive: true }, function (err) {
|
||||
fs.mkdir(config.POSTER_PATH, { recursive: true }, err => {
|
||||
if (err) return console.log('error creating poster dir: %o', err)
|
||||
const posterFileName = torrent.infoHash + extension
|
||||
const posterFilePath = path.join(config.POSTER_PATH, posterFileName)
|
||||
fs.writeFile(posterFilePath, buf, function (err) {
|
||||
fs.writeFile(posterFilePath, buf, err => {
|
||||
if (err) return console.log('error saving poster: %o', err)
|
||||
// show the poster
|
||||
ipcRenderer.send('wt-poster', torrentKey, posterFileName)
|
||||
@@ -251,15 +252,13 @@ function updateTorrentProgress () {
|
||||
function getTorrentProgress () {
|
||||
// First, track overall progress
|
||||
const progress = client.progress
|
||||
const hasActiveTorrents = client.torrents.some(function (torrent) {
|
||||
return torrent.progress !== 1
|
||||
})
|
||||
const hasActiveTorrents = client.torrents.some(torrent => torrent.progress !== 1)
|
||||
|
||||
// Track progress for every file in each torrent
|
||||
// TODO: ideally this would be tracked by WebTorrent, which could do it
|
||||
// more efficiently than looping over torrent.bitfield
|
||||
const torrentProg = client.torrents.map(function (torrent) {
|
||||
const fileProg = torrent.files && torrent.files.map(function (file, index) {
|
||||
const torrentProg = client.torrents.map(torrent => {
|
||||
const fileProg = torrent.files && torrent.files.map(file => {
|
||||
const numPieces = file._endPiece - file._startPiece + 1
|
||||
let numPiecesPresent = 0
|
||||
for (let piece = file._startPiece; piece <= file._endPiece; piece++) {
|
||||
@@ -299,12 +298,12 @@ function startServer (infoHash) {
|
||||
else torrent.once('ready', () => startServerFromReadyTorrent(torrent))
|
||||
}
|
||||
|
||||
function startServerFromReadyTorrent (torrent, cb) {
|
||||
function startServerFromReadyTorrent (torrent) {
|
||||
if (server) return
|
||||
|
||||
// start the streaming torrent-to-http server
|
||||
server = torrent.createServer()
|
||||
server.listen(0, function () {
|
||||
server.listen(0, () => {
|
||||
const port = server.address().port
|
||||
const urlSuffix = ':' + port
|
||||
const info = {
|
||||
@@ -339,7 +338,7 @@ function getAudioMetadata (infoHash, index) {
|
||||
native: false,
|
||||
skipCovers: true,
|
||||
fileSize: file.length,
|
||||
observer: event => {
|
||||
observer: () => {
|
||||
ipcRenderer.send('wt-audio-metadata', infoHash, index, {
|
||||
common: metadata.common,
|
||||
format: metadata.format
|
||||
@@ -384,7 +383,7 @@ function selectFiles (torrentOrInfoHash, selections) {
|
||||
// selection with individual selections for each file, so we can
|
||||
// select/deselect files later on
|
||||
if (!selections) {
|
||||
selections = torrent.files.map((x) => true)
|
||||
selections = new Array(torrent.files.length).fill(true)
|
||||
}
|
||||
|
||||
// Selections specified incorrectly?
|
||||
@@ -397,15 +396,15 @@ function selectFiles (torrentOrInfoHash, selections) {
|
||||
torrent.deselect(0, torrent.pieces.length - 1, false)
|
||||
|
||||
// Add selections (individual files)
|
||||
for (let i = 0; i < selections.length; i++) {
|
||||
selections.forEach((selection, i) => {
|
||||
const file = torrent.files[i]
|
||||
if (selections[i]) {
|
||||
if (selection) {
|
||||
file.select()
|
||||
} else {
|
||||
console.log('deselecting file ' + i + ' of torrent ' + torrent.name)
|
||||
file.deselect()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Gets a WebTorrent handle by torrentKey
|
||||
@@ -423,7 +422,7 @@ function onError (err) {
|
||||
// TODO: remove this once the following bugs are fixed:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=490143
|
||||
// https://github.com/electron/electron/issues/7212
|
||||
window.testOfflineMode = function () {
|
||||
window.testOfflineMode = () => {
|
||||
console.log('Test, going OFFLINE')
|
||||
client = window.client = new WebTorrent({
|
||||
peerId: PEER_ID,
|
||||
|
||||
@@ -71,7 +71,6 @@ table {
|
||||
|
||||
.app {
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
@@ -143,6 +142,7 @@ table {
|
||||
*/
|
||||
|
||||
.header {
|
||||
-webkit-app-region: drag;
|
||||
background: rgb(40, 40, 40);
|
||||
border-bottom: 1px solid rgb(30, 30, 30);
|
||||
height: 38px; /* vertically center OS menu buttons (OS X) */
|
||||
|
||||
Reference in New Issue
Block a user