Compare commits
138 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9749b43cfa | ||
|
|
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 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -12,8 +12,8 @@ jobs:
|
|||||||
node:
|
node:
|
||||||
- '16'
|
- '16'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
- run: npm install
|
- run: npm install
|
||||||
|
|||||||
24
.github/workflows/package.yml
vendored
24
.github/workflows/package.yml
vendored
@@ -5,11 +5,11 @@ jobs:
|
|||||||
package_linux:
|
package_linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '16'
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
${{ runner.os }}-node-
|
${{ runner.os }}-node-
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run package -- linux
|
- run: npm run package -- linux
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: linux
|
name: linux
|
||||||
path: |
|
path: |
|
||||||
@@ -27,11 +27,11 @@ jobs:
|
|||||||
package_macos:
|
package_macos:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '16'
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
${{ runner.os }}-node-
|
${{ runner.os }}-node-
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run package -- darwin
|
- run: npm run package -- darwin
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: macos
|
name: macos
|
||||||
path: |
|
path: |
|
||||||
@@ -48,11 +48,11 @@ jobs:
|
|||||||
package_windows:
|
package_windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '16'
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
${{ runner.os }}-node-
|
${{ runner.os }}-node-
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run package -- win32
|
- run: npm run package -- win32
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: windows
|
name: windows
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
6
.github/workflows/stale.yml
vendored
6
.github/workflows/stale.yml
vendored
@@ -12,12 +12,12 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v4
|
- uses: actions/stale@v6
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
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-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?'
|
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-issue-labels: accepted,blocked,dependency,security,meta
|
||||||
exempt-pr-labels: accepted,blocked,bug,dependency,enhancement,'help wanted',question,security,meta
|
exempt-pr-labels: accepted,blocked,bug,dependency,security,meta
|
||||||
stale-issue-label: 'stale'
|
stale-issue-label: 'stale'
|
||||||
stale-pr-label: 'stale'
|
stale-pr-label: 'stale'
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ to be installed. For example on Mac, first install
|
|||||||
[XQuartz](http://www.xquartz.org/), then run:
|
[XQuartz](http://www.xquartz.org/), then run:
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install wine mono
|
$ brew install wine mono
|
||||||
```
|
```
|
||||||
|
|
||||||
(Requires the [Homebrew](http://brew.sh/) package manager.)
|
(Requires the [Homebrew](http://brew.sh/) package manager.)
|
||||||
|
|||||||
18762
package-lock.json
generated
18762
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
64
package.json
64
package.json
@@ -21,67 +21,67 @@
|
|||||||
"url": "https://github.com/webtorrent/webtorrent-desktop/issues"
|
"url": "https://github.com/webtorrent/webtorrent-desktop/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "2.0.1",
|
"@electron/remote": "2.0.8",
|
||||||
|
"@material-ui/core": "4.12.4",
|
||||||
"airplayer": "github:webtorrent/airplayer#fix-security",
|
"airplayer": "github:webtorrent/airplayer#fix-security",
|
||||||
"application-config": "2.0.0",
|
"application-config": "2.0.0",
|
||||||
"arch": "2.2.0",
|
"arch": "2.2.0",
|
||||||
"auto-launch": "5.0.5",
|
"auto-launch": "5.0.5",
|
||||||
"bitfield": "4.0.0",
|
"bitfield": "4.1.0",
|
||||||
"capture-frame": "4.0.0",
|
"capture-frame": "4.0.0",
|
||||||
"chokidar": "3.5.2",
|
"chokidar": "3.5.3",
|
||||||
"chromecasts": "1.10.2",
|
"chromecasts": "1.10.2",
|
||||||
"create-torrent": "5.0.1",
|
"create-torrent": "5.0.6",
|
||||||
"debounce": "1.2.1",
|
"debounce": "1.2.1",
|
||||||
"dlnacasts": "0.1.0",
|
"dlnacasts": "0.1.0",
|
||||||
"drag-drop": "7.2.0",
|
"drag-drop": "7.2.0",
|
||||||
"es6-error": "4.1.1",
|
"es6-error": "4.1.1",
|
||||||
"fn-getter": "1.0.0",
|
"fn-getter": "1.0.0",
|
||||||
"iso-639-1": "2.1.9",
|
"iso-639-1": "2.1.15",
|
||||||
"languagedetect": "2.0.0",
|
"languagedetect": "2.0.0",
|
||||||
"location-history": "1.1.2",
|
"location-history": "1.1.2",
|
||||||
"material-ui": "0.20.2",
|
"music-metadata": "7.13.0",
|
||||||
"music-metadata": "7.11.4",
|
|
||||||
"network-address": "1.1.2",
|
"network-address": "1.1.2",
|
||||||
"parse-torrent": "9.1.4",
|
"parse-torrent": "9.1.5",
|
||||||
"prettier-bytes": "1.0.4",
|
"prettier-bytes": "1.0.4",
|
||||||
"prop-types": "15.7.2",
|
"prop-types": "15.8.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"run-parallel": "1.2.0",
|
"run-parallel": "1.2.0",
|
||||||
"semver": "7.3.5",
|
"semver": "7.3.8",
|
||||||
"simple-concat": "1.0.1",
|
"simple-concat": "1.0.1",
|
||||||
"simple-get": "4.0.0",
|
"simple-get": "4.0.1",
|
||||||
"srt-to-vtt": "1.1.3",
|
"srt-to-vtt": "1.1.3",
|
||||||
"vlc-command": "1.2.0",
|
"vlc-command": "1.2.0",
|
||||||
"webtorrent": "1.5.6",
|
"webtorrent": "1.8.32",
|
||||||
"winreg": "1.2.4"
|
"winreg": "1.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.15.7",
|
"@babel/cli": "7.19.3",
|
||||||
"@babel/core": "7.15.8",
|
"@babel/core": "7.19.3",
|
||||||
"@babel/eslint-parser": "7.15.8",
|
"@babel/eslint-parser": "7.19.1",
|
||||||
"@babel/plugin-transform-react-jsx": "7.14.9",
|
"@babel/plugin-transform-react-jsx": "7.19.0",
|
||||||
"cross-zip": "4.0.0",
|
"cross-zip": "4.0.0",
|
||||||
"depcheck": "1.4.2",
|
"depcheck": "1.4.3",
|
||||||
"electron": "15.2.0",
|
"electron": "15.5.7",
|
||||||
"electron-notarize": "1.1.1",
|
"electron-notarize": "1.2.1",
|
||||||
"electron-osx-sign": "0.5.0",
|
"electron-osx-sign": "0.6.0",
|
||||||
"electron-packager": "15.4.0",
|
"electron-packager": "15.5.2",
|
||||||
"electron-winstaller": "5.0.0",
|
"electron-winstaller": "5.0.0",
|
||||||
"gh-release": "6.0.1",
|
"gh-release": "6.0.4",
|
||||||
"minimist": "1.2.5",
|
"minimist": "1.2.6",
|
||||||
"nodemon": "2.0.13",
|
"nodemon": "2.0.20",
|
||||||
"open": "8.3.0",
|
"open": "8.4.0",
|
||||||
"plist": "3.0.4",
|
"plist": "3.0.6",
|
||||||
"pngjs": "6.0.0",
|
"pngjs": "6.0.0",
|
||||||
"run-series": "1.1.9",
|
"run-series": "1.1.9",
|
||||||
"spectron": "15.0.0",
|
"spectron": "19.0.0",
|
||||||
"standard": "16.0.4",
|
"standard": "17.0.0",
|
||||||
"tape": "5.3.1"
|
"tape": "5.6.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.0.0",
|
"node": "^16.0.0 || ^18.0.0",
|
||||||
"npm": "^7.10.0 || ^8.0.0"
|
"npm": "^7.10.0 || ^8.0.0"
|
||||||
},
|
},
|
||||||
"homepage": "https://webtorrent.io",
|
"homepage": "https://webtorrent.io",
|
||||||
@@ -113,10 +113,12 @@
|
|||||||
"clean": "node ./bin/clean.js",
|
"clean": "node ./bin/clean.js",
|
||||||
"gh-release": "gh-release",
|
"gh-release": "gh-release",
|
||||||
"install-system-deps": "brew install fakeroot dpkg rpm",
|
"install-system-deps": "brew install fakeroot dpkg rpm",
|
||||||
|
"lint": "standard",
|
||||||
|
"lint:fix": "standard --fix",
|
||||||
"open-config": "node ./bin/open-config.js",
|
"open-config": "node ./bin/open-config.js",
|
||||||
"package": "node ./bin/package.js",
|
"package": "node ./bin/package.js",
|
||||||
"start": "npm run build && electron --no-sandbox .",
|
"start": "npm run build && electron --no-sandbox .",
|
||||||
"test": "standard && depcheck --ignores=standard,@babel/eslint-parser --ignore-dirs=build,dist",
|
"test": "npm run lint && depcheck --ignores=standard,@babel/eslint-parser --ignore-dirs=build,dist",
|
||||||
"test-integration": "npm run build && node ./test",
|
"test-integration": "npm run build && node ./test",
|
||||||
"update-authors": "./bin/update-authors.sh",
|
"update-authors": "./bin/update-authors.sh",
|
||||||
"watch": "nodemon --exec \"npm run start\" --ext js,css --ignore build/ --ignore dist/"
|
"watch": "nodemon --exec \"npm run start\" --ext js,css --ignore build/ --ignore dist/"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ module.exports = class DeleteAllTorrentsModal extends React.Component {
|
|||||||
<p><strong>{message}</strong></p>
|
<p><strong>{message}</strong></p>
|
||||||
<ModalOKCancel
|
<ModalOKCancel
|
||||||
cancelText='CANCEL'
|
cancelText='CANCEL'
|
||||||
|
color='secondary'
|
||||||
onCancel={dispatcher('exitModal')}
|
onCancel={dispatcher('exitModal')}
|
||||||
okText={buttonText}
|
okText={buttonText}
|
||||||
onOK={handleRemove}
|
onOK={handleRemove}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Header extends React.Component {
|
|||||||
onMouseMove={dispatcher('mediaMouseMoved')}
|
onMouseMove={dispatcher('mediaMouseMoved')}
|
||||||
onMouseEnter={dispatcher('mediaControlsMouseEnter')}
|
onMouseEnter={dispatcher('mediaControlsMouseEnter')}
|
||||||
onMouseLeave={dispatcher('mediaControlsMouseLeave')}
|
onMouseLeave={dispatcher('mediaControlsMouseLeave')}
|
||||||
|
role='navigation'
|
||||||
>
|
>
|
||||||
{this.getTitle()}
|
{this.getTitle()}
|
||||||
<div className='nav left float-left'>
|
<div className='nav left float-left'>
|
||||||
@@ -18,6 +19,9 @@ class Header extends React.Component {
|
|||||||
className={'icon back ' + (loc.hasBack() ? '' : 'disabled')}
|
className={'icon back ' + (loc.hasBack() ? '' : 'disabled')}
|
||||||
title='Back'
|
title='Back'
|
||||||
onClick={dispatcher('back')}
|
onClick={dispatcher('back')}
|
||||||
|
role='button'
|
||||||
|
aria-disabled={!loc.hasBack()}
|
||||||
|
aria-label='Back'
|
||||||
>
|
>
|
||||||
chevron_left
|
chevron_left
|
||||||
</i>
|
</i>
|
||||||
@@ -25,6 +29,9 @@ class Header extends React.Component {
|
|||||||
className={'icon forward ' + (loc.hasForward() ? '' : 'disabled')}
|
className={'icon forward ' + (loc.hasForward() ? '' : 'disabled')}
|
||||||
title='Forward'
|
title='Forward'
|
||||||
onClick={dispatcher('forward')}
|
onClick={dispatcher('forward')}
|
||||||
|
role='button'
|
||||||
|
aria-disabled={!loc.hasForward()}
|
||||||
|
aria-label='Forward'
|
||||||
>
|
>
|
||||||
chevron_right
|
chevron_right
|
||||||
</i>
|
</i>
|
||||||
@@ -50,6 +57,7 @@ class Header extends React.Component {
|
|||||||
className='icon add'
|
className='icon add'
|
||||||
title='Add torrent'
|
title='Add torrent'
|
||||||
onClick={dispatcher('openFiles')}
|
onClick={dispatcher('openFiles')}
|
||||||
|
role='button'
|
||||||
>
|
>
|
||||||
add
|
add
|
||||||
</i>
|
</i>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
|
||||||
const colors = require('material-ui/styles/colors')
|
const grey = require('@material-ui/core/colors/grey').default
|
||||||
|
|
||||||
class Heading extends React.Component {
|
class Heading extends React.Component {
|
||||||
static get propTypes () {
|
static get propTypes () {
|
||||||
@@ -19,7 +19,7 @@ class Heading extends React.Component {
|
|||||||
render () {
|
render () {
|
||||||
const HeadingTag = 'h' + this.props.level
|
const HeadingTag = 'h' + this.props.level
|
||||||
const style = {
|
const style = {
|
||||||
color: colors.grey100,
|
color: grey['100'],
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
marginBottom: 15,
|
marginBottom: 15,
|
||||||
marginTop: 30
|
marginTop: 30
|
||||||
|
|||||||
@@ -1,26 +1,28 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const FlatButton = require('material-ui/FlatButton').default
|
const Button = require('@material-ui/core/Button').default
|
||||||
const RaisedButton = require('material-ui/RaisedButton').default
|
|
||||||
|
|
||||||
module.exports = class ModalOKCancel extends React.Component {
|
module.exports = class ModalOKCancel extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
const cancelStyle = { marginRight: 10, color: 'black' }
|
const cancelStyle = { marginRight: 10, color: 'black' }
|
||||||
const { cancelText, onCancel, okText, onOK } = this.props
|
const { cancelText, color = 'primary', onCancel, okText, onOK } = this.props
|
||||||
return (
|
return (
|
||||||
<div className='float-right'>
|
<div className='float-right'>
|
||||||
<FlatButton
|
<Button
|
||||||
className='control cancel'
|
className='control cancel'
|
||||||
style={cancelStyle}
|
|
||||||
label={cancelText}
|
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
/>
|
style={cancelStyle}
|
||||||
<RaisedButton
|
>
|
||||||
className='control ok'
|
{cancelText}
|
||||||
primary
|
</Button>
|
||||||
label={okText}
|
<Button
|
||||||
onClick={onOK}
|
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
className='control ok'
|
||||||
|
onClick={onOK}
|
||||||
|
color={color}
|
||||||
|
variant='contained'
|
||||||
|
>
|
||||||
|
{okText}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const TextField = require('material-ui/TextField').default
|
const TextField = require('@material-ui/core/TextField').default
|
||||||
const { clipboard } = require('electron')
|
const { clipboard } = require('electron')
|
||||||
|
|
||||||
const ModalOKCancel = require('./modal-ok-cancel')
|
const ModalOKCancel = require('./modal-ok-cancel')
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const colors = require('material-ui/styles/colors')
|
|
||||||
const remote = require('@electron/remote')
|
const remote = require('@electron/remote')
|
||||||
const React = require('react')
|
const React = require('react')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
|
||||||
const RaisedButton = require('material-ui/RaisedButton').default
|
const Button = require('@material-ui/core/Button').default
|
||||||
const TextField = require('material-ui/TextField').default
|
const TextField = require('@material-ui/core/TextField').default
|
||||||
|
const grey = require('@material-ui/core/colors/grey').default
|
||||||
|
|
||||||
// Lets you pick a file or directory.
|
// Lets you pick a file or directory.
|
||||||
// Uses the system Open File dialog.
|
// Uses the system Open File dialog.
|
||||||
@@ -53,10 +53,8 @@ class PathSelector extends React.Component {
|
|||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap'
|
whiteSpace: 'nowrap'
|
||||||
}
|
}
|
||||||
const textareaStyle = {
|
|
||||||
color: colors.grey50
|
|
||||||
}
|
|
||||||
const textFieldStyle = {
|
const textFieldStyle = {
|
||||||
|
color: grey['50'],
|
||||||
flex: '1'
|
flex: '1'
|
||||||
}
|
}
|
||||||
const text = this.props.value || ''
|
const text = this.props.value || ''
|
||||||
@@ -70,13 +68,20 @@ class PathSelector extends React.Component {
|
|||||||
{this.props.title}:
|
{this.props.title}:
|
||||||
</div>
|
</div>
|
||||||
<TextField
|
<TextField
|
||||||
className='control' disabled id={id} value={text}
|
className='control'
|
||||||
inputStyle={textareaStyle} style={textFieldStyle}
|
disabled
|
||||||
|
id={id}
|
||||||
|
style={textFieldStyle}
|
||||||
|
value={text}
|
||||||
/>
|
/>
|
||||||
<RaisedButton
|
<Button
|
||||||
className='control' label='Change' onClick={this.handleClick}
|
className='control'
|
||||||
|
onClick={this.handleClick}
|
||||||
style={buttonStyle}
|
style={buttonStyle}
|
||||||
/>
|
variant='contained'
|
||||||
|
>
|
||||||
|
Change
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ module.exports = class RemoveTorrentModal extends React.Component {
|
|||||||
<p><strong>{message}</strong></p>
|
<p><strong>{message}</strong></p>
|
||||||
<ModalOKCancel
|
<ModalOKCancel
|
||||||
cancelText='CANCEL'
|
cancelText='CANCEL'
|
||||||
|
color='secondary'
|
||||||
onCancel={dispatcher('exitModal')}
|
onCancel={dispatcher('exitModal')}
|
||||||
okText={buttonText}
|
okText={buttonText}
|
||||||
onOK={handleRemove}
|
onOK={handleRemove}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
|
||||||
const RaisedButton = require('material-ui/RaisedButton').default
|
const Button = require('@material-ui/core/Button').default
|
||||||
|
|
||||||
class ShowMore extends React.Component {
|
class ShowMore extends React.Component {
|
||||||
static get propTypes () {
|
static get propTypes () {
|
||||||
@@ -42,11 +42,13 @@ class ShowMore extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className='show-more' style={this.props.style}>
|
<div className='show-more' style={this.props.style}>
|
||||||
{this.state.expanded ? this.props.children : null}
|
{this.state.expanded ? this.props.children : null}
|
||||||
<RaisedButton
|
<Button
|
||||||
className='control'
|
className='control'
|
||||||
onClick={this.handleClick}
|
onClick={this.handleClick}
|
||||||
label={label}
|
variant='contained'
|
||||||
/>
|
>
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,10 @@ module.exports = class TorrentListController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setGlobalTrackers (globalTrackers) {
|
||||||
|
ipcRenderer.send('wt-set-global-trackers', globalTrackers)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use torrentKey, not infoHash
|
// TODO: use torrentKey, not infoHash
|
||||||
toggleTorrent (infoHash) {
|
toggleTorrent (infoHash) {
|
||||||
const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ function chromecastPlayer () {
|
|||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Transfer-Encoding': 'chunked'
|
'Transfer-Encoding': 'chunked'
|
||||||
})
|
})
|
||||||
res.end(Buffer.from(selectedSubtitle.buffer.substr(21), 'base64'))
|
res.end(Buffer.from(selectedSubtitle.buffer.slice(21), 'base64'))
|
||||||
}).listen(0, () => {
|
}).listen(0, () => {
|
||||||
const port = ret.subServer.address().port
|
const port = ret.subServer.address().port
|
||||||
const subtitlesUrl = 'http://' + state.server.networkAddress + ':' + port + '/'
|
const subtitlesUrl = 'http://' + state.server.networkAddress + ':' + port + '/'
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const path = require('path')
|
|||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events')
|
||||||
|
|
||||||
const config = require('../../config')
|
const config = require('../../config')
|
||||||
|
const defaultAnnounceList = require('create-torrent').announceList.map((arr) => arr[0])
|
||||||
|
|
||||||
const SAVE_DEBOUNCE_INTERVAL = 1000
|
const SAVE_DEBOUNCE_INTERVAL = 1000
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ function getDefaultState () {
|
|||||||
getPlayingTorrentSummary,
|
getPlayingTorrentSummary,
|
||||||
getPlayingFileSummary,
|
getPlayingFileSummary,
|
||||||
getExternalPlayerName,
|
getExternalPlayerName,
|
||||||
|
getGlobalTrackers,
|
||||||
shouldHidePlayerControls
|
shouldHidePlayerControls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +131,8 @@ function setupStateSaved () {
|
|||||||
soundNotifications: true,
|
soundNotifications: true,
|
||||||
autoAddTorrents: false,
|
autoAddTorrents: false,
|
||||||
torrentsFolderPath: '',
|
torrentsFolderPath: '',
|
||||||
highestPlaybackPriority: true
|
highestPlaybackPriority: true,
|
||||||
|
globalTrackers: defaultAnnounceList
|
||||||
},
|
},
|
||||||
torrents: config.DEFAULT_TORRENTS.map(createTorrentObject),
|
torrents: config.DEFAULT_TORRENTS.map(createTorrentObject),
|
||||||
torrentsToResume: [],
|
torrentsToResume: [],
|
||||||
@@ -198,8 +201,15 @@ function shouldHidePlayerControls () {
|
|||||||
new Date().getTime() - this.playing.mouseStationarySince > 2000 &&
|
new Date().getTime() - this.playing.mouseStationarySince > 2000 &&
|
||||||
!this.playing.mouseInControls &&
|
!this.playing.mouseInControls &&
|
||||||
!this.playing.isPaused &&
|
!this.playing.isPaused &&
|
||||||
this.playing.location === 'local' &&
|
this.playing.location === 'local'
|
||||||
this.playing.playbackRate === 1
|
}
|
||||||
|
|
||||||
|
function getGlobalTrackers () {
|
||||||
|
const trackers = this.saved.prefs.globalTrackers
|
||||||
|
if (!trackers) {
|
||||||
|
return defaultAnnounceList
|
||||||
|
}
|
||||||
|
return trackers
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load (cb) {
|
async function load (cb) {
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ function onState (err, _state) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Give global trackers
|
||||||
|
setGlobalTrackers()
|
||||||
|
|
||||||
// Restart everything we were torrenting last time the app ran
|
// Restart everything we were torrenting last time the app ran
|
||||||
resumeTorrents()
|
resumeTorrents()
|
||||||
|
|
||||||
@@ -314,6 +317,7 @@ const dispatchHandlers = {
|
|||||||
preferences: () => controllers.prefs().show(),
|
preferences: () => controllers.prefs().show(),
|
||||||
updatePreferences: (key, value) => controllers.prefs().update(key, value),
|
updatePreferences: (key, value) => controllers.prefs().update(key, value),
|
||||||
checkDownloadPath,
|
checkDownloadPath,
|
||||||
|
updateGlobalTrackers: (trackers) => setGlobalTrackers(trackers),
|
||||||
startFolderWatcher: () => controllers.folderWatcher().start(),
|
startFolderWatcher: () => controllers.folderWatcher().start(),
|
||||||
stopFolderWatcher: () => controllers.folderWatcher().stop(),
|
stopFolderWatcher: () => controllers.folderWatcher().stop(),
|
||||||
|
|
||||||
@@ -416,6 +420,10 @@ function escapeBack () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setGlobalTrackers () {
|
||||||
|
controllers.torrentList().setGlobalTrackers(state.getGlobalTrackers())
|
||||||
|
}
|
||||||
|
|
||||||
// Starts all torrents that aren't paused on program startup
|
// Starts all torrents that aren't paused on program startup
|
||||||
function resumeTorrents () {
|
function resumeTorrents () {
|
||||||
state.saved.torrents
|
state.saved.torrents
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
const colors = require('material-ui/styles/colors')
|
|
||||||
const createGetter = require('fn-getter')
|
const createGetter = require('fn-getter')
|
||||||
const React = require('react')
|
const React = require('react')
|
||||||
|
|
||||||
const darkBaseTheme = require('material-ui/styles/baseThemes/darkBaseTheme').default
|
const { ThemeProvider, createTheme } = require('@material-ui/core/styles')
|
||||||
const getMuiTheme = require('material-ui/styles/getMuiTheme').default
|
const grey = require('@material-ui/core/colors/grey').default
|
||||||
const MuiThemeProvider = require('material-ui/styles/MuiThemeProvider').default
|
const red = require('@material-ui/core/colors/red').default
|
||||||
|
|
||||||
const Header = require('../components/header')
|
const Header = require('../components/header')
|
||||||
|
|
||||||
@@ -33,17 +32,8 @@ const fontFamily = process.platform === 'win32'
|
|||||||
? '"Segoe UI", sans-serif'
|
? '"Segoe UI", sans-serif'
|
||||||
: 'BlinkMacSystemFont, "Helvetica Neue", Helvetica, sans-serif'
|
: 'BlinkMacSystemFont, "Helvetica Neue", Helvetica, sans-serif'
|
||||||
|
|
||||||
darkBaseTheme.fontFamily = fontFamily
|
let darkTheme
|
||||||
darkBaseTheme.userAgent = false
|
let lightTheme
|
||||||
darkBaseTheme.palette.primary1Color = colors.grey50
|
|
||||||
darkBaseTheme.palette.primary2Color = colors.grey50
|
|
||||||
darkBaseTheme.palette.primary3Color = colors.grey600
|
|
||||||
darkBaseTheme.palette.accent1Color = colors.redA200
|
|
||||||
darkBaseTheme.palette.accent2Color = colors.redA400
|
|
||||||
darkBaseTheme.palette.accent3Color = colors.redA100
|
|
||||||
|
|
||||||
let darkMuiTheme
|
|
||||||
let lightMuiTheme
|
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
@@ -64,19 +54,66 @@ class App extends React.Component {
|
|||||||
if (state.window.isFocused) cls.push('is-focused')
|
if (state.window.isFocused) cls.push('is-focused')
|
||||||
if (hideControls) cls.push('hide-video-controls')
|
if (hideControls) cls.push('hide-video-controls')
|
||||||
|
|
||||||
if (!darkMuiTheme) {
|
if (!darkTheme) {
|
||||||
darkMuiTheme = getMuiTheme(darkBaseTheme)
|
darkTheme = createTheme({
|
||||||
|
overrides: {
|
||||||
|
MuiButton: {
|
||||||
|
contained: {
|
||||||
|
backgroundColor: '#303030',
|
||||||
|
color: 'white',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#414141',
|
||||||
|
// Reset on touch devices, it doesn't add specificity
|
||||||
|
'@media (hover: none)': {
|
||||||
|
backgroundColor: '#303030',
|
||||||
|
color: 'white'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiCheckbox: {
|
||||||
|
root: {
|
||||||
|
padding: '0px',
|
||||||
|
marginRight: '16px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiFormControlLabel: {
|
||||||
|
label: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: '0.875rem'
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
marginLeft: '0px',
|
||||||
|
marginRight: '0px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: grey['50']
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: grey['50']
|
||||||
|
},
|
||||||
|
type: 'dark'
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
userAgent: false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiThemeProvider muiTheme={darkMuiTheme}>
|
<ThemeProvider theme={darkTheme}>
|
||||||
<div className={'app ' + cls.join(' ')}>
|
<div className={'app ' + cls.join(' ')}>
|
||||||
<Header state={state} />
|
<Header state={state} />
|
||||||
{this.getErrorPopover()}
|
{this.getErrorPopover()}
|
||||||
<div key='content' className='content'>{this.getView()}</div>
|
<div key='content' className='content'>{this.getView()}</div>
|
||||||
{this.getModal()}
|
{this.getModal()}
|
||||||
</div>
|
</div>
|
||||||
</MuiThemeProvider>
|
</ThemeProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,23 +139,32 @@ class App extends React.Component {
|
|||||||
const state = this.props.state
|
const state = this.props.state
|
||||||
if (!state.modal) return
|
if (!state.modal) return
|
||||||
|
|
||||||
if (!lightMuiTheme) {
|
if (!lightTheme) {
|
||||||
const lightBaseTheme = require('material-ui/styles/baseThemes/lightBaseTheme').default
|
lightTheme = createTheme({
|
||||||
lightBaseTheme.fontFamily = fontFamily
|
palette: {
|
||||||
lightBaseTheme.userAgent = false
|
secondary: {
|
||||||
lightMuiTheme = getMuiTheme(lightBaseTheme)
|
main: red.A200
|
||||||
|
},
|
||||||
|
type: 'light'
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
userAgent: false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalContents = Modals[state.modal.id]()
|
const ModalContents = Modals[state.modal.id]()
|
||||||
return (
|
return (
|
||||||
<MuiThemeProvider muiTheme={lightMuiTheme}>
|
<ThemeProvider theme={lightTheme}>
|
||||||
<div key='modal' className='modal'>
|
<div key='modal' className='modal'>
|
||||||
<div key='modal-background' className='modal-background' />
|
<div key='modal-background' className='modal-background' />
|
||||||
<div key='modal-content' className='modal-content'>
|
<div key='modal-content' className='modal-content'>
|
||||||
<ModalContents state={state} />
|
<ModalContents state={state} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MuiThemeProvider>
|
</ThemeProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,17 +3,16 @@ const path = require('path')
|
|||||||
const prettyBytes = require('prettier-bytes')
|
const prettyBytes = require('prettier-bytes')
|
||||||
const React = require('react')
|
const React = require('react')
|
||||||
|
|
||||||
const { dispatch, dispatcher } = require('../lib/dispatcher')
|
const Button = require('@material-ui/core/Button').default
|
||||||
|
const TextField = require('@material-ui/core/TextField').default
|
||||||
const FlatButton = require('material-ui/FlatButton').default
|
const Checkbox = require('@material-ui/core/Checkbox').default
|
||||||
const RaisedButton = require('material-ui/RaisedButton').default
|
|
||||||
const TextField = require('material-ui/TextField').default
|
|
||||||
const Checkbox = require('material-ui/Checkbox').default
|
|
||||||
|
|
||||||
const CreateTorrentErrorPage = require('../components/create-torrent-error-page')
|
const CreateTorrentErrorPage = require('../components/create-torrent-error-page')
|
||||||
const Heading = require('../components/heading')
|
const Heading = require('../components/heading')
|
||||||
const ShowMore = require('../components/show-more')
|
const ShowMore = require('../components/show-more')
|
||||||
|
|
||||||
|
const { dispatch, dispatcher } = require('../lib/dispatcher')
|
||||||
|
|
||||||
// Shows a basic UI to create a torrent, from an already-selected file or folder.
|
// Shows a basic UI to create a torrent, from an already-selected file or folder.
|
||||||
// Includes a "Show Advanced..." button and more advanced UI.
|
// Includes a "Show Advanced..." button and more advanced UI.
|
||||||
class CreateTorrentPage extends React.Component {
|
class CreateTorrentPage extends React.Component {
|
||||||
@@ -99,20 +98,23 @@ class CreateTorrentPage extends React.Component {
|
|||||||
{this.renderAdvanced()}
|
{this.renderAdvanced()}
|
||||||
</ShowMore>
|
</ShowMore>
|
||||||
<div className='float-right'>
|
<div className='float-right'>
|
||||||
<FlatButton
|
<Button
|
||||||
className='control cancel'
|
className='control cancel'
|
||||||
label='Cancel'
|
onClick={dispatcher('cancel')}
|
||||||
style={{
|
style={{
|
||||||
marginRight: 10
|
marginRight: 10
|
||||||
}}
|
}}
|
||||||
onClick={dispatcher('cancel')}
|
>
|
||||||
/>
|
Cancel
|
||||||
<RaisedButton
|
</Button>
|
||||||
|
<Button
|
||||||
className='control create-torrent-button'
|
className='control create-torrent-button'
|
||||||
label='Create Torrent'
|
|
||||||
primary
|
|
||||||
onClick={this.handleSubmit}
|
onClick={this.handleSubmit}
|
||||||
/>
|
color='primary'
|
||||||
|
variant='contained'
|
||||||
|
>
|
||||||
|
Create Torrent
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -134,10 +136,6 @@ class CreateTorrentPage extends React.Component {
|
|||||||
fileElems.push(<div key='more'>+ {files.length - maxFileElems} more</div>)
|
fileElems.push(<div key='more'>+ {files.length - maxFileElems} more</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align the text fields
|
|
||||||
const textFieldStyle = { width: '' }
|
|
||||||
const textareaStyle = { margin: 0 }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key='advanced' className='create-torrent-advanced'>
|
<div key='advanced' className='create-torrent-advanced'>
|
||||||
<div key='private' className='torrent-attribute'>
|
<div key='private' className='torrent-attribute'>
|
||||||
@@ -146,34 +144,32 @@ class CreateTorrentPage extends React.Component {
|
|||||||
className='torrent-is-private control'
|
className='torrent-is-private control'
|
||||||
style={{ display: '' }}
|
style={{ display: '' }}
|
||||||
checked={this.state.isPrivate}
|
checked={this.state.isPrivate}
|
||||||
onCheck={this.handleSetIsPrivate}
|
onChange={this.handleSetIsPrivate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div key='trackers' className='torrent-attribute'>
|
<div key='trackers' className='torrent-attribute'>
|
||||||
<label>Trackers:</label>
|
<label>Trackers:</label>
|
||||||
<TextField
|
<TextField
|
||||||
className='torrent-trackers control'
|
className='torrent-trackers control'
|
||||||
style={textFieldStyle}
|
fullWidth
|
||||||
textareaStyle={textareaStyle}
|
maxRows={10}
|
||||||
multiLine
|
minRows={2}
|
||||||
rows={2}
|
multiline
|
||||||
rowsMax={10}
|
|
||||||
value={this.state.trackers}
|
|
||||||
onChange={this.handleSetTrackers}
|
onChange={this.handleSetTrackers}
|
||||||
|
value={this.state.trackers}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div key='comment' className='torrent-attribute'>
|
<div key='comment' className='torrent-attribute'>
|
||||||
<label>Comment:</label>
|
<label>Comment:</label>
|
||||||
<TextField
|
<TextField
|
||||||
className='torrent-comment control'
|
className='torrent-comment control'
|
||||||
style={textFieldStyle}
|
fullWidth
|
||||||
textareaStyle={textareaStyle}
|
maxRows={10}
|
||||||
hintText='Optionally describe your torrent...'
|
minRows={2}
|
||||||
multiLine
|
multiline
|
||||||
rows={2}
|
|
||||||
rowsMax={10}
|
|
||||||
value={this.state.comment}
|
|
||||||
onChange={this.handleSetComment}
|
onChange={this.handleSetComment}
|
||||||
|
placeholder='Optionally describe your torrent...'
|
||||||
|
value={this.state.comment}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div key='files' className='torrent-attribute'>
|
<div key='files' className='torrent-attribute'>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* globals MediaMetadata */
|
||||||
|
|
||||||
const React = require('react')
|
const React = require('react')
|
||||||
const BitField = require('bitfield').default
|
const BitField = require('bitfield').default
|
||||||
const prettyBytes = require('prettier-bytes')
|
const prettyBytes = require('prettier-bytes')
|
||||||
@@ -35,6 +37,7 @@ module.exports = class Player extends React.Component {
|
|||||||
tag.pause()
|
tag.pause()
|
||||||
tag.src = ''
|
tag.src = ''
|
||||||
tag.load()
|
tag.load()
|
||||||
|
navigator.mediaSession.metadata = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +54,28 @@ function renderMedia (state) {
|
|||||||
// Get the <video> or <audio> tag
|
// Get the <video> or <audio> tag
|
||||||
const mediaElement = document.querySelector(state.playing.type)
|
const mediaElement = document.querySelector(state.playing.type)
|
||||||
if (mediaElement !== null) {
|
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) {
|
if (state.playing.isPaused && !mediaElement.paused) {
|
||||||
mediaElement.pause()
|
mediaElement.pause()
|
||||||
} else if (!state.playing.isPaused && mediaElement.paused) {
|
} else if (!state.playing.isPaused && mediaElement.paused) {
|
||||||
@@ -610,6 +635,8 @@ function renderPlayerControls (state) {
|
|||||||
key='skip-previous'
|
key='skip-previous'
|
||||||
className={'icon skip-previous float-left ' + prevClass}
|
className={'icon skip-previous float-left ' + prevClass}
|
||||||
onClick={dispatcher('previousTrack')}
|
onClick={dispatcher('previousTrack')}
|
||||||
|
role='button'
|
||||||
|
aria-label='Previous track'
|
||||||
>
|
>
|
||||||
skip_previous
|
skip_previous
|
||||||
</i>,
|
</i>,
|
||||||
@@ -618,6 +645,8 @@ function renderPlayerControls (state) {
|
|||||||
key='play'
|
key='play'
|
||||||
className='icon play-pause float-left'
|
className='icon play-pause float-left'
|
||||||
onClick={dispatcher('playPause')}
|
onClick={dispatcher('playPause')}
|
||||||
|
role='button'
|
||||||
|
aria-label={state.playing.isPaused ? 'Play' : 'Pause'}
|
||||||
>
|
>
|
||||||
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
||||||
</i>,
|
</i>,
|
||||||
@@ -626,6 +655,8 @@ function renderPlayerControls (state) {
|
|||||||
key='skip-next'
|
key='skip-next'
|
||||||
className={'icon skip-next float-left ' + nextClass}
|
className={'icon skip-next float-left ' + nextClass}
|
||||||
onClick={dispatcher('nextTrack')}
|
onClick={dispatcher('nextTrack')}
|
||||||
|
role='button'
|
||||||
|
aria-label='Next track'
|
||||||
>
|
>
|
||||||
skip_next
|
skip_next
|
||||||
</i>,
|
</i>,
|
||||||
@@ -634,6 +665,8 @@ function renderPlayerControls (state) {
|
|||||||
key='fullscreen'
|
key='fullscreen'
|
||||||
className='icon fullscreen float-right'
|
className='icon fullscreen float-right'
|
||||||
onClick={dispatcher('toggleFullScreen')}
|
onClick={dispatcher('toggleFullScreen')}
|
||||||
|
role='button'
|
||||||
|
aria-label={state.window.isFullScreen ? 'Exit full screen' : 'Enter full screen'}
|
||||||
>
|
>
|
||||||
{state.window.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}
|
{state.window.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}
|
||||||
</i>
|
</i>
|
||||||
@@ -646,6 +679,8 @@ function renderPlayerControls (state) {
|
|||||||
key='subtitles'
|
key='subtitles'
|
||||||
className={'icon closed-caption float-right ' + captionsClass}
|
className={'icon closed-caption float-right ' + captionsClass}
|
||||||
onClick={handleSubtitles}
|
onClick={handleSubtitles}
|
||||||
|
role='button'
|
||||||
|
aria-label='Closed captions'
|
||||||
>
|
>
|
||||||
closed_caption
|
closed_caption
|
||||||
</i>
|
</i>
|
||||||
@@ -727,6 +762,8 @@ function renderPlayerControls (state) {
|
|||||||
<i
|
<i
|
||||||
className='icon volume-icon float-left'
|
className='icon volume-icon float-left'
|
||||||
onMouseDown={handleVolumeMute}
|
onMouseDown={handleVolumeMute}
|
||||||
|
role='button'
|
||||||
|
aria-label='Mute'
|
||||||
>
|
>
|
||||||
{volumeIcon}
|
{volumeIcon}
|
||||||
</i>
|
</i>
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
|
||||||
const colors = require('material-ui/styles/colors')
|
const Button = require('@material-ui/core/Button').default
|
||||||
const Checkbox = require('material-ui/Checkbox').default
|
const Checkbox = require('@material-ui/core/Checkbox').default
|
||||||
const RaisedButton = require('material-ui/RaisedButton').default
|
const FormControlLabel = require('@material-ui/core/FormControlLabel').default
|
||||||
|
const TextField = require('@material-ui/core/TextField').default
|
||||||
|
const grey = require('@material-ui/core/colors/grey').default
|
||||||
|
|
||||||
const Heading = require('../components/heading')
|
const Heading = require('../components/heading')
|
||||||
const PathSelector = require('../components/path-selector')
|
const PathSelector = require('../components/path-selector')
|
||||||
|
|
||||||
@@ -28,6 +31,15 @@ class PreferencesPage extends React.Component {
|
|||||||
|
|
||||||
this.handleSoundNotificationsChange =
|
this.handleSoundNotificationsChange =
|
||||||
this.handleSoundNotificationsChange.bind(this)
|
this.handleSoundNotificationsChange.bind(this)
|
||||||
|
|
||||||
|
this.handleSetGlobalTrackers =
|
||||||
|
this.handleSetGlobalTrackers.bind(this)
|
||||||
|
|
||||||
|
const globalTrackers = this.props.state.getGlobalTrackers().join('\n')
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
globalTrackers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPathSelector () {
|
downloadPathSelector () {
|
||||||
@@ -53,11 +65,15 @@ class PreferencesPage extends React.Component {
|
|||||||
openExternalPlayerCheckbox () {
|
openExternalPlayerCheckbox () {
|
||||||
return (
|
return (
|
||||||
<Preference>
|
<Preference>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={!this.props.state.saved.prefs.openExternalPlayer}
|
checked={!this.props.state.saved.prefs.openExternalPlayer}
|
||||||
|
onChange={this.handleOpenExternalPlayerChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
label='Play torrent media files using WebTorrent'
|
label='Play torrent media files using WebTorrent'
|
||||||
onCheck={this.handleOpenExternalPlayerChange}
|
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
@@ -70,11 +86,15 @@ class PreferencesPage extends React.Component {
|
|||||||
highestPlaybackPriorityCheckbox () {
|
highestPlaybackPriorityCheckbox () {
|
||||||
return (
|
return (
|
||||||
<Preference>
|
<Preference>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.highestPlaybackPriority}
|
checked={this.props.state.saved.prefs.highestPlaybackPriority}
|
||||||
|
onChange={this.handleHighestPlaybackPriorityChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
label='Highest Playback Priority'
|
label='Highest Playback Priority'
|
||||||
onCheck={this.handleHighestPlaybackPriorityChange}
|
|
||||||
/>
|
/>
|
||||||
<p>Pauses all active torrents to allow playback to use all of the available bandwidth.</p>
|
<p>Pauses all active torrents to allow playback to use all of the available bandwidth.</p>
|
||||||
</Preference>
|
</Preference>
|
||||||
@@ -116,11 +136,15 @@ class PreferencesPage extends React.Component {
|
|||||||
autoAddTorrentsCheckbox () {
|
autoAddTorrentsCheckbox () {
|
||||||
return (
|
return (
|
||||||
<Preference>
|
<Preference>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.autoAddTorrents}
|
checked={this.props.state.saved.prefs.autoAddTorrents}
|
||||||
|
onChange={(e, value) => { this.handleAutoAddTorrentsChange(e, value) }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
label='Watch for new .torrent files and add them immediately'
|
label='Watch for new .torrent files and add them immediately'
|
||||||
onCheck={(e, value) => { this.handleAutoAddTorrentsChange(e, value) }}
|
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
@@ -178,11 +202,13 @@ class PreferencesPage extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Preference>
|
<Preference>
|
||||||
<p>WebTorrent is not currently the default torrent app.</p>
|
<p>WebTorrent is not currently the default torrent app.</p>
|
||||||
<RaisedButton
|
<Button
|
||||||
className='control'
|
className='control'
|
||||||
onClick={this.handleSetDefaultApp}
|
onClick={this.handleSetDefaultApp}
|
||||||
label='Make WebTorrent the default'
|
variant='contained'
|
||||||
/>
|
>
|
||||||
|
Make WebTorrent the default
|
||||||
|
</Button>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -198,11 +224,15 @@ class PreferencesPage extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Preference>
|
<Preference>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.startup}
|
checked={this.props.state.saved.prefs.startup}
|
||||||
|
onChange={this.handleStartupChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
label='Open WebTorrent on startup'
|
label='Open WebTorrent on startup'
|
||||||
onCheck={this.handleStartupChange}
|
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
@@ -211,11 +241,15 @@ class PreferencesPage extends React.Component {
|
|||||||
soundNotificationsCheckbox () {
|
soundNotificationsCheckbox () {
|
||||||
return (
|
return (
|
||||||
<Preference>
|
<Preference>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.soundNotifications}
|
checked={this.props.state.saved.prefs.soundNotifications}
|
||||||
|
onChange={this.handleSoundNotificationsChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
label='Enable sounds'
|
label='Enable sounds'
|
||||||
onCheck={this.handleSoundNotificationsChange}
|
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
@@ -229,9 +263,37 @@ class PreferencesPage extends React.Component {
|
|||||||
dispatch('updatePreferences', 'isFileHandler', true)
|
dispatch('updatePreferences', 'isFileHandler', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setGlobalTrackers () {
|
||||||
|
return (
|
||||||
|
<Preference>
|
||||||
|
<TextField
|
||||||
|
className='torrent-trackers control'
|
||||||
|
fullWidth
|
||||||
|
maxRows={10}
|
||||||
|
minRows={2}
|
||||||
|
multiline
|
||||||
|
onChange={this.handleSetGlobalTrackers}
|
||||||
|
value={this.state.globalTrackers}
|
||||||
|
/>
|
||||||
|
</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 () {
|
render () {
|
||||||
const style = {
|
const style = {
|
||||||
color: colors.grey400,
|
color: grey['400'],
|
||||||
marginLeft: 25,
|
marginLeft: 25,
|
||||||
marginRight: 25
|
marginRight: 25
|
||||||
}
|
}
|
||||||
@@ -254,6 +316,9 @@ class PreferencesPage extends React.Component {
|
|||||||
{this.setStartupCheckbox()}
|
{this.setStartupCheckbox()}
|
||||||
{this.soundNotificationsCheckbox()}
|
{this.soundNotificationsCheckbox()}
|
||||||
</PreferencesSection>
|
</PreferencesSection>
|
||||||
|
<PreferencesSection title='Trackers'>
|
||||||
|
{this.setGlobalTrackers()}
|
||||||
|
</PreferencesSection>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const prettyBytes = require('prettier-bytes')
|
const prettyBytes = require('prettier-bytes')
|
||||||
|
|
||||||
const Checkbox = require('material-ui/Checkbox').default
|
const Checkbox = require('@material-ui/core/Checkbox').default
|
||||||
const LinearProgress = require('material-ui/LinearProgress').default
|
const LinearProgress = require('@material-ui/core/LinearProgress').default
|
||||||
|
|
||||||
const TorrentSummary = require('../lib/torrent-summary')
|
const TorrentSummary = require('../lib/torrent-summary')
|
||||||
const TorrentPlayer = require('../lib/torrent-player')
|
const TorrentPlayer = require('../lib/torrent-player')
|
||||||
@@ -124,19 +124,19 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
const isActive = ['downloading', 'seeding'].includes(torrentSummary.status)
|
const isActive = ['downloading', 'seeding'].includes(torrentSummary.status)
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
key='download-button'
|
checked={isActive}
|
||||||
className={'control download ' + torrentSummary.status}
|
className={'control download ' + torrentSummary.status}
|
||||||
|
key='download-button'
|
||||||
|
onChange={dispatcher('toggleTorrent', infoHash)}
|
||||||
|
onClick={stopPropagation}
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
width: 32
|
marginRight: '12px',
|
||||||
|
'& .MuiSvgIconRoot': {
|
||||||
|
width: '20px',
|
||||||
|
height: '20px'
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
iconStyle={{
|
|
||||||
width: 20,
|
|
||||||
height: 20
|
|
||||||
}}
|
|
||||||
checked={isActive}
|
|
||||||
onClick={stopPropagation}
|
|
||||||
onCheck={dispatcher('toggleTorrent', infoHash)}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div key='progress-bar' style={styles.wrapper}>
|
<div key='progress-bar' style={styles.wrapper}>
|
||||||
<LinearProgress style={styles.progress} mode='determinate' value={progress} />
|
<LinearProgress style={styles.progress} value={progress} variant='determinate' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ console.time('init')
|
|||||||
|
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
const defaultAnnounceList = require('create-torrent').announceList
|
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const mm = require('music-metadata')
|
const mm = require('music-metadata')
|
||||||
@@ -16,11 +15,6 @@ const config = require('../config')
|
|||||||
const { TorrentKeyNotFoundError } = require('./lib/errors')
|
const { TorrentKeyNotFoundError } = require('./lib/errors')
|
||||||
const torrentPoster = require('./lib/torrent-poster')
|
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.
|
* WebTorrent version.
|
||||||
*/
|
*/
|
||||||
@@ -65,6 +59,8 @@ init()
|
|||||||
function init () {
|
function init () {
|
||||||
listenToClientEvents()
|
listenToClientEvents()
|
||||||
|
|
||||||
|
ipcRenderer.on('wt-set-global-trackers', (e, globalTrackers) =>
|
||||||
|
setGlobalTrackers(globalTrackers))
|
||||||
ipcRenderer.on('wt-start-torrenting', (e, torrentKey, torrentID, path, fileModtimes, selections) =>
|
ipcRenderer.on('wt-start-torrenting', (e, torrentKey, torrentID, path, fileModtimes, selections) =>
|
||||||
startTorrenting(torrentKey, torrentID, path, fileModtimes, selections))
|
startTorrenting(torrentKey, torrentID, path, fileModtimes, selections))
|
||||||
ipcRenderer.on('wt-stop-torrenting', (e, infoHash) =>
|
ipcRenderer.on('wt-stop-torrenting', (e, infoHash) =>
|
||||||
@@ -99,6 +95,11 @@ function listenToClientEvents () {
|
|||||||
client.on('error', (err) => ipcRenderer.send('wt-error', null, err.message))
|
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.
|
// Starts a given TorrentID, which can be an infohash, magnet URI, etc.
|
||||||
// Returns a WebTorrent object. See https://git.io/vik9M
|
// Returns a WebTorrent object. See https://git.io/vik9M
|
||||||
function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections) {
|
function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections) {
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ textarea,
|
|||||||
text-shadow: rgba(0, 0, 0, 0.5) 0 0 4px;
|
text-shadow: rgba(0, 0, 0, 0.5) 0 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.torrent .metadata span:not(:last-child)::after {
|
.torrent .metadata .ellipsis > span:not(:last-child):not(.control)::after {
|
||||||
content: ' • ';
|
content: ' • ';
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
|
|||||||
Reference in New Issue
Block a user