Compare commits

...

254 Commits

Author SHA1 Message Date
Julen Garcia Leunda
caab9c3b76 Enable uTP 2020-11-27 17:45:07 +01:00
Feross Aboukhadijeh
919af5bf15 Merge pull request #1217 from cezar-carneiro/show-progress-on-cast-screen 2020-11-26 01:44:32 +01:00
Feross Aboukhadijeh
d819acedd5 Merge pull request #1865 from BlueManCZ/patch-1 2020-11-25 22:33:25 +01:00
Feross Aboukhadijeh
54fcc5057b recursively update all deps 2020-11-24 12:02:08 -10:00
Feross Aboukhadijeh
cd5da2fe9b cross-zip@4 2020-11-24 12:00:00 -10:00
Feross Aboukhadijeh
1c79ffc720 bump deps; including electron ~11.0.3
Fixes: https://github.com/webtorrent/webtorrent-desktop/issues/1896
2020-11-24 11:56:17 -10:00
Feross Aboukhadijeh
a1a590fbba travis: disable cache
the cache keeps caching outdated versions which cause test failures
2020-11-22 16:32:36 -10:00
Feross Aboukhadijeh
606c02aef4 Remove extra-lint
- standard enforces 'let' and 'const' now
- I've never been a fan of the <100 chars per line rule since it violates the standard philosophy. it should be possible to write conformant code without needing a tool, so 'magic numbers' like 'no more than X lines/chars/statements' are not ideal
2020-11-22 16:29:59 -10:00
Feross Aboukhadijeh
4f68a8ad0b parse-torrent@9 2020-11-22 16:26:42 -10:00
Feross Aboukhadijeh
37d962fcf3 bump deps 2020-11-22 16:24:46 -10:00
Feross Aboukhadijeh
baf06461df Remove unused 'buble' dependency 2020-11-22 16:20:09 -10:00
Feross Aboukhadijeh
464e63fd92 standard (Fixes for PR #1818) 2020-11-22 16:12:04 -10:00
Feross Aboukhadijeh
2761e9c768 Merge pull request #1818 from surajrathod/master 2020-11-23 03:11:34 +01:00
suraj rathod
0efb5fa7ad Merge branch 'master' into master 2020-11-20 11:27:33 +05:30
Feross Aboukhadijeh
34947c355d standard@16 2020-11-18 12:38:20 -10:00
Feross Aboukhadijeh
958814f2ea use @babel/eslint-parser 2020-11-18 12:37:03 -10:00
Feross Aboukhadijeh
ec0c0c7870 Update package-lock.json 2020-11-18 12:30:13 -10:00
Feross Aboukhadijeh
ec0a1d1bb4 Merge pull request #1895 from webtorrent/electron11 2020-11-18 03:41:45 +01:00
Feross Aboukhadijeh
969d71afec Merge pull request #1698 from webtorrent/babel
Use babel instead of buble
2020-11-18 03:41:19 +01:00
Feross Aboukhadijeh
c1db01b936 Use babel instead of buble
This way we can target just the JSX tranformation. We don't use any other cutting edge JS features that require compilation, nor should we in the future.
2020-11-17 16:40:14 -10:00
Feross Aboukhadijeh
90670a4645 changelog: add link to security issue explanation 2020-11-17 15:42:11 -10:00
Feross Aboukhadijeh
b5fad54f4a Upgrade to Electron 11 2020-11-16 18:03:35 -10:00
Feross Aboukhadijeh
50718d3791 Merge pull request #1887 from webtorrent/fix_lintian_warnings
Fix lintian warnings
2020-11-09 22:58:14 +01:00
Julen Garcia Leunda
bd54a8c214 Fix lintian warnings 2020-11-06 17:13:22 +01:00
Feross Aboukhadijeh
0cd0edf4cc Merge pull request #1886 from webtorrent/throttling
Disable background throttling
2020-11-05 22:30:22 +01:00
Feross Aboukhadijeh
9e0d91f144 Disable background throttling
Reference: https://github.com/webtorrent/webtorrent-desktop/pull/1720#issuecomment-722011487

I actually think we want backgroundThrottling: false so our timers and intervals aren't throttled when the app is backgrounded.
2020-11-04 12:34:48 -10:00
Feross Aboukhadijeh
38d9c4c504 Merge pull request #1885 from webtorrent/bitfield
bitfield@4
2020-11-04 10:15:40 +01:00
Feross Aboukhadijeh
9e1721990d bitfield@4 2020-11-03 13:03:40 -10:00
Feross Aboukhadijeh
a20f82cc61 standard 2020-10-29 11:30:07 -10:00
Feross Aboukhadijeh
630ed76b8c standard 2020-10-28 09:52:07 -10:00
Feross Aboukhadijeh
1155cba4dd Merge pull request #1883 from webtorrent/deps 2020-10-28 19:18:16 +01:00
Feross Aboukhadijeh
2343181e1b Update package-lock.json 2020-10-28 08:15:53 -10:00
Feross Aboukhadijeh
9bb7330caa spectron@12 2020-10-28 08:14:10 -10:00
Feross Aboukhadijeh
3aae1614ea pngjs@6 2020-10-28 08:13:13 -10:00
Feross Aboukhadijeh
cdd308fc4a gh-release@4 2020-10-28 08:12:11 -10:00
Feross Aboukhadijeh
594d18e76e react 17 2020-10-28 08:11:10 -10:00
Feross Aboukhadijeh
50d772eb54 parse-torrent@8 2020-10-28 08:10:43 -10:00
Feross Aboukhadijeh
57ffb5e0c4 bump deps 2020-10-28 08:10:26 -10:00
Feross Aboukhadijeh
49ab4bd201 Merge pull request #1882 from webtorrent/render-deprecated 2020-10-28 19:07:03 +01:00
Feross Aboukhadijeh
7b06acb972 don't rely on deprecated return value from ReactDOM.render 2020-10-27 18:18:30 -10:00
Feross Aboukhadijeh
80b86b5693 standard 2020-10-21 13:50:42 -10:00
Diego Rodríguez Baquero
748b996522 Merge pull request #1875 from webtorrent/dependabot/npm_and_yarn/electron-10.1.2
Bump electron from 10.1.1 to 10.1.2
2020-10-20 10:51:26 -05:00
Julen Garcia Leunda
77877d4201 Merge pull request #1812 from dsernst/scrub-preview
Adds Youtube-style Scrubbing preview
2020-10-20 17:31:43 +02:00
dependabot[bot]
696fa4479c Bump electron from 10.1.1 to 10.1.2
Bumps [electron](https://github.com/electron/electron) from 10.1.1 to 10.1.2.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/master/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v10.1.1...v10.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-06 17:49:29 +00:00
Feross Aboukhadijeh
e0bb7562be Update package-lock.json 2020-09-03 11:36:21 -07:00
Feross Aboukhadijeh
8f20d9676b electron 10.1.1 2020-09-03 11:35:08 -07:00
BlueManCZ
b61a4e84f5 Remove Version entry 2020-08-29 14:19:36 +02:00
Ivo Šmerek
5def2d3947 Fix StartupWMClass 2020-08-29 13:53:02 +02:00
Feross Aboukhadijeh
ce6326a869 Update RELEASE_PROCESS.md 2020-08-28 17:58:07 -07:00
Feross Aboukhadijeh
7e56550887 Update RELEASE_PROCESS.md 2020-08-28 17:51:12 -07:00
Feross Aboukhadijeh
aa42627d45 0.24.0 2020-08-28 17:19:47 -07:00
Feross Aboukhadijeh
bd6dc1a7c1 authors 2020-08-28 17:19:20 -07:00
Feross Aboukhadijeh
dfedbcea32 add 0.24.0 changelog 2020-08-28 17:18:42 -07:00
Feross Aboukhadijeh
d930b97b30 Merge pull request #1864 from webtorrent/update 2020-08-28 17:14:58 -07:00
Feross Aboukhadijeh
de7899c8f8 Update package-lock.json 2020-08-28 17:06:51 -07:00
Feross Aboukhadijeh
2f53c5e137 bump electron deps 2020-08-28 17:03:33 -07:00
Feross Aboukhadijeh
ff54f48abb bump deps 2020-08-28 17:00:29 -07:00
Feross Aboukhadijeh
a7766e8d3f fixes for capture-frame@4 2020-08-28 16:58:40 -07:00
Feross Aboukhadijeh
844e34e596 capture-frame@4 2020-08-28 16:58:36 -07:00
Julen Garcia Leunda
8515fee681 Merge pull request #1859 from webtorrent/add_m2ts_video_container
Add m2ts video container support
2020-08-17 21:58:32 +02:00
Borewit
10a1ee3a09 Merge pull request #1861 from webtorrent/update-music-metadata
Update music-metadata to version 7.0.2
2020-08-17 19:26:32 +02:00
Borewit
a1b2641130 Update music-metadata to version 7.0.2 2020-08-16 08:48:37 +02:00
Julen Garcia Leunda
bb55b3fab2 Add m2ts video container support 2020-08-12 23:06:14 +02:00
Julen Garcia Leunda
57d02aa316 Merge pull request #1850 from Hinara/patch-1
Fix #1807 (VLC does not start)
2020-07-31 17:11:07 +02:00
David Ernst
d3bfccaa6b Check for type === video in clearPreview() 2020-07-30 19:10:14 -07:00
Julen Garcia Leunda
3a92f596ff Merge pull request #1838 from webtorrent/update-trackers
Update trackers to be consistent
2020-07-30 18:31:43 +02:00
Julen Garcia Leunda
60b4365a76 Merge pull request #1840 from subins2000/fix-1839-no-keyevents-on-user-input
Fix #1839: Prevent keypress events on user input elements
2020-07-30 18:31:22 +02:00
Julen Garcia Leunda
cb0ad73c80 Merge pull request #1754 from hicom150/fix_windows_installer
Fix windows installer event handler
2020-07-30 18:30:59 +02:00
Julen Garcia Leunda
9c865050bb Merge pull request #1847 from webtorrent/update-music-metadata
Update music metadata
2020-07-30 18:30:08 +02:00
Hinara
0edeaa4d58 Accept null value as playerPath 2020-07-30 15:06:26 +02:00
Mathias Rasmussen
dfd1ca3a8e Merge pull request #1841 from webtorrent/update_loading_gif
Update loading GIF
2020-07-30 03:59:49 +02:00
Borewit
75d9939b98 Update dependency music-metadata to version 7 2020-07-29 18:00:29 +02:00
Hinara
f88d5426c9 Fix #1807
eb5a291c8b/src/renderer/lib/migrations.js (L219) cause external player to be a empty string instead of a null one
2020-07-25 02:39:09 +02:00
Borewit
1b7d4f09a9 Fix issue #1833, only pass metadata. Prevent MetadataCollector (from music-metadata) is serialized. 2020-07-21 23:00:22 +02:00
Alex
680376c4a6 Update loading.gif 2020-07-17 21:14:15 +02:00
Subin Siby
15cca44bd2 Fix #1839: Prevent keypress events on user input elements 2020-07-17 18:47:23 +05:30
Feross Aboukhadijeh
29d17870cb Update trackers to be consistent
Updated all .torrent files to include:

```
  "announce": [
    "udp://tracker.leechers-paradise.org:6969",
    "udp://tracker.coppersurfer.tk:6969",
    "udp://tracker.opentrackr.org:1337",
    "udp://explodie.org:6969",
    "udp://tracker.empire-js.us:1337",
    "wss://tracker.btorrent.xyz",
    "wss://tracker.openwebtorrent.com"
  ]
```

Removed dead trackers from the list.
2020-07-16 20:18:15 -07:00
Feross Aboukhadijeh
c150d22c97 Update package-lock.json 2020-07-16 10:14:43 -07:00
Feross Aboukhadijeh
4e0c1ed393 Update CHANGELOG.md 2020-07-15 23:04:06 -07:00
Feross Aboukhadijeh
c6240c3253 Update CHANGELOG.md 2020-07-15 22:38:58 -07:00
Feross Aboukhadijeh
5deb0d7e9a Merge pull request #1835 from webtorrent/osx-notarize
Add macOS Notarization
2020-07-16 07:28:56 +02:00
Feross Aboukhadijeh
803cce808b Add macOS Notarization
Fixes: https://github.com/webtorrent/webtorrent-desktop/issues/1675
2020-07-15 22:26:29 -07:00
Feross Aboukhadijeh
8e89c0962b 0.23.0 2020-07-15 20:13:51 -07:00
Feross Aboukhadijeh
50cc394a27 Update CHANGELOG.md 2020-07-15 20:13:51 -07:00
Feross Aboukhadijeh
0165d541b8 update dep 2020-07-15 20:13:51 -07:00
Feross Aboukhadijeh
5af36428fa Merge pull request #1834 from webtorrent/electron10 2020-07-16 05:01:40 +02:00
Feross Aboukhadijeh
48ad571a59 electron 10: re-enable remote module
Electron 10 disables the remote module by default. We've always tried to avoid using `remote` in WTD so there aren't many occurrances of it, but there are still a few places where we use it
2020-07-15 20:01:08 -07:00
Feross Aboukhadijeh
57a003d7c5 electron 10 crash reporter changes
Crash reporter doesn't need to be started in child processes, and in fact the functions are all deprecated. Instead start it from the main process, and the child processes will automatically be covered

Change of params to crashReporter.start() function
2020-07-15 19:44:34 -07:00
Feross Aboukhadijeh
5f5b13d7fe update to electron 10.0.0-beta.11 2020-07-15 19:42:08 -07:00
Feross Aboukhadijeh
ed3f3f11f6 update tape, pngjs deps 2020-07-15 19:24:08 -07:00
Feross Aboukhadijeh
0572997a44 Update RELEASE_PROCESS.md 2020-07-15 19:15:47 -07:00
Feross Aboukhadijeh
4ce10859e7 0.22.0 changelog formatting 2020-07-15 18:17:03 -07:00
Feross Aboukhadijeh
eb5a291c8b Update RELEASE_PROCESS.md 2020-07-15 18:02:30 -07:00
Feross Aboukhadijeh
4b6394d0d5 0.22.0 2020-07-15 17:55:28 -07:00
Feross Aboukhadijeh
6b075ebe83 update integration tests to pass 2020-07-15 17:55:02 -07:00
Feross Aboukhadijeh
9b4dea29f4 lock spectron to 11.0.0
11.1.0 contains breaking changes. See: https://github.com/electron-userland/spectron/issues/647
2020-07-15 16:38:55 -07:00
Feross Aboukhadijeh
a2539b15d5 Prep for 0.22.0 release
Supercedes: https://github.com/webtorrent/webtorrent-desktop/pull/1730

Thanks @hicom150 :)
2020-07-15 15:39:39 -07:00
Feross Aboukhadijeh
a0da514f33 Update package.js 2020-07-15 15:22:01 -07:00
Feross Aboukhadijeh
ff5ae7a054 authors 2020-07-15 14:47:28 -07:00
Feross Aboukhadijeh
27bbdcc465 fixes for Electron 9 2020-07-15 14:35:03 -07:00
Feross Aboukhadijeh
1f19ed9a2d update electron to 9; update related deps 2020-07-15 14:34:27 -07:00
Feross Aboukhadijeh
06ce97bf6c Remove mkdirp
Fixes: https://github.com/webtorrent/webtorrent-desktop/issues/1831
2020-07-15 14:03:27 -07:00
Feross Aboukhadijeh
5c67a561c1 update easy deps
Update deps

from ~70 down to 34 vulnerabilities (33 low, 1 moderate)
2020-07-15 14:03:26 -07:00
Feross Aboukhadijeh
1ee49318fc Merge pull request #1830 from webtorrent/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-15 13:47:25 -07:00
dependabot[bot]
cc06379ce8 Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-15 20:38:26 +00:00
Feross Aboukhadijeh
66ac79c709 Merge pull request #1828 from webtorrent/dependabot/npm_and_yarn/electron-7.2.4 2020-07-15 13:37:32 -07:00
dependabot[bot]
ad252c5fc6 Bump electron from 7.1.0 to 7.2.4
Bumps [electron](https://github.com/electron/electron) from 7.1.0 to 7.2.4.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/master/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v7.1.0...v7.2.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-07 00:30:18 +00:00
SurajRathod
ab9f86d6c9 added .vscode ignore 2020-06-06 17:47:38 +05:30
SurajRathod
583cecc661 selective import 2020-06-06 17:46:30 +05:30
Feross Aboukhadijeh
3d66d32597 Merge pull request #1806 from LinusU/object-shorthand 2020-05-17 12:43:29 -07:00
Feross Aboukhadijeh
e4962fca52 Merge pull request #1776 from webtorrent/greenkeeper/cross-zip-3.0.0 2020-05-10 11:34:04 -07:00
David Ernst
c4b318bd5f Clean up code and add better comments 2020-05-02 11:40:00 -07:00
David Ernst
d55acf9c12 Fix 'extra-lint' errors 2020-05-01 22:41:19 -07:00
David Ernst
24bc40c95e Fix preview border rendering 2020-05-01 22:06:05 -07:00
David Ernst
0716444be5 Working video scrubbing preview 2020-05-01 21:57:42 -07:00
David Ernst
85c0e99e16 Only show previews for video 2020-05-01 21:05:29 -07:00
David Ernst
0b57961ff7 Basic placeholder UI for scrubbing preview 2020-05-01 19:43:47 -07:00
Linus Unnebäck
81b3d64f42 Use object shorthand for properties 2020-04-26 15:14:36 +01:00
Borewit
cf0cf79440 Merge pull request #1795 from webtorrent/greenkeeper/music-metadata-6.3.6
Greenkeeper/music metadata 6.3.6
2020-03-16 18:11:00 +01:00
greenkeeper[bot]
a8e6796002 chore(package): update lockfile package-lock.json 2020-03-11 07:37:52 +00:00
greenkeeper[bot]
f77aff6adf fix(package): update music-metadata to version 6.3.6
Closes #1774
2020-03-11 07:37:48 +00:00
Borewit
7fd028e5fa Merge pull request #1787 from dsernst/dynamic-copyright-year
Automatically keep the copyright year up-to-date
2020-02-09 14:15:31 +01:00
David Ernst
74f1be5452 Remove unnecessary parentheses 2020-02-08 12:37:48 -08:00
Borewit
77317aadc4 Merge pull request #1582 from dsernst/feature/sort-file-alphanumerically-1185
Context menu option to sort files by name
2020-02-08 12:01:55 +01:00
David Ernst
8eb2fb8d5d Automatically keep the copyright year up-to-date 2020-02-05 16:15:17 -08:00
David Ernst
58de27c484 Merge branch 'master' into feature/sort-file-alphanumerically-1185 2020-02-05 09:22:51 -08:00
David Ernst
185f5ec30b Remove unnecessary natsort dep 2020-02-05 09:17:58 -08:00
greenkeeper[bot]
351e890db5 chore(package): update lockfile package-lock.json 2020-01-16 00:28:55 +00:00
greenkeeper[bot]
6f2a00c785 chore(package): update cross-zip to version 3.0.0 2020-01-16 00:28:51 +00:00
Borewit
6f2aa86229 Merge pull request #1772 from webtorrent/greenkeeper/music-metadata-6.1.0
Update music metadata 6.1.0
2020-01-08 20:02:17 +01:00
Borewit
38aef81476 Add additional audio file extensions: MPEG-Layer-2, Musepack, Matroska audio, WavePack 2020-01-08 19:58:48 +01:00
Borewit
9dc3bb4f03 Pass FileInfo into music-metadata.parseStream() according API v6.
Update metadata if music-metadata parse method resolves.
2020-01-06 12:01:38 +01:00
Borewit
9291449737 Sync lock file 2020-01-06 11:01:04 +01:00
greenkeeper[bot]
98ee69d696 chore(package): update lockfile package-lock.json 2020-01-05 16:41:17 +00:00
greenkeeper[bot]
c5d20d56ec fix(package): update music-metadata to version 6.1.0
Closes #1749
2020-01-05 16:41:12 +00:00
Julen Garcia Leunda
e341367583 Merge pull request #1239 from SharonGrossman/feat/remove-all-torrents
feat(delete-all-torrents): added remove all torrents capability to the Transfers menu
2020-01-05 16:29:01 +01:00
Diego Rodríguez Baquero
f92a4c3e7d Merge pull request #1764 from hicom150/remove_deep_equal
Remove deep-equal dependency
2020-01-04 13:07:57 -05:00
Julen Garcia Leunda
5b894df71b fix lint errors 2019-12-19 18:34:35 +01:00
Julen Garcia Leunda
4577670fa8 Merge branch 'master' into feat/remove-all-torrents 2019-12-19 18:26:29 +01:00
Julen Garcia Leunda
6cac1f84ec Merge pull request #1757 from webtorrent/greenkeeper/semver-7.0.0
Update semver to the latest version 🚀
2019-12-19 17:46:05 +01:00
Julen Garcia Leunda
3c6b189ae6 Remove deep-equal dependency 2019-12-19 17:23:17 +01:00
greenkeeper[bot]
570145b2a4 chore(package): update lockfile package-lock.json 2019-12-14 20:06:27 +00:00
greenkeeper[bot]
95f2356b4c fix(package): update semver to version 7.0.0 2019-12-14 20:06:23 +00:00
Julen Garcia Leunda
97426621bf Fix windows installer event handler 2019-12-12 22:48:13 +01:00
Julen Garcia Leunda
3b7a9f9830 Merge pull request #1751 from hicom150/update_to_dialog_sync_functions
Fix deprecated dialog callback functions
2019-12-12 22:09:58 +01:00
Julen Garcia Leunda
61b92efcda Merge pull request #1746 from webtorrent/greenkeeper/application-config-2.0.0
Update application-config to the latest version 🚀
2019-12-06 17:17:25 +01:00
hicom150
b3026dbd87 Merge remote-tracking branch 'upstream/master' into update_application_config 2019-12-06 16:58:15 +01:00
hicom150
2eea86d8eb fix application-config update 2019-12-06 16:48:53 +01:00
Julen Garcia Leunda
46fb391d6c Merge pull request #1752 from hicom150/architectures
Show all supported architectures
2019-11-28 18:47:35 +01:00
Julen Garcia Leunda
79b3597637 Merge pull request #1740 from webtorrent/greenkeeper/electron-7.1.0
Update electron to the latest version 🚀
2019-11-28 17:23:45 +01:00
Julen Garcia Leunda
32dc268891 Merge pull request #1735 from akaustav/master
Fixed Material UI Getting Started link
2019-11-28 17:23:01 +01:00
Julen Garcia Leunda
02975e6b0e Merge branch 'master' into greenkeeper/electron-7.1.0 2019-11-28 17:21:23 +01:00
Julen Garcia Leunda
83dd5e35a7 Fix integration tests 2019-11-28 17:13:37 +01:00
Julen Garcia Leunda
1d6054f78b Merge pull request #1750 from webtorrent/greenkeeper/nodemon-2.0.0
Update nodemon to the latest version 🚀
2019-11-28 16:39:56 +01:00
Julen Garcia Leunda
8a947a2f80 Merge pull request #1748 from webtorrent/update-music-metadata
Update music-metadata to 4.9.2
2019-11-28 16:35:29 +01:00
Julen Garcia Leunda
6c22f5f595 show all supported architectures 2019-11-28 16:22:23 +01:00
Julen Garcia Leunda
bea86b2a67 Merge pull request #1743 from gpatarin/issue-1741-savetorrentas
Fix for issue #1741 (Save Torrent File As...)
2019-11-26 17:11:25 +01:00
Julen Garcia Leunda
82f873270e Merge pull request #1737 from akaustav/fix-about-window
Fix: Increase height of 'About' window
2019-11-26 17:01:50 +01:00
Julen Garcia Leunda
2b8fa8b6fe fix review comments 2019-11-26 16:59:10 +01:00
Julen Garcia Leunda
38390405dc Merge remote-tracking branch 'upstream/master' into fix-about-window 2019-11-26 16:55:44 +01:00
Gael Patarin
f30343b821 Added buttonLabel as Save in the save dialog 2019-11-26 14:33:47 +01:00
hicom150
d738021285 Fix deprecated dialog callback functions 2019-11-23 00:03:20 +01:00
greenkeeper[bot]
08e32dde7e chore(package): update lockfile package-lock.json 2019-11-20 16:03:51 +00:00
greenkeeper[bot]
229321c6c5 chore(package): update nodemon to version 2.0.0 2019-11-20 16:03:40 +00:00
Borewit
3b65f2a4a7 Update music-metadata to 4.9.2 2019-11-19 21:13:56 +01:00
Diego Rodríguez Baquero
93b0e42609 Merge pull request #1739 from webtorrent/greenkeeper/depcheck-0.9.0
Update depcheck to the latest version 🚀
2019-11-18 12:36:00 -05:00
Diego Rodríguez Baquero
633cdb4a82 Merge pull request #1742 from webtorrent/greenkeeper/languagedetect-2.0.0
Update languagedetect to the latest version 🚀
2019-11-18 12:33:47 -05:00
greenkeeper[bot]
eda0e0f964 chore(package): update lockfile package-lock.json 2019-11-16 18:01:35 +00:00
greenkeeper[bot]
a850cf6635 fix(package): update application-config to version 2.0.0 2019-11-16 18:01:31 +00:00
Feross Aboukhadijeh
af8b9cf1f2 Update drag-drop to the latest version 🚀 (#1744)
Update drag-drop to the latest version 🚀
2019-11-12 16:13:31 -08:00
greenkeeper[bot]
cc6cc41ad3 chore(package): update lockfile package-lock.json 2019-11-13 00:07:46 +00:00
greenkeeper[bot]
8228036936 fix(package): update drag-drop to version 6.0.0 2019-11-13 00:07:40 +00:00
gpatarin
600646b6ce Making the save file dialog sync to ensure working properly on MacOS and others 2019-11-09 23:58:43 +01:00
greenkeeper[bot]
fc73d2e6fd chore(package): update lockfile package-lock.json 2019-11-05 23:41:49 +00:00
greenkeeper[bot]
616cef87cb fix(package): update languagedetect to version 2.0.0 2019-11-05 23:41:45 +00:00
greenkeeper[bot]
fdc65d6e51 chore(package): update lockfile package-lock.json 2019-11-05 14:45:08 +00:00
greenkeeper[bot]
be922ef7c1 chore(package): update electron to version 7.1.0 2019-11-05 14:45:03 +00:00
greenkeeper[bot]
7dd5385f15 chore(package): update lockfile package-lock.json 2019-11-01 22:46:37 +00:00
greenkeeper[bot]
a5a199b63c chore(package): update depcheck to version 0.9.0 2019-11-01 22:46:32 +00:00
Ameet Kaustav
ab129fa233 Fix: Increase Height of 'About' window even more 2019-10-31 01:17:09 -07:00
Mathias Rasmussen
35717e9dfb Fix config copyright path in about window 2019-10-30 12:58:30 +01:00
Ameet Kaustav
a881668b38 Fix: Increase height of 'About' window 2019-10-29 22:28:07 -07:00
Ameet Kaustav
7e92647360 Fixed Material UI Getting Started link 2019-10-29 19:54:03 -07:00
Feross Aboukhadijeh
0198d7493d spectron@9 2019-10-23 13:23:34 -07:00
Feross Aboukhadijeh
04d9bc8752 Bump versions 2019-10-23 13:21:49 -07:00
Feross Aboukhadijeh
3e5fdcf6b9 Fixes for Electron 7 2019-10-23 13:19:24 -07:00
Feross Aboukhadijeh
d538a23ad0 Update electron to the latest version 🚀 (#1729)
Update electron to the latest version 🚀
2019-10-23 13:19:12 -07:00
Feross Aboukhadijeh
8de77e3d11 use org .github repo 2019-10-23 11:37:03 -07:00
greenkeeper[bot]
985def222e chore(package): update lockfile package-lock.json 2019-10-22 06:04:33 +00:00
greenkeeper[bot]
9bf4576a50 chore(package): update electron to version 7.0.0 2019-10-22 06:04:22 +00:00
Feross Aboukhadijeh
a5c41c8313 Update open to the latest version 🚀 (#1724)
Update open to the latest version 🚀
2019-10-19 12:56:42 -07:00
Julen Garcia Leunda
11d04d52c1 Merge pull request #1720 from webtorrent/type-issues
Fix a few type errors
2019-10-18 11:26:25 +02:00
greenkeeper[bot]
cb5af1a396 chore(package): update lockfile package-lock.json 2019-10-15 18:45:03 +00:00
greenkeeper[bot]
8a487cff9e chore(package): update open to version 7.0.0 2019-10-15 18:44:44 +00:00
Julen Garcia Leunda
45920e065e Merge pull request #1712 from hicom150/change_audio_tracks
Add support for multiple audio tracks
2019-10-13 22:54:59 +02:00
hicom150
2d7b6c01d0 Merge branch 'master' into change_audio_tracks 2019-10-13 22:38:50 +02:00
Julen Garcia Leunda
c33acd0746 Merge pull request #1711 from hicom150/fix_codec_unsupported_detection
Improve codec unsupported detection
2019-10-13 22:12:56 +02:00
hicom150
f2c531baa4 use videoTracks and audioTracks to check unsupported codecs 2019-10-12 17:44:13 +02:00
hicom150
287bcfd703 Merge branch 'master' into fix_codec_unsupported_detection 2019-10-11 16:56:34 +02:00
Mathias Rasmussen
e71555e664 Fix type errors 2019-10-09 19:34:30 +02:00
Borewit
bc921c889e Merge pull request #1719 from webtorrent/update-music-metadata
Update music-metadata to v4.8.0
2019-10-08 10:54:08 +02:00
Julen Garcia Leunda
59ebe132db Merge pull request #1707 from hicom150/no_sandbox
Add --no-sandbox option to desktop files
2019-10-07 22:57:04 +02:00
hicom150
b47d335e86 Merge branch 'fix_codec_unsupported_detection' of github.com:hicom150/webtorrent-desktop into fix_codec_unsupported_detection 2019-10-07 22:08:46 +02:00
hicom150
f5e186dc67 Apply review changes 2019-10-07 22:06:50 +02:00
hicom150
3d85803df9 Improve codec unsupported detection 2019-10-07 22:06:50 +02:00
Borewit
5c64fb5d35 Update music-metadata to v4.8.0 2019-10-07 20:01:19 +02:00
hicom150
5280fc76e9 Merge branch 'master' into fix_codec_unsupported_detection 2019-10-07 17:54:41 +02:00
hicom150
d4a8d9a120 Apply review changes 2019-10-07 17:54:36 +02:00
Feross Aboukhadijeh
3fbf33b8ae remove borewit from funding.yml (per his request) 2019-10-06 14:52:23 -07:00
hicom150
0d27223f16 Add support for multiple audio tracks 2019-10-06 22:10:35 +02:00
Feross Aboukhadijeh
2c5fcab469 Merge pull request #1717 from pR0Ps/feature/verification-status
Report when files are being verified
2019-10-06 11:04:35 -07:00
Carey Metcalfe
8fc7150559 Report when files are being verified
When starting a torrent that is partially-downloaded, WebTorrent will
now report "Verifying" as it verifies the existing data on disk.

Fixes #1586
2019-10-03 02:22:12 -04:00
Feross Aboukhadijeh
89b53ffe96 Merge pull request #1716 from pR0Ps/master
Floor individual file percentages for display
2019-10-01 06:49:42 -07:00
Feross Aboukhadijeh
e990bc898d mono is needed to create setup.exe (#1715)
mono is needed to create setup.exe
2019-09-30 21:49:09 -07:00
Feross Aboukhadijeh
cb699b5fec readme: clarify windows homebrew instructions 2019-09-30 21:48:56 -07:00
Lucas
8a235c31e0 mono is needed to create setup.exe 2019-10-01 11:05:53 +13:00
Carey Metcalfe
8ee27b8ef4 Floor individual file percentages for display
Fixes #1713
2019-09-26 20:49:17 -04:00
hicom150
5023651e63 Improve codec unsupported detection 2019-09-25 22:24:56 +02:00
Julen Garcia Leunda
f65fc68179 Add --no-sandbox option to desktop files 2019-09-19 22:41:34 +02:00
Feross Aboukhadijeh
b9bcf747de Set default externalPlayerPath (#1702)
Set default externalPlayerPath
2019-09-19 12:58:42 -07:00
Feross Aboukhadijeh
88e7167b6c Add rpm package creation support (#1694)
Add rpm package creation support
2019-09-19 12:56:14 -07:00
Pieter Goetschalckx
f5ab39be8e Migrate config file 2019-09-19 15:22:49 +02:00
Julen Garcia Leunda
6e69e5d36e Set correct architecture for RedHat based packages 2019-09-18 20:44:14 +02:00
Feross Aboukhadijeh
9c4ca25615 Handle null paths in path selector (#1704)
Handle null paths in path selector
2019-09-18 11:22:33 -07:00
Mathias Rasmussen
d15f40b22d handle null paths 2019-09-18 19:41:26 +02:00
Pieter Goetschalckx
1befac8d0e Set default externalPlayerPath 2019-09-18 13:34:39 +02:00
Julen Garcia Leunda
cfa1ebbea7 Merge branch 'master' into add_package_rpm 2019-09-16 22:13:41 +02:00
Feross Aboukhadijeh
2a679dd6e8 Add linux arm64 build (Fixes for PR #1650) (#1696)
Add linux arm64 build (Fixes for PR #1650)
2019-09-15 14:50:14 -07:00
Feross Aboukhadijeh
fce5f00925 Add buble compiler target chrome version (#1695)
Add buble compiler target chrome version
2019-09-15 12:36:14 -07:00
Feross Aboukhadijeh
39d04c4b2a Add linux arm64 build (Fixes for PR #1650) 2019-09-15 12:30:30 -07:00
Feross Aboukhadijeh
5688e4538c introduce linux arm64 support (#1650)
introduce linux arm64 support
2019-09-15 12:19:15 -07:00
Julen Garcia Leunda
4e18d4091a Add rpm package creation documentation 2019-09-15 20:30:41 +02:00
Julen Garcia Leunda
cfde3ee85d Add buble compiler target chrome version 2019-09-15 19:34:16 +02:00
Julen Garcia Leunda
1c343cb4c1 Add rpm package creation support 2019-09-15 19:16:03 +02:00
Дамјан Георгиевски
e3e490daa5 Merge branch 'master' into master 2019-09-15 18:25:43 +02:00
Feross Aboukhadijeh
d7783749ca Update test-add-torrent.js 2019-09-14 17:06:28 -07:00
Feross Aboukhadijeh
b07fc8285f 0.21.0 2019-09-14 16:44:47 -07:00
Feross Aboukhadijeh
6379356612 authors 2019-09-14 16:44:38 -07:00
Feross Aboukhadijeh
ee3768faf8 Merge branch 'fix-windows' 2019-09-14 16:42:56 -07:00
Feross Aboukhadijeh
8ff65412a3 readme: screenshots: 2018 MacBook Pro 13" 2019-09-14 16:42:40 -07:00
Feross Aboukhadijeh
cb930bef0b test: Update screenshots 2019-09-14 16:42:01 -07:00
Feross Aboukhadijeh
6a76554563 Fix "EPERM: operation not permitted, open 'C:\Users\account\App… (#1693)
Fix "EPERM: operation not permitted, open 'C:\Users\account\AppData\Local
2019-09-14 16:35:12 -07:00
Feross Aboukhadijeh
e72005e239 Remove cp-file, use copyFileSync instead 2019-09-14 16:32:38 -07:00
Дамјан Георгиевски
b8f7880a78 introduce linux arm64 support 2019-08-15 01:50:47 +02:00
David Ernst
aab918ff1a Fix lint error (Line >100 chars) 2019-05-06 16:23:50 -07:00
David Ernst
ca97413b76 Update package-lock.json for natsort 2019-05-06 16:00:23 -07:00
David Ernst
2466b2e0a6 Add context menu option to toggle Sort by Name 2019-05-04 22:39:27 -07:00
David Ernst
2dc2953831 Merge branch 'master' into feature/sort-file-alphanumerically-1185 2019-05-04 22:03:59 -07:00
Mathias Rasmussen
60862ec01d refactor torrent-list-controller 2018-10-08 01:52:21 +02:00
Sharon Grossman
b7fedb1983 feat(delete-all-torrents): added remove all torrents capability to the Transfers menu 2018-10-08 01:52:21 +02:00
Cezar Carneiro
ab41d55e4b fix ETA and reorganize 2017-08-02 22:52:45 -03:00
Cezar Carneiro
739e7a50f7 improve infos 2017-08-02 00:03:52 -03:00
Cezar Carneiro
64ff5ebfd5 show percentage, size, speed and peers 2017-07-31 22:47:53 -03:00
Egor Yurtaev
2aa2f0de19 Sort files alphanumerically #1185 2017-06-24 22:09:42 +06:00
105 changed files with 6567 additions and 4531 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +0,0 @@
github: feross
custom: https://paypal.me/borewit

View File

@@ -1,11 +0,0 @@
<!-- DO NOT POST LINKS OR REFERENCES TO COPYRIGHTED CONTENT IN YOUR ISSUE. -->
**What version of WebTorrent Desktop?** (See the 'About WebTorrent' menu)
**What operating system and version?**
**What did you do?**
**What did you expect to happen?**
**What actually happened?**

20
.github/ISSUE_TEMPLATE/BUG_REPORT.md vendored Normal file
View File

@@ -0,0 +1,20 @@
---
name: "🐞 Bug report"
about: Report an issue with this software
title: ''
labels: ''
assignees: ''
---
<!-- DO NOT POST LINKS OR REFERENCES TO COPYRIGHTED CONTENT IN YOUR ISSUE. -->
**What version of WebTorrent Desktop are you using?**
**What operating system and version?**
**What happened?**
**What did you expect to happen?**
**Are you willing to submit a pull request to fix this bug?**

View File

@@ -0,0 +1,20 @@
---
name: "⭐️ Feature request"
about: Request a new feature to be added
title: ''
labels: ''
assignees: ''
---
<!-- DO NOT POST LINKS OR REFERENCES TO COPYRIGHTED CONTENT IN YOUR ISSUE. -->
**What version of WebTorrent Desktop are you using?**
**What operating system and version?**
**What problem do you want to solve?**
**What do you think is the correct solution to this problem?**
**Are you willing to submit a pull request to implement this change?**

15
.github/config.yml vendored
View File

@@ -1,15 +0,0 @@
# ProBot Request Info (https://probot.github.io/apps/request-info/)
requestInfoReplyComment: >
👋 We would appreciate it if you could provide us with more information about this
issue. <br><br> ![](https://feross.net/s/cats/14.gif)
requestInfoLabelToAdd: 'need more info'
# ProBot Welcome (https://probot.github.io/apps/welcome/)
newPRWelcomeComment: >
🙌 Thanks for opening this pull request! You're awesome.
<br><br> ![](https://feross.net/s/cats/6.gif)
firstPRMergeComment: >
🎉 Congrats on getting your first pull request landed! <br><br>
![](https://feross.net/s/cats/29.gif)

4
.github/lock.yml vendored
View File

@@ -1,4 +0,0 @@
# ProBot Lock (https://probot.github.io/apps/lock/)
daysUntilLock: 365
lockComment: false

View File

@@ -1,9 +0,0 @@
# ProBot No Response (https://probot.github.io/apps/no-response/)
daysUntilClose: 14
responseRequiredLabel: 'need more info'
closeComment: >
This issue has been automatically closed because there was no response to a
request for more information from the issue opener. Please leave a comment or
open a new issue if you have additional information related to this issue.
<br><br> ![](https://feross.net/s/cats/7.gif)

17
.github/stale.yml vendored
View File

@@ -1,17 +0,0 @@
# ProBot Stale (https://probot.github.io/apps/stale/)
daysUntilStale: 90
daysUntilClose: 14
exemptLabels:
- accepted
- blocked
- bug
- enhancement
- greenkeeper
- 'help wanted'
- meta
staleLabel: stale
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
closeComment: false

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ node_modules/
build/
dist/
npm-debug.log*
.vscode/
# JetBrains IntelliJ IDEA project files
.idea

View File

@@ -1,3 +1,5 @@
language: node_js
node_js:
- lts/*
cache:
npm: false

View File

@@ -39,6 +39,7 @@
- Nuno Campos (nuno.campos@me.com)
- Ebrahim Byagowi (ebrahim@gnu.org)
- Josip Janzic (josip@jjanzic.com)
- Egor Yurtaev (yurtaev.egor@gmail.com)
- Emil Bay (github@tixz.dk)
- Borewit (borewit@users.noreply.github.com)
- greenkeeper[bot] (greenkeeper[bot]@users.noreply.github.com)
@@ -55,6 +56,7 @@
- Dan Flettre (flettre@gmail.com)
- Sibiraj (dev.sibiraj@outlook.com)
- clujin (clujin@gmail.com)
- Sharon Grossman (sharong1337@gmail.com)
- Linus Unnebäck (linus@folkdatorn.se)
- Adrian Tombu (adrian@otso.fr)
- Lucas (5874806+RecoX@users.noreply.github.com)
@@ -64,7 +66,18 @@
- Recox (5874806+RecoX@users.noreply.github.com)
- greenkeeper[bot] (23040076+greenkeeper[bot]@users.noreply.github.com)
- hicom150 (hicom150@gmail.com)
- Дамјан Георгиевски (gdamjan@gmail.com)
- Jimmy Wärting (jimmy@warting.se)
- Julen Garcia Leunda (hicom150@gmail.com)
- Feross (feross@feross.org)
- Daniele Debernardi (drebrez@gmail.com)
- Chandan Chowdary Bhagam (chandandharana@gmail.com)
- Pieter Goetschalckx (3.14.e.ter@gmail.com)
- Carey Metcalfe (carey@cmetcalfe.ca)
- Ameet Kaustav (akaustav@users.noreply.github.com)
- gpatarin (gael.patarin@outlook.com)
- Gael Patarin (gael.patarin@outlook.com)
- Subin Siby (mail@subinsb.com)
- Hinara (hinara.turevel@gmail.com)
#### Generated by bin/update-authors.sh.

View File

@@ -1,6 +1,64 @@
# WebTorrent Desktop Version History
## v0.21.0 - 2019-08
## v0.24.0 - 2020-08-28
### Added
- Support the `.m2ts` video container format ([hicom150](https://github.com/hicom150))
### Changed
- Update to Electron 10.1.0 [\#1864](https://github.com/webtorrent/webtorrent-desktop/pull/1864) ([feross](https://github.com/feross))
- Update the Windows installer loading image [\#1841](https://github.com/webtorrent/webtorrent-desktop/pull/1841) ([alxhotel](https://github.com/alxhotel))
### Fixed
- Fix music metadata not showing up [\#1847](https://github.com/webtorrent/webtorrent-desktop/pull/1847) ([Borewit](https://github.com/Borewit))
- Fix the "Play in VLC" functionality [\#1850](https://github.com/webtorrent/webtorrent-desktop/pull/1850) ([Hinara](https://github.com/Hinara))
- Prevent shortcuts from activating when user input elements are focused [\#1840](https://github.com/webtorrent/webtorrent-desktop/pull/1840) ([subins2000](https://github.com/subins2000))
## v0.23.0 - 2020-07-15
🔒 This release contains a critical security fix. Please update as soon as possible. [\#1837](https://github.com/webtorrent/webtorrent-desktop/issues/1837#issuecomment-729320901)
### Added
- Add macOS Notarization [\#1834](https://github.com/webtorrent/webtorrent-desktop/pull/1834) ([feross](https://github.com/feross))
### Changed
- Update to Electron 10 beta [\#1834](https://github.com/webtorrent/webtorrent-desktop/pull/1834) ([feross](https://github.com/feross))
## v0.22.0 - 2020-07-15
❤️✨ A new version of WebTorrent Desktop is out! ❤️✨
### Added
- Linux `.rpm` packages and `arm64` builds are now available! [\#1694](https://github.com/webtorrent/webtorrent-desktop/pull/1694) ([hicom150](https://github.com/hicom150))
- Add support for multiple audio tracks [\#1712](https://github.com/webtorrent/webtorrent-desktop/pull/1712) ([hicom150](https://github.com/hicom150))
- Improve codec unsupported detection [\#1711](https://github.com/webtorrent/webtorrent-desktop/pull/1711) ([hicom150](https://github.com/hicom150))
- Report when files are being verified [\#1717](https://github.com/webtorrent/webtorrent-desktop/pull/1717) ([pR0Ps](https://github.com/pR0Ps))
- Support additional audio files: MPEG-Layer-2, Musepack, Matroska audio, WavePack [\#1772](https://github.com/webtorrent/webtorrent-desktop/pull/1772)
### Changed
- Update to Electron 9 [\#1729](https://github.com/webtorrent/webtorrent-desktop/pull/1729) [\#1832](https://github.com/webtorrent/webtorrent-desktop/issues/1832)
- Update to music-metadata 4.8.0 [\#1719](https://github.com/webtorrent/webtorrent-desktop/pull/1719) ([Borewit](https://github.com/Borewit))
- Update Windows build documentation [\#1715](https://github.com/webtorrent/webtorrent-desktop/pull/1715) ([RecoX](https://github.com/RecoX))
- Remove unneeded dependencies ([feross](https://github.com/feross))
### Fixed
- Fix a few type errors [\#1720](https://github.com/webtorrent/webtorrent-desktop/pull/1720) ([mathiasvr](https://github.com/mathiasvr))
- Fix electron SUID sandbox error [\#1707](https://github.com/webtorrent/webtorrent-desktop/pull/1707) ([hicom150](https://github.com/hicom150))
- Fix percentage rounding error [\#1716](https://github.com/webtorrent/webtorrent-desktop/pull/1716) ([pR0Ps](https://github.com/pR0Ps))
- Fix path-selector in preferences page [\#1702](https://github.com/webtorrent/webtorrent-desktop/pull/1702) ([314eter](https://github.com/314eter))
- Fix path-selector in preferences page [\#1704](https://github.com/webtorrent/webtorrent-desktop/pull/1702) ([mathiasvr](https://github.com/mathiasvr))
- Fix: Increase height of 'About' window [\#1737](https://github.com/webtorrent/webtorrent-desktop/pull/1737) ([akaustav](https://github.com/akaustav))
- Fix "Save Torrent File As..." [\#1743](https://github.com/webtorrent/webtorrent-desktop/pull/1743) ([gpatarin](https://github.com/gpatarin))
## v0.21.0 - 2019-09-14
### Added

View File

@@ -97,7 +97,7 @@ comparing each one to a reference. Why screenshots?
https://github.com/blog/817-behold-image-view-modes
For MacOS, you'll need a Retina screen for the integration tests to pass. Your screen should have
the same resolution as a 2016 12" Macbook.
the same resolution as a 2018 MacBook Pro 13".
For Windows, you'll need Windows 10 with a 1366x768 screen.
@@ -125,6 +125,7 @@ The following optional arguments are available:
- `--sign` - Sign the application (Mac, Windows)
- `--package=[type]` - Package single output type.
- `deb` - Debian package
- `rpm` - RedHat package
- `zip` - Linux zip file
- `dmg` - Mac disk image
- `exe` - Windows installer
@@ -141,11 +142,12 @@ The Windows app can be packaged from **any** platform.
Note: Windows code signing only works from **Windows**, for now.
Note: To package the Windows app from non-Windows platforms,
[Wine](https://www.winehq.org/) needs to be installed. For example on Mac, first
install [XQuartz](http://www.xquartz.org/), then run:
[Wine](https://www.winehq.org/) and [Mono](https://www.mono-project.com/) need
to be installed. For example on Mac, first install
[XQuartz](http://www.xquartz.org/), then run:
```
brew install wine
brew install wine mono
```
(Requires the [Homebrew](http://brew.sh/) package manager.)
@@ -163,7 +165,6 @@ If packaging from Mac, install system dependencies with Homebrew by running:
```
npm run install-system-deps
```
#### Recommended readings to start working in the app
Electron (Framework to make native apps for Windows, OSX and Linux in Javascript):
@@ -173,7 +174,7 @@ React.js (Framework to work with Frontend UI):
https://reactjs.org/docs/getting-started.html
Material UI (React components that implement Google's Material Design.):
https://material-ui.com/getting-started
https://material-ui.com/getting-started/installation
### Privacy

View File

@@ -46,6 +46,11 @@
```
npm run package -- darwin --sign
```
Move the `.zip` and `.dmg` file somewhere because the next step wipes the `dist/` folder away.
```
npm run package -- linux --sign
```
@@ -69,17 +74,29 @@
**This is the most important part.**
- Manually download the binaries for each platform from Github.
- Manually download the binaries for each platform from Github.
**Do not use your locally built binaries.** Modern OSs treat executables differently if they've
been downloaded, even though the files are byte for byte identical. This ensures that the
codesigning worked and is valid.
- Smoke test WebTorrent Desktop on each platform.
- Smoke test WebTorrent Desktop on each platform. Before a release, check that the following basic use cases work correctly:
See Smoke Tests below for details. Open DevTools
on Windows and Mac, and ensure that the auto updater is running. If the auto updater does not
run, users will successfully auto update to this new version, and then be stuck there forever.
1. Click "Play" to stream a built-in torrent (e.g. Sintel)
- Ensure that seeking to undownloaded region works and plays immediately.
- Ensure that sintel.mp4 gets downloaded to `~/Downloads`.
2. Check that the auto-updater works
- Open the console and check for the line "No update available" to indicate that the auto-updater is working. (If the auto updater does not run, users will successfully auto update to this new version, and then be stuck there forever.)
3. Add a new .torrent file via drag-and-drop.
- Ensure that it gets added to the list and starts downloading.
4. Remove a torrent from the client
- Ensure that the file is removed from `~/Downloads`
5. Create and seed a new a torrent via drag-and-drop.
- Ensure that the torrent gets created and seeding begins.
### 4. Ship it
@@ -88,25 +105,5 @@
Create a pull request in [webtorrent.io](https://github.com/webtorrent/webtorrent.io). Update
`config.js`, updating the desktop app version.
As soon as this PR is merged, Jenkins will automatically redeploy the WebTorrent website, and
Once this PR is merged and Feross redeploys the WebTorrent website,
hundreds of thousands of users around the world will start auto updating. **Merge with care.**
## Smoke Tests
Before a release, check that the following basic use cases work correctly:
1. Click "Play" to stream a built-in torrent (e.g. Sintel)
- Ensure that seeking to undownloaded region works and plays immediately.
- Ensure that sintel.mp4 gets downloaded to `~/Downloads`.
2. Check that the auto-updater works
- Open the console and check for the line "No update available" to indicate
3. Add a new .torrent file via drag-and-drop.
- Ensure that it gets added to the list and starts downloading
4. Remove a torrent from the client
- Ensure that the file is removed from `~/Downloads`
5. Create and seed a new a torrent via drag-and-drop.
- Ensure that the torrent gets created and seeding begins.

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
</dict>
</plist>

View File

@@ -1,39 +0,0 @@
#!/usr/bin/env node
const walkSync = require('walk-sync')
const fs = require('fs')
const path = require('path')
let hasErrors = false
// Find all Javascript source files
const files = walkSync('src', { globs: ['**/*.js'] })
console.log('Running extra-lint on ' + files.length + ' files...')
// Read each file, line by line
files.forEach(function (file) {
const filepath = path.join('src', file)
const lines = fs.readFileSync(filepath, 'utf8').split('\n')
lines.forEach(function (line, i) {
let error
// No lines over 100 characters
if (line.length > 100) {
error = 'Line >100 chars'
}
if (line.match(/^var /) || line.match(/ var /)) {
error = 'Use const or let'
}
if (error) {
const name = path.basename(file)
console.log('%s:%d - %s:\n%s', name, i + 1, error, line)
hasErrors = true
}
})
})
if (hasErrors) process.exit(1)
else console.log('Looks good!')

View File

@@ -8,7 +8,6 @@ const cp = require('child_process')
const electronPackager = require('electron-packager')
const fs = require('fs')
const minimist = require('minimist')
const mkdirp = require('mkdirp')
const os = require('os')
const path = require('path')
const rimraf = require('rimraf')
@@ -37,7 +36,7 @@ const argv = minimist(process.argv.slice(2), {
})
function build () {
console.log('Reinstalling node_modules...')
console.log('Installing node_modules...')
rimraf.sync(NODE_MODULES_PATH)
cp.execSync('npm ci', { stdio: 'inherit' })
@@ -173,8 +172,8 @@ const linux = {
// Build for Linux.
platform: 'linux',
// Build x64 binary onle.
arch: 'x64'
// Build x64 and arm64 binaries.
arch: ['x64', 'arm64']
// Note: Application icon for Linux is specified via the BrowserWindow `icon` option.
}
@@ -267,6 +266,7 @@ function buildDarwin (cb) {
function signApp (cb) {
const sign = require('electron-osx-sign')
const { notarize } = require('electron-notarize')
/*
* Sign the app with Apple Developer ID certificates. We sign the app for 2 reasons:
@@ -282,16 +282,37 @@ function buildDarwin (cb) {
* - Membership in the Apple Developer Program
*/
const signOpts = {
verbose: true,
app: appPath,
platform: 'darwin',
verbose: true
identity: 'Developer ID Application: WebTorrent, LLC (5MAMC8G3L8)',
hardenedRuntime: true,
entitlements: path.join(config.ROOT_PATH, 'bin', 'darwin-entitlements.plist'),
'entitlements-inherit': path.join(config.ROOT_PATH, 'bin', 'darwin-entitlements.plist'),
'signature-flags': 'library'
}
const notarizeOpts = {
appBundleId: darwin.appBundleId,
appPath,
appleId: 'feross@feross.org',
appleIdPassword: '@keychain:AC_PASSWORD'
}
console.log('Mac: Signing app...')
sign(signOpts, function (err) {
if (err) return cb(err)
console.log('Mac: Signed app.')
cb(null)
console.log('Mac: Notarizing app...')
notarize(notarizeOpts).then(
function () {
console.log('Mac: Notarized app.')
cb(null)
},
function (err) {
cb(err)
})
})
}
@@ -430,7 +451,7 @@ function buildWin32 (cb) {
// remoteToken: process.env.WEBTORRENT_GITHUB_API_TOKEN,
setupExe: config.APP_NAME + 'Setup-v' + config.APP_VERSION + '.exe',
setupIcon: config.APP_ICON + '.ico',
signWithParams: signWithParams,
signWithParams,
title: config.APP_NAME,
usePackageJson: false,
version: pkg.version
@@ -457,13 +478,13 @@ function buildWin32 (cb) {
console.log('Windows: Creating portable app...')
const portablePath = path.join(filesPath, 'Portable Settings')
mkdirp.sync(portablePath)
fs.mkdirSync(portablePath, { recursive: true })
const downloadsPath = path.join(portablePath, 'Downloads')
mkdirp.sync(downloadsPath)
fs.mkdirSync(downloadsPath, { recursive: true })
const tempPath = path.join(portablePath, 'Temp')
mkdirp.sync(tempPath)
fs.mkdirSync(tempPath, { recursive: true })
const inPath = path.join(DIST_PATH, path.basename(filesPath))
const outPath = path.join(DIST_PATH, BUILD_NAME + '-win.zip')
@@ -485,11 +506,16 @@ function buildLinux (cb) {
const tasks = []
buildPath.forEach(function (filesPath) {
const destArch = filesPath.split('-').pop()
if (argv.package === 'deb' || argv.package === 'all') {
tasks.push((cb) => packageDeb(filesPath, cb))
tasks.push((cb) => packageDeb(filesPath, destArch, cb))
}
if (argv.package === 'rpm' || argv.package === 'all') {
tasks.push((cb) => packageRpm(filesPath, destArch, cb))
}
if (argv.package === 'zip' || argv.package === 'all') {
tasks.push((cb) => packageZip(filesPath, cb))
tasks.push((cb) => packageZip(filesPath, destArch, cb))
}
})
series(tasks, cb)
@@ -497,16 +523,65 @@ function buildLinux (cb) {
cb(err)
})
function packageDeb (filesPath, cb) {
function packageDeb (filesPath, destArch, cb) {
// Linux convention for Debian based 'x64' is 'amd64'
if (destArch === 'x64') {
destArch = 'amd64'
}
// Create .deb file for Debian-based platforms
console.log('Linux: Creating deb...')
console.log(`Linux: Creating ${destArch} deb...`)
const installer = require('electron-installer-debian')
const options = {
src: filesPath + '/',
dest: DIST_PATH,
arch: 'amd64',
arch: destArch,
bin: 'WebTorrent',
icon: {
'48x48': path.join(config.STATIC_PATH, 'linux/share/icons/hicolor/48x48/apps/webtorrent-desktop.png'),
'256x256': path.join(config.STATIC_PATH, 'linux/share/icons/hicolor/256x256/apps/webtorrent-desktop.png')
},
categories: ['Network', 'FileTransfer', 'P2P'],
mimeType: ['application/x-bittorrent', 'x-scheme-handler/magnet', 'x-scheme-handler/stream-magnet'],
desktopTemplate: path.join(config.STATIC_PATH, 'linux/webtorrent-desktop.ejs'),
lintianOverrides: [
'unstripped-binary-or-object',
'embedded-library',
'missing-dependency-on-libc',
'changelog-file-missing-in-native-package',
'description-synopsis-is-duplicated',
'setuid-binary',
'binary-without-manpage',
'shlib-with-executable-bit'
]
}
installer(options).then(
() => {
console.log(`Linux: Created ${destArch} deb.`)
cb(null)
},
(err) => cb(err)
)
}
function packageRpm (filesPath, destArch, cb) {
// Linux convention for RedHat based 'x64' is 'x86_64'
if (destArch === 'x64') {
destArch = 'x86_64'
}
// Create .rpm file for RedHat-based platforms
console.log(`Linux: Creating ${destArch} rpm...`)
const installer = require('electron-installer-redhat')
const options = {
src: filesPath + '/',
dest: DIST_PATH,
arch: destArch,
bin: 'WebTorrent',
icon: {
'48x48': path.join(config.STATIC_PATH, 'linux/share/icons/hicolor/48x48/apps/webtorrent-desktop.png'),
@@ -519,22 +594,22 @@ function buildLinux (cb) {
installer(options).then(
() => {
console.log('Linux: Created deb.')
console.log(`Linux: Created ${destArch} rpm.`)
cb(null)
},
(err) => cb(err)
)
}
function packageZip (filesPath, cb) {
function packageZip (filesPath, destArch, cb) {
// Create .zip file for Linux
console.log('Linux: Creating zip...')
console.log(`Linux: Creating ${destArch} zip...`)
const inPath = path.join(DIST_PATH, path.basename(filesPath))
const outPath = path.join(DIST_PATH, BUILD_NAME + '-linux.zip')
const outPath = path.join(DIST_PATH, `${BUILD_NAME}-linux-${destArch}.zip`)
zip.zipSync(inPath, outPath)
console.log('Linux: Created zip.')
console.log(`Linux: Created ${destArch} zip.`)
cb(null)
}
}

View File

@@ -13,6 +13,7 @@ while (<>) {
next if /(dc\@DCs-MacBook.local)/;
next if /(rolandoguedes\@gmail.com)/;
next if /(grunjol\@users.noreply.github.com)/;
next if /(dependabot)/;
$seen{$_} = push @authors, "- ", $_;
}
END {

9215
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,74 +1,83 @@
{
"name": "webtorrent-desktop",
"description": "WebTorrent, the streaming torrent client. For Mac, Windows, and Linux.",
"version": "0.20.0",
"version": "0.24.0",
"author": {
"name": "WebTorrent, LLC",
"email": "feross@webtorrent.io",
"url": "https://webtorrent.io"
},
"babel": {
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"useBuiltIns": true
}
]
]
},
"bugs": {
"url": "https://github.com/webtorrent/webtorrent-desktop/issues"
},
"dependencies": {
"airplayer": "github:webtorrent/airplayer#fix-security",
"application-config": "^1.0.1",
"arch": "^2.1.1",
"application-config": "^2.0.0",
"arch": "^2.2.0",
"auto-launch": "^5.0.5",
"bitfield": "^3.0.0",
"capture-frame": "^3.0.0",
"chokidar": "^3.0.2",
"bitfield": "^4.0.0",
"capture-frame": "^4.0.0",
"chokidar": "^3.4.3",
"chromecasts": "^1.9.1",
"cp-file": "^7.0.0",
"create-torrent": "^4.4.1",
"create-torrent": "^4.4.2",
"debounce": "^1.2.0",
"deep-equal": "^1.1.0",
"dlnacasts": "^0.1.0",
"drag-drop": "^5.0.1",
"drag-drop": "^6.1.0",
"es6-error": "^4.1.1",
"fn-getter": "^1.0.0",
"iso-639-1": "^2.1.0",
"languagedetect": "^1.2.0",
"location-history": "^1.1.1",
"iso-639-1": "^2.1.4",
"languagedetect": "^2.0.0",
"location-history": "^1.1.2",
"material-ui": "^0.20.2",
"mkdirp": "^0.5.1",
"music-metadata": "^4.5.3",
"music-metadata": "^7.5.0",
"network-address": "^1.1.2",
"parse-torrent": "^7.0.1",
"parse-torrent": "^9.1.0",
"prettier-bytes": "^1.0.4",
"prop-types": "^15.7.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"rimraf": "^3.0.0",
"run-parallel": "^1.1.9",
"semver": "^6.3.0",
"simple-concat": "^1.0.0",
"simple-get": "^3.0.3",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"rimraf": "^3.0.2",
"run-parallel": "^1.1.10",
"semver": "^7.3.2",
"simple-concat": "^1.0.1",
"simple-get": "^4.0.0",
"srt-to-vtt": "^1.1.3",
"vlc-command": "^1.2.0",
"webtorrent": ">=0.107.16",
"webtorrent": ">=0.111.0",
"winreg": "^1.2.4"
},
"devDependencies": {
"babel-eslint": "^10.0.3",
"buble": "^0.19.8",
"cross-zip": "^2.1.6",
"depcheck": "^0.8.3",
"electron": "~6.0.9",
"electron-osx-sign": "^0.4.13",
"electron-packager": "^14.0.6",
"electron-winstaller": "^4.0.0",
"gh-release": "^3.5.0",
"minimist": "^1.2.0",
"nodemon": "^1.19.2",
"open": "^6.4.0",
"@babel/cli": "^7.12.8",
"@babel/core": "^7.12.9",
"@babel/eslint-parser": "^7.12.1",
"@babel/plugin-transform-react-jsx": "^7.12.7",
"cross-zip": "^4.0.0",
"depcheck": "^1.3.1",
"electron": "~11.0.3",
"electron-notarize": "^1.0.0",
"electron-osx-sign": "^0.5.0",
"electron-packager": "^15.1.0",
"electron-winstaller": "^4.0.1",
"gh-release": "^4.0.3",
"minimist": "^1.2.5",
"nodemon": "^2.0.6",
"open": "^7.3.0",
"plist": "^3.0.1",
"pngjs": "^3.4.0",
"run-series": "^1.1.8",
"spectron": "^8.0.0",
"pngjs": "^6.0.0",
"run-series": "^1.1.9",
"spectron": "~12.0.0",
"standard": "*",
"tape": "^4.11.0",
"walk-sync": "^2.0.2"
"tape": "^5.0.1"
},
"engines": {
"node": ">=4.0.0"
@@ -88,7 +97,8 @@
"main": "index.js",
"optionalDependencies": {
"appdmg": "^0.6.0",
"electron-installer-debian": "^2.0.0"
"electron-installer-debian": "^3.1.0",
"electron-installer-redhat": "^3.2.0"
},
"private": true,
"productName": "WebTorrent",
@@ -97,19 +107,19 @@
"url": "git://github.com/webtorrent/webtorrent-desktop.git"
},
"scripts": {
"build": "buble src --output build",
"build": "babel src --out-dir build",
"clean": "node ./bin/clean.js",
"gh-release": "gh-release",
"install-system-deps": "brew install fakeroot dpkg",
"install-system-deps": "brew install fakeroot dpkg rpm",
"open-config": "node ./bin/open-config.js",
"package": "node ./bin/package.js",
"start": "npm run build && electron .",
"test": "standard && depcheck --ignores=standard,babel-eslint --ignore-dirs=build,dist && node ./bin/extra-lint.js",
"start": "npm run build && electron --no-sandbox .",
"test": "standard && depcheck --ignores=standard,@babel/eslint-parser --ignore-dirs=build,dist",
"test-integration": "npm run build && node ./test",
"update-authors": "./bin/update-authors.sh",
"watch": "nodemon --exec \"npm run start\" --ext js,css --ignore build/ --ignore dist/"
},
"standard": {
"parser": "babel-eslint"
"parser": "@babel/eslint-parser"
}
}

View File

@@ -1,6 +1,6 @@
const appConfig = require('application-config')('WebTorrent')
const path = require('path')
const electron = require('electron')
const { app, remote } = require('electron')
const arch = require('arch')
const APP_NAME = 'WebTorrent'
@@ -23,12 +23,12 @@ module.exports = {
CRASH_REPORT_URL: 'https://webtorrent.io/desktop/crash-report',
TELEMETRY_URL: 'https://webtorrent.io/desktop/telemetry',
APP_COPYRIGHT: 'Copyright © 2014-2019 ' + APP_TEAM,
APP_COPYRIGHT: `Copyright © 2014-${new Date().getFullYear()} ${APP_TEAM}`,
APP_FILE_ICON: path.join(__dirname, '..', 'static', 'WebTorrentFile'),
APP_ICON: path.join(__dirname, '..', 'static', 'WebTorrent'),
APP_NAME: APP_NAME,
APP_TEAM: APP_TEAM,
APP_VERSION: APP_VERSION,
APP_NAME,
APP_TEAM,
APP_VERSION,
APP_WINDOW_TITLE: APP_NAME,
CONFIG_PATH: getConfigPath(),
@@ -78,9 +78,9 @@ module.exports = {
HOME_PAGE_URL: 'https://webtorrent.io',
TWITTER_PAGE_URL: 'https://twitter.com/WebTorrentApp',
IS_PORTABLE: IS_PORTABLE,
IS_PRODUCTION: IS_PRODUCTION,
IS_TEST: IS_TEST,
IS_PORTABLE,
IS_PRODUCTION,
IS_TEST,
OS_SYSARCH: arch() === 'x64' ? 'x64' : 'ia32',
@@ -100,8 +100,8 @@ module.exports = {
WINDOW_MIN_HEIGHT: UI_HEADER_HEIGHT + (UI_TORRENT_HEIGHT * 2), // header + 2 torrents
WINDOW_MIN_WIDTH: 425,
UI_HEADER_HEIGHT: UI_HEADER_HEIGHT,
UI_TORRENT_HEIGHT: UI_TORRENT_HEIGHT
UI_HEADER_HEIGHT,
UI_TORRENT_HEIGHT
}
function getConfigPath () {
@@ -126,10 +126,10 @@ function getPath (key) {
return ''
} else if (process.type === 'renderer') {
// Electron renderer process
return electron.remote.app.getPath(key)
return remote.app.getPath(key)
} else {
// Electron main process
return electron.app.getPath(key)
return app.getPath(key)
}
}

View File

@@ -4,11 +4,12 @@ module.exports = {
function init () {
const config = require('./config')
const electron = require('electron')
const { crashReporter } = require('electron')
electron.crashReporter.start({
companyName: config.APP_NAME,
crashReporter.start({
productName: config.APP_NAME,
submitURL: config.CRASH_REPORT_URL
submitURL: config.CRASH_REPORT_URL,
globalExtra: { _companyName: config.APP_NAME },
compress: true
})
}

View File

@@ -2,7 +2,7 @@ module.exports = {
init
}
const electron = require('electron')
const { dialog } = require('electron')
const config = require('../config')
const log = require('./log')
@@ -44,13 +44,11 @@ function onResponse (err, res, data) {
}
}
electron.dialog.showMessageBox({
dialog.showMessageBox({
type: 'info',
buttons: ['OK'],
title: data.title,
message: data.message,
detail: data.detail
}, noop)
})
}
function noop () {}

View File

@@ -6,7 +6,7 @@ module.exports = {
openFiles
}
const electron = require('electron')
const { dialog } = require('electron')
const log = require('./log')
const windows = require('./windows')
@@ -34,13 +34,13 @@ function openSeedDirectory () {
log('openSeedDirectory')
const opts = process.platform === 'darwin'
? {
title: 'Select a file or folder for the torrent.',
properties: ['openFile', 'openDirectory']
}
title: 'Select a file or folder for the torrent.',
properties: ['openFile', 'openDirectory']
}
: {
title: 'Select a folder for the torrent.',
properties: ['openDirectory']
}
title: 'Select a folder for the torrent.',
properties: ['openDirectory']
}
showOpenSeed(opts)
}
@@ -53,19 +53,18 @@ function openFiles () {
log('openFiles')
const opts = process.platform === 'darwin'
? {
title: 'Select a file or folder to add.',
properties: ['openFile', 'openDirectory']
}
title: 'Select a file or folder to add.',
properties: ['openFile', 'openDirectory']
}
: {
title: 'Select a file to add.',
properties: ['openFile']
}
title: 'Select a file to add.',
properties: ['openFile']
}
setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
resetTitle()
if (!Array.isArray(selectedPaths)) return
windows.main.dispatch('onOpen', selectedPaths)
})
const selectedPaths = dialog.showOpenDialogSync(windows.main.win, opts)
resetTitle()
if (!Array.isArray(selectedPaths)) return
windows.main.dispatch('onOpen', selectedPaths)
}
/*
@@ -80,12 +79,11 @@ function openTorrentFile () {
properties: ['openFile', 'multiSelections']
}
setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
resetTitle()
if (!Array.isArray(selectedPaths)) return
selectedPaths.forEach(function (selectedPath) {
windows.main.dispatch('addTorrent', selectedPath)
})
const selectedPaths = dialog.showOpenDialogSync(windows.main.win, opts)
resetTitle()
if (!Array.isArray(selectedPaths)) return
selectedPaths.forEach(function (selectedPath) {
windows.main.dispatch('addTorrent', selectedPath)
})
}
@@ -116,9 +114,8 @@ function resetTitle () {
*/
function showOpenSeed (opts) {
setTitle(opts.title)
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
resetTitle()
if (!Array.isArray(selectedPaths)) return
windows.main.dispatch('showCreateTorrent', selectedPaths)
})
const selectedPaths = dialog.showOpenDialogSync(windows.main.win, opts)
resetTitle()
if (!Array.isArray(selectedPaths)) return
windows.main.dispatch('showCreateTorrent', selectedPaths)
}

View File

@@ -34,7 +34,7 @@ function setBadge (count) {
if (process.platform === 'darwin' ||
(process.platform === 'linux' && app.isUnityRunning())) {
log(`setBadge: ${count}`)
app.setBadgeCount(Number(count))
app.badgeCount = Number(count)
}
}

View File

@@ -17,12 +17,12 @@ let proc = null
function checkInstall (playerPath, cb) {
// check for VLC if external player has not been specified by the user
// otherwise assume the player is installed
if (playerPath == null) return vlcCommand(cb)
if (!playerPath) return vlcCommand(cb)
process.nextTick(() => cb(null))
}
function spawn (playerPath, url, title) {
if (playerPath != null) return spawnExternal(playerPath, [url])
if (playerPath) return spawnExternal(playerPath, [url])
// Try to find and use VLC if external player is not specified
vlcCommand((err, vlcPath) => {

View File

@@ -25,8 +25,7 @@ function uninstall () {
}
function installDarwin () {
const electron = require('electron')
const app = electron.app
const { app } = require('electron')
// On Mac, only protocols that are listed in `Info.plist` can be set as the
// default handler at runtime.

View File

@@ -1,12 +1,14 @@
console.time('init')
const electron = require('electron')
const app = electron.app
const { app, ipcMain } = require('electron')
// Start crash reporter early, so it takes effect for child processes
const crashReporter = require('../crash-reporter')
crashReporter.init()
const parallel = require('run-parallel')
const config = require('../config')
const crashReporter = require('../crash-reporter')
const ipc = require('./ipc')
const log = require('./log')
const menu = require('./menu')
@@ -64,8 +66,6 @@ function init () {
app.setPath('temp', path.join(config.CONFIG_PATH, 'Temp'))
}
const ipcMain = electron.ipcMain
let isReady = false // app ready, windows can be created
app.ipcReady = false // main window has finished loading and IPC is ready
app.isQuitting = false
@@ -81,7 +81,7 @@ function init () {
isReady = true
const state = results.state
windows.main.init(state, { hidden: hidden })
windows.main.init(state, { hidden })
windows.webtorrent.init()
menu.init()
@@ -109,10 +109,6 @@ function init () {
ipc.init()
app.once('will-finish-launching', function () {
crashReporter.init()
})
app.once('ipcReady', function () {
log('Command line args:', argv)
processArgv(argv)
@@ -199,9 +195,13 @@ function onAppOpen (newArgv) {
// Development: 2 args, eg: electron .
// Test: 4 args, eg: electron -r .../mocks.js .
function sliceArgv (argv) {
return argv.slice(config.IS_PRODUCTION ? 1
: config.IS_TEST ? 4
: 2)
return argv.slice(
config.IS_PRODUCTION
? 1
: config.IS_TEST
? 4
: 2
)
}
function processArgv (argv) {

View File

@@ -3,9 +3,7 @@ module.exports = {
setModule
}
const electron = require('electron')
const app = electron.app
const { app, ipcMain } = require('electron')
const log = require('./log')
const menu = require('./menu')
@@ -23,14 +21,12 @@ function setModule (name, module) {
}
function init () {
const ipc = electron.ipcMain
ipc.once('ipcReady', function (e) {
ipcMain.once('ipcReady', function (e) {
app.ipcReady = true
app.emit('ipcReady')
})
ipc.once('ipcReadyWebTorrent', function (e) {
ipcMain.once('ipcReadyWebTorrent', function (e) {
app.ipcReadyWebTorrent = true
log('sending %d queued messages from the main win to the webtorrent window',
messageQueueMainToWebTorrent.length)
@@ -44,11 +40,11 @@ function init () {
* Dialog
*/
ipc.on('openTorrentFile', () => {
ipcMain.on('openTorrentFile', () => {
const dialog = require('./dialog')
dialog.openTorrentFile()
})
ipc.on('openFiles', () => {
ipcMain.on('openFiles', () => {
const dialog = require('./dialog')
dialog.openFiles()
})
@@ -57,11 +53,11 @@ function init () {
* Dock
*/
ipc.on('setBadge', (e, ...args) => {
ipcMain.on('setBadge', (e, ...args) => {
const dock = require('./dock')
dock.setBadge(...args)
})
ipc.on('downloadFinished', (e, ...args) => {
ipcMain.on('downloadFinished', (e, ...args) => {
const dock = require('./dock')
dock.downloadFinished(...args)
})
@@ -70,7 +66,7 @@ function init () {
* Player Events
*/
ipc.on('onPlayerOpen', function () {
ipcMain.on('onPlayerOpen', function () {
const powerSaveBlocker = require('./power-save-blocker')
const shortcuts = require('./shortcuts')
const thumbar = require('./thumbar')
@@ -81,14 +77,14 @@ function init () {
thumbar.enable()
})
ipc.on('onPlayerUpdate', function (e, ...args) {
ipcMain.on('onPlayerUpdate', function (e, ...args) {
const thumbar = require('./thumbar')
menu.onPlayerUpdate(...args)
thumbar.onPlayerUpdate(...args)
})
ipc.on('onPlayerClose', function () {
ipcMain.on('onPlayerClose', function () {
const powerSaveBlocker = require('./power-save-blocker')
const shortcuts = require('./shortcuts')
const thumbar = require('./thumbar')
@@ -99,7 +95,7 @@ function init () {
thumbar.disable()
})
ipc.on('onPlayerPlay', function () {
ipcMain.on('onPlayerPlay', function () {
const powerSaveBlocker = require('./power-save-blocker')
const thumbar = require('./thumbar')
@@ -107,7 +103,7 @@ function init () {
thumbar.onPlayerPlay()
})
ipc.on('onPlayerPause', function () {
ipcMain.on('onPlayerPause', function () {
const powerSaveBlocker = require('./power-save-blocker')
const thumbar = require('./thumbar')
@@ -119,7 +115,7 @@ function init () {
* Folder Watcher Events
*/
ipc.on('startFolderWatcher', function () {
ipcMain.on('startFolderWatcher', function () {
if (!modules.folderWatcher) {
log('IPC ERR: folderWatcher module is not defined.')
return
@@ -128,7 +124,7 @@ function init () {
modules.folderWatcher.start()
})
ipc.on('stopFolderWatcher', function () {
ipcMain.on('stopFolderWatcher', function () {
if (!modules.folderWatcher) {
log('IPC ERR: folderWatcher module is not defined.')
return
@@ -141,15 +137,15 @@ function init () {
* Shell
*/
ipc.on('openItem', (e, ...args) => {
ipcMain.on('openPath', (e, ...args) => {
const shell = require('./shell')
shell.openItem(...args)
shell.openPath(...args)
})
ipc.on('showItemInFolder', (e, ...args) => {
ipcMain.on('showItemInFolder', (e, ...args) => {
const shell = require('./shell')
shell.showItemInFolder(...args)
})
ipc.on('moveItemToTrash', (e, ...args) => {
ipcMain.on('moveItemToTrash', (e, ...args) => {
const shell = require('./shell')
shell.moveItemToTrash(...args)
})
@@ -158,7 +154,7 @@ function init () {
* File handlers
*/
ipc.on('setDefaultFileHandler', (e, flag) => {
ipcMain.on('setDefaultFileHandler', (e, flag) => {
const handlers = require('./handlers')
if (flag) handlers.install()
@@ -169,7 +165,7 @@ function init () {
* Auto start on login
*/
ipc.on('setStartup', (e, flag) => {
ipcMain.on('setStartup', (e, flag) => {
const startup = require('./startup')
if (flag) startup.install()
@@ -182,19 +178,19 @@ function init () {
const main = windows.main
ipc.on('setAspectRatio', (e, ...args) => main.setAspectRatio(...args))
ipc.on('setBounds', (e, ...args) => main.setBounds(...args))
ipc.on('setProgress', (e, ...args) => main.setProgress(...args))
ipc.on('setTitle', (e, ...args) => main.setTitle(...args))
ipc.on('show', () => main.show())
ipc.on('toggleFullScreen', (e, ...args) => main.toggleFullScreen(...args))
ipc.on('setAllowNav', (e, ...args) => menu.setAllowNav(...args))
ipcMain.on('setAspectRatio', (e, ...args) => main.setAspectRatio(...args))
ipcMain.on('setBounds', (e, ...args) => main.setBounds(...args))
ipcMain.on('setProgress', (e, ...args) => main.setProgress(...args))
ipcMain.on('setTitle', (e, ...args) => main.setTitle(...args))
ipcMain.on('show', () => main.show())
ipcMain.on('toggleFullScreen', (e, ...args) => main.toggleFullScreen(...args))
ipcMain.on('setAllowNav', (e, ...args) => menu.setAllowNav(...args))
/**
* External Media Player
*/
ipc.on('checkForExternalPlayer', function (e, path) {
ipcMain.on('checkForExternalPlayer', function (e, path) {
const externalPlayer = require('./external-player')
externalPlayer.checkInstall(path, function (err) {
@@ -202,7 +198,7 @@ function init () {
})
})
ipc.on('openExternalPlayer', (e, ...args) => {
ipcMain.on('openExternalPlayer', (e, ...args) => {
const externalPlayer = require('./external-player')
const thumbar = require('./thumbar')
@@ -211,7 +207,7 @@ function init () {
externalPlayer.spawn(...args)
})
ipc.on('quitExternalPlayer', () => {
ipcMain.on('quitExternalPlayer', () => {
const externalPlayer = require('./external-player')
externalPlayer.kill()
})
@@ -220,8 +216,8 @@ function init () {
* Message passing
*/
const oldEmit = ipc.emit
ipc.emit = function (name, e, ...args) {
const oldEmit = ipcMain.emit
ipcMain.emit = function (name, e, ...args) {
// Relay messages between the main window and the WebTorrent hidden window
if (name.startsWith('wt-') && !app.isQuitting) {
if (e.sender.browserWindowOptions.title === 'webtorrent-hidden-window') {
@@ -235,8 +231,8 @@ function init () {
} else {
// Queue message for webtorrent window, it hasn't finished loading yet
messageQueueMainToWebTorrent.push({
name: name,
args: args
name,
args
})
log('webtorrent: queueing %s', name)
}
@@ -244,6 +240,6 @@ function init () {
}
// Emit all other events normally
oldEmit.call(ipc, name, e, ...args)
oldEmit.call(ipcMain, name, e, ...args)
}
}

View File

@@ -8,11 +8,9 @@ module.exports.error = error
* where they can be viewed in Developer Tools.
*/
const electron = require('electron')
const { app } = require('electron')
const windows = require('./windows')
const app = electron.app
function log (...args) {
if (app.ipcReady) {
windows.main.send('log', ...args)

View File

@@ -8,9 +8,7 @@ module.exports = {
onToggleFullScreen
}
const electron = require('electron')
const app = electron.app
const { app, Menu } = require('electron')
const config = require('../config')
const windows = require('./windows')
@@ -18,8 +16,8 @@ const windows = require('./windows')
let menu = null
function init () {
menu = electron.Menu.buildFromTemplate(getMenuTemplate())
electron.Menu.setApplicationMenu(menu)
menu = Menu.buildFromTemplate(getMenuTemplate())
Menu.setApplicationMenu(menu)
}
function togglePlaybackControls (flag) {
@@ -288,6 +286,14 @@ function getMenuTemplate () {
{
label: 'Resume All',
click: () => windows.main.dispatch('resumeAllTorrents')
},
{
label: 'Remove All From List',
click: () => windows.main.dispatch('confirmDeleteAllTorrents', false)
},
{
label: 'Remove All Data Files',
click: () => windows.main.dispatch('confirmDeleteAllTorrents', true)
}
]
},
@@ -357,8 +363,7 @@ function getMenuTemplate () {
type: 'separator'
},
{
role: 'services',
submenu: []
role: 'services'
},
{
type: 'separator'

View File

@@ -3,7 +3,7 @@ module.exports = {
disable
}
const electron = require('electron')
const { powerSaveBlocker } = require('electron')
const log = require('./log')
let blockId = 0
@@ -13,11 +13,11 @@ let blockId = 0
* display.
*/
function enable () {
if (electron.powerSaveBlocker.isStarted(blockId)) {
if (powerSaveBlocker.isStarted(blockId)) {
// If a power saver block already exists, do nothing.
return
}
blockId = electron.powerSaveBlocker.start('prevent-display-sleep')
blockId = powerSaveBlocker.start('prevent-display-sleep')
log(`powerSaveBlocker.enable: ${blockId}`)
}
@@ -25,10 +25,10 @@ function enable () {
* Stop blocking the system from entering low-power mode.
*/
function disable () {
if (!electron.powerSaveBlocker.isStarted(blockId)) {
if (!powerSaveBlocker.isStarted(blockId)) {
// If a power saver block does not exist, do nothing.
return
}
electron.powerSaveBlocker.stop(blockId)
powerSaveBlocker.stop(blockId)
log(`powerSaveBlocker.disable: ${blockId}`)
}

View File

@@ -1,11 +1,11 @@
module.exports = {
openExternal,
openItem,
openPath,
showItemInFolder,
moveItemToTrash
}
const electron = require('electron')
const { shell } = require('electron')
const log = require('./log')
/**
@@ -13,15 +13,16 @@ const log = require('./log')
*/
function openExternal (url) {
log(`openExternal: ${url}`)
electron.shell.openExternal(url)
shell.openExternal(url)
}
/**
* Open the given file in the desktops default manner.
*/
function openItem (path) {
log(`openItem: ${path}`)
electron.shell.openItem(path)
function openPath (path) {
log(`openPath: ${path}`)
shell.openPath(path)
}
/**
@@ -29,7 +30,7 @@ function openItem (path) {
*/
function showItemInFolder (path) {
log(`showItemInFolder: ${path}`)
electron.shell.showItemInFolder(path)
shell.showItemInFolder(path)
}
/**
@@ -37,5 +38,5 @@ function showItemInFolder (path) {
*/
function moveItemToTrash (path) {
log(`moveItemToTrash: ${path}`)
electron.shell.moveItemToTrash(path)
shell.moveItemToTrash(path)
}

View File

@@ -3,20 +3,20 @@ module.exports = {
enable
}
const electron = require('electron')
const { globalShortcut } = require('electron')
const windows = require('./windows')
function enable () {
// Register play/pause media key, available on some keyboards.
electron.globalShortcut.register(
globalShortcut.register(
'MediaPlayPause',
() => windows.main.dispatch('playPause')
)
electron.globalShortcut.register(
globalShortcut.register(
'MediaNextTrack',
() => windows.main.dispatch('nextTrack')
)
electron.globalShortcut.register(
globalShortcut.register(
'MediaPreviousTrack',
() => windows.main.dispatch('previousTrack')
)
@@ -24,7 +24,7 @@ function enable () {
function disable () {
// Return the media key to the OS, so other apps can use it.
electron.globalShortcut.unregister('MediaPlayPause')
electron.globalShortcut.unregister('MediaNextTrack')
electron.globalShortcut.unregister('MediaPreviousTrack')
globalShortcut.unregister('MediaPlayPause')
globalShortcut.unregister('MediaNextTrack')
globalShortcut.unregister('MediaPreviousTrack')
}

View File

@@ -2,150 +2,39 @@ module.exports = {
handleEvent
}
const cp = require('child_process')
const electron = require('electron')
const fs = require('fs')
const os = require('os')
const path = require('path')
const { app } = require('electron')
const app = electron.app
const path = require('path')
const spawn = require('child_process').spawn
const handlers = require('./handlers')
const EXE_NAME = path.basename(process.execPath)
const UPDATE_EXE = path.join(process.execPath, '..', '..', 'Update.exe')
function handleEvent (cmd) {
if (cmd === '--squirrel-install') {
// App was installed. Install desktop/start menu shortcuts.
createShortcuts(function () {
// Ensure user sees install splash screen so they realize that Setup.exe actually
// installed an application and isn't the application itself.
setTimeout(function () {
app.quit()
}, 3000)
})
return true
}
const run = function (args, done) {
spawn(UPDATE_EXE, args, { detached: true })
.on('close', done)
}
if (cmd === '--squirrel-updated') {
// App was updated. (Called on new version of app)
updateShortcuts(function () {
app.quit()
})
function handleEvent (cmd) {
if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') {
run([`--createShortcut=${EXE_NAME}`], app.quit)
return true
}
if (cmd === '--squirrel-uninstall') {
// App was just uninstalled. Undo anything we did in the --squirrel-install and
// --squirrel-updated handlers
// Uninstall .torrent file and magnet link handlers
handlers.uninstall()
// Remove desktop/start menu shortcuts.
// HACK: add a callback to handlers.uninstall() so we can remove this setTimeout
setTimeout(function () {
removeShortcuts(function () {
app.quit()
})
}, 1000)
run([`--removeShortcut=${EXE_NAME}`], app.quit)
return true
}
if (cmd === '--squirrel-obsolete') {
// App will be updated. (Called on outgoing version of app)
app.quit()
return true
}
if (cmd === '--squirrel-firstrun') {
// App is running for the first time. Do not quit, allow startup to continue.
return false
}
return false
}
/**
* Spawn a command and invoke the callback when it completes with an error and
* the output from standard out.
*/
function spawn (command, args, cb) {
let stdout = ''
let error = null
let child = null
try {
child = cp.spawn(command, args)
} catch (err) {
// Spawn can throw an error
process.nextTick(function () {
cb(error, stdout)
})
return
}
child.stdout.on('data', function (data) {
stdout += data
})
child.on('error', function (processError) {
error = processError
})
child.on('close', function (code, signal) {
if (code !== 0 && !error) error = new Error('Command failed: #{signal || code}')
if (error) error.stdout = stdout
cb(error, stdout)
})
}
/**
* Spawn the Squirrel `Update.exe` command with the given arguments and invoke
* the callback when the command completes.
*/
function spawnUpdate (args, cb) {
spawn(UPDATE_EXE, args, cb)
}
/**
* Create desktop and start menu shortcuts using the Squirrel `Update.exe`
* command.
*/
function createShortcuts (cb) {
spawnUpdate(['--createShortcut', EXE_NAME], cb)
}
/**
* Update desktop and start menu shortcuts using the Squirrel `Update.exe`
* command.
*/
function updateShortcuts (cb) {
const homeDir = os.homedir()
if (homeDir) {
const desktopShortcutPath = path.join(homeDir, 'Desktop', 'WebTorrent.lnk')
// If the desktop shortcut was deleted by the user, then keep it deleted.
fs.access(desktopShortcutPath, function (err) {
const desktopShortcutExists = !err
createShortcuts(function () {
if (desktopShortcutExists) {
cb()
} else {
// Remove the unwanted desktop shortcut that was recreated
fs.unlink(desktopShortcutPath, cb)
}
})
})
} else {
createShortcuts(cb)
}
}
/**
* Remove desktop and start menu shortcuts using the Squirrel `Update.exe`
* command.
*/
function removeShortcuts (cb) {
spawnUpdate(['--removeShortcut', EXE_NAME], cb)
}

View File

@@ -4,9 +4,7 @@ module.exports = {
setWindowFocus
}
const electron = require('electron')
const app = electron.app
const { app, Tray, Menu } = require('electron')
const config = require('../config')
const windows = require('./windows')
@@ -67,7 +65,7 @@ function checkLinuxTraySupport (cb) {
}
function createTray () {
tray = new electron.Tray(getIconPath())
tray = new Tray(getIconPath())
// On Windows, left click opens the app, right click opens the context menu.
// On Linux, any click (left or right) opens the context menu.
@@ -78,7 +76,7 @@ function createTray () {
}
function updateTrayMenu () {
const contextMenu = electron.Menu.buildFromTemplate(getMenuTemplate())
const contextMenu = Menu.buildFromTemplate(getMenuTemplate())
tray.setContextMenu(contextMenu)
}

View File

@@ -2,7 +2,7 @@ module.exports = {
init
}
const electron = require('electron')
const { autoUpdater } = require('electron')
const get = require('simple-get')
const config = require('../config')
@@ -47,31 +47,31 @@ function onResponse (err, res, data) {
}
function initDarwinWin32 () {
electron.autoUpdater.on(
autoUpdater.on(
'error',
(err) => log.error(`Update error: ${err.message}`)
)
electron.autoUpdater.on(
autoUpdater.on(
'checking-for-update',
() => log('Checking for update')
)
electron.autoUpdater.on(
autoUpdater.on(
'update-available',
() => log('Update available')
)
electron.autoUpdater.on(
autoUpdater.on(
'update-not-available',
() => log('No update available')
)
electron.autoUpdater.on(
autoUpdater.on(
'update-downloaded',
(e, notes, name, date, url) => log(`Update downloaded: ${name}: ${url}`)
)
electron.autoUpdater.setFeedURL(AUTO_UPDATE_URL)
electron.autoUpdater.checkForUpdates()
autoUpdater.setFeedURL({ url: AUTO_UPDATE_URL })
autoUpdater.checkForUpdates()
}

View File

@@ -2,9 +2,7 @@ module.exports = {
init
}
const electron = require('electron')
const app = electron.app
const { app } = require('electron')
/**
* Add a user task menu to the app icon on right-click. (Windows)

View File

@@ -4,18 +4,18 @@ const about = module.exports = {
}
const config = require('../../config')
const electron = require('electron')
const { BrowserWindow } = require('electron')
function init () {
if (about.win) {
return about.win.show()
}
const win = about.win = new electron.BrowserWindow({
const win = about.win = new BrowserWindow({
backgroundColor: '#ECECEC',
center: true,
fullscreen: false,
height: 170,
height: 250,
icon: getIconPath(),
maximizable: false,
minimizable: false,
@@ -25,18 +25,22 @@ function init () {
title: 'About ' + config.APP_WINDOW_TITLE,
useContentSize: true,
webPreferences: {
nodeIntegration: true
nodeIntegration: true,
enableBlinkFeatures: 'AudioVideoTracks',
enableRemoteModule: true,
backgroundThrottling: false
},
width: 300
})
win.loadURL(config.WINDOW_ABOUT)
// No menu on the About window
win.setMenu(null)
win.once('ready-to-show', function () {
win.show()
// No menu on the About window
// Hack: BrowserWindow removeMenu method not working on electron@7
// https://github.com/electron/electron/issues/21088
win.setMenuBarVisibility(false)
})
win.once('closed', function () {

View File

@@ -14,11 +14,9 @@ const main = module.exports = {
win: null
}
const electron = require('electron')
const { app, BrowserWindow, screen } = require('electron')
const debounce = require('debounce')
const app = electron.app
const config = require('../../config')
const log = require('../log')
const menu = require('../menu')
@@ -30,9 +28,8 @@ function init (state, options) {
const initialBounds = Object.assign(config.WINDOW_INITIAL_BOUNDS, state.saved.bounds)
const win = main.win = new electron.BrowserWindow({
const win = main.win = new BrowserWindow({
backgroundColor: '#282828',
backgroundThrottling: false, // do not throttle animations/timers when page is background
darkTheme: true, // Forces dark theme (GTK+3)
height: initialBounds.height,
icon: getIconPath(), // Window icon (Windows, Linux)
@@ -44,7 +41,10 @@ function init (state, options) {
useContentSize: true, // Specify web page size without OS chrome
width: initialBounds.width,
webPreferences: {
nodeIntegration: true
nodeIntegration: true,
enableBlinkFeatures: 'AudioVideoTracks',
enableRemoteModule: true,
backgroundThrottling: false
},
x: initialBounds.x,
y: initialBounds.y
@@ -160,7 +160,7 @@ function setBounds (bounds, maximize) {
log(`setBounds: setting bounds to ${JSON.stringify(bounds)}`)
if (bounds.x === null && bounds.y === null) {
// X and Y not specified? By default, center on current screen
const scr = electron.screen.getDisplayMatching(main.win.getBounds())
const scr = screen.getDisplayMatching(main.win.getBounds())
bounds.x = Math.round(scr.bounds.x + (scr.bounds.width / 2) - (bounds.width / 2))
bounds.y = Math.round(scr.bounds.y + (scr.bounds.height / 2) - (bounds.height / 2))
log(`setBounds: centered to ${JSON.stringify(bounds)}`)

View File

@@ -6,14 +6,13 @@ const webtorrent = module.exports = {
win: null
}
const electron = require('electron')
const { app, BrowserWindow } = require('electron')
const config = require('../../config')
function init () {
const win = webtorrent.win = new electron.BrowserWindow({
const win = webtorrent.win = new BrowserWindow({
backgroundColor: '#1E1E1E',
backgroundThrottling: false, // do not throttle animations/timers when page is background
center: true,
fullscreen: false,
fullscreenable: false,
@@ -26,7 +25,10 @@ function init () {
title: 'webtorrent-hidden-window',
useContentSize: true,
webPreferences: {
nodeIntegration: true
nodeIntegration: true,
enableBlinkFeatures: 'AudioVideoTracks',
enableRemoteModule: true,
backgroundThrottling: false
},
width: 150
})
@@ -35,7 +37,7 @@ function init () {
// Prevent killing the WebTorrent process
win.on('close', function (e) {
if (electron.app.isQuitting) {
if (app.isQuitting) {
return
}
e.preventDefault()

View File

@@ -0,0 +1,31 @@
const React = require('react')
const ModalOKCancel = require('./modal-ok-cancel')
const { dispatch, dispatcher } = require('../lib/dispatcher')
module.exports = class DeleteAllTorrentsModal extends React.Component {
render () {
const { state: { modal: { deleteData } } } = this.props
const message = deleteData
? 'Are you sure you want to remove all the torrents from the list and delete the data files?'
: 'Are you sure you want to remove all the torrents from the list?'
const buttonText = deleteData ? 'REMOVE DATA' : 'REMOVE'
return (
<div>
<p><strong>{message}</strong></p>
<ModalOKCancel
cancelText='CANCEL'
onCancel={dispatcher('exitModal')}
okText={buttonText}
onOK={handleRemove}
/>
</div>
)
function handleRemove () {
dispatch('deleteAllTorrents', deleteData)
dispatch('exitModal')
}
}
}

View File

@@ -1,12 +1,10 @@
const path = require('path')
const colors = require('material-ui/styles/colors')
const electron = require('electron')
const { remote } = require('electron')
const React = require('react')
const PropTypes = require('prop-types')
const remote = electron.remote
const RaisedButton = require('material-ui/RaisedButton').default
const TextField = require('material-ui/TextField').default
@@ -32,18 +30,13 @@ class PathSelector extends React.Component {
handleClick () {
const opts = Object.assign({
defaultPath: this.props.value && path.dirname(this.props.value),
defaultPath: path.dirname(this.props.value || ''),
properties: ['openFile', 'openDirectory']
}, this.props.dialog)
remote.dialog.showOpenDialog(
remote.getCurrentWindow(),
opts,
(filenames) => {
if (!Array.isArray(filenames)) return
this.props.onChange && this.props.onChange(filenames[0])
}
)
const filenames = remote.dialog.showOpenDialogSync(remote.getCurrentWindow(), opts)
if (!Array.isArray(filenames)) return
this.props.onChange && this.props.onChange(filenames[0])
}
render () {

View File

@@ -1,5 +1,5 @@
const React = require('react')
const electron = require('electron')
const { shell } = require('electron')
const ModalOKCancel = require('./modal-ok-cancel')
const { dispatcher } = require('../lib/dispatcher')
@@ -36,7 +36,7 @@ module.exports = class UnsupportedMediaModal extends React.Component {
}
onInstall () {
electron.shell.openExternal('http://www.videolan.org/vlc/')
shell.openExternal('http://www.videolan.org/vlc/')
// TODO: dcposch send a dispatch rather than modifying state directly
const state = this.props.state

View File

@@ -1,5 +1,5 @@
const React = require('react')
const electron = require('electron')
const { shell } = require('electron')
const ModalOKCancel = require('./modal-ok-cancel')
const { dispatch } = require('../lib/dispatcher')
@@ -25,7 +25,7 @@ module.exports = class UpdateAvailableModal extends React.Component {
function handleShow () {
// TODO: use the GitHub urls from config.js
electron.shell.openExternal('https://github.com/webtorrent/webtorrent-desktop/releases')
shell.openExternal('https://github.com/webtorrent/webtorrent-desktop/releases')
dispatch('exitModal')
}

View File

@@ -0,0 +1,17 @@
const { dispatch } = require('../lib/dispatcher')
module.exports = class AudioTracksController {
constructor (state) {
this.state = state
}
selectAudioTrack (ix) {
this.state.playing.audioTracks.selectedIndex = ix
dispatch('skip', 0.2) // HACK: hardcoded seek value for smooth audio change
}
toggleAudioTracksMenu () {
const audioTracks = this.state.playing.audioTracks
audioTracks.showMenu = !audioTracks.showMenu
}
}

View File

@@ -26,7 +26,7 @@ module.exports = class MediaController {
ipcRenderer.once('checkForExternalPlayer', function (e, isInstalled) {
state.modal = {
id: 'unsupported-media-modal',
error: error,
error,
externalPlayerInstalled: isInstalled
}
})

View File

@@ -1,4 +1,4 @@
const electron = require('electron')
const { ipcRenderer } = require('electron')
const path = require('path')
const Cast = require('../lib/cast')
@@ -11,8 +11,6 @@ const TorrentSummary = require('../lib/torrent-summary')
const Playlist = require('../lib/playlist')
const State = require('../lib/state')
const ipcRenderer = electron.ipcRenderer
// Controls playback of torrents and files within torrents
// both local (<video>,<audio>,external player) and remote (cast)
module.exports = class PlaybackController {
@@ -61,12 +59,12 @@ module.exports = class PlaybackController {
}
// Open a file in OS default app.
openItem (infoHash, index) {
openPath (infoHash, index) {
const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
const filePath = path.join(
torrentSummary.path,
torrentSummary.files[index].path)
ipcRenderer.send('openItem', filePath)
ipcRenderer.send('openPath', filePath)
}
// Toggle (play or pause) the currently playing media
@@ -158,6 +156,20 @@ module.exports = class PlaybackController {
else this.state.playing.jumpToTime = time
}
// Show video preview
preview (x) {
if (!Number.isFinite(x)) {
console.error('Tried to preview a non-finite position ' + x)
return console.trace()
}
this.state.playing.previewXCoord = x
}
// Hide video preview
clearPreview () {
this.state.playing.previewXCoord = null
}
// Change playback speed. 1 = faster, -1 = slower
// Playback speed ranges from 16 (fast forward) to 1 (normal playback)
// to 0.25 (quarter-speed playback), then goes to -0.25, -0.5, -1, -2, etc
@@ -270,8 +282,10 @@ module.exports = class PlaybackController {
state.playing.infoHash = infoHash
state.playing.fileIndex = index
state.playing.fileName = fileSummary.name
state.playing.type = TorrentPlayer.isVideo(fileSummary) ? 'video'
: TorrentPlayer.isAudio(fileSummary) ? 'audio'
state.playing.type = TorrentPlayer.isVideo(fileSummary)
? 'video'
: TorrentPlayer.isAudio(fileSummary)
? 'audio'
: 'other'
// pick up where we left off

View File

@@ -1,5 +1,5 @@
const { dispatch } = require('../lib/dispatcher')
const ipcRenderer = require('electron').ipcRenderer
const { ipcRenderer } = require('electron')
// Controls the Preferences screen
module.exports = class PrefsController {

View File

@@ -1,10 +1,8 @@
const electron = require('electron')
const { remote } = require('electron')
const fs = require('fs')
const path = require('path')
const parallel = require('run-parallel')
const remote = electron.remote
const { dispatch } = require('../lib/dispatcher')
module.exports = class SubtitlesController {
@@ -13,14 +11,13 @@ module.exports = class SubtitlesController {
}
openSubtitles () {
remote.dialog.showOpenDialog({
const filenames = remote.dialog.showOpenDialogSync({
title: 'Select a subtitles file.',
filters: [{ name: 'Subtitles', extensions: ['vtt', 'srt'] }],
properties: ['openFile']
}, (filenames) => {
if (!Array.isArray(filenames)) return
this.addSubtitles(filenames, true)
})
if (!Array.isArray(filenames)) return
this.addSubtitles(filenames, true)
}
selectSubtitle (ix) {
@@ -110,7 +107,7 @@ function loadSubtitle (file, cb) {
buffer: 'data:text/vtt;base64,' + buf.toString('base64'),
language: langDetected,
label: langDetected,
filePath: filePath
filePath
}
cb(null, track)

View File

@@ -1,5 +1,5 @@
const path = require('path')
const ipcRenderer = require('electron').ipcRenderer
const { ipcRenderer } = require('electron')
const TorrentSummary = require('../lib/torrent-summary')
const sound = require('../lib/sound')
@@ -25,7 +25,7 @@ module.exports = class TorrentController {
}
torrentSummary = {
torrentKey: torrentKey,
torrentKey,
status: 'new'
}
torrents.unshift(torrentSummary)

View File

@@ -1,14 +1,12 @@
const fs = require('fs')
const path = require('path')
const electron = require('electron')
const { ipcRenderer, remote, clipboard } = require('electron')
const { dispatch } = require('../lib/dispatcher')
const { TorrentKeyNotFoundError } = require('../lib/errors')
const sound = require('../lib/sound')
const TorrentSummary = require('../lib/torrent-summary')
const ipcRenderer = electron.ipcRenderer
const instantIoRegex = /^(https:\/\/)?instant\.io\/#/
// Controls the torrent list: creating, adding, deleting, & manipulating torrents
@@ -55,7 +53,7 @@ module.exports = class TorrentListController {
if (files.length === 0 || typeof files[0] !== 'string') {
this.state.location.go({
url: 'create-torrent',
files: files,
files,
setup: (cb) => {
this.state.window.title = 'Create New Torrent'
cb(null)
@@ -160,7 +158,7 @@ module.exports = class TorrentListController {
.filter((torrent) => { // We're interested in active torrents only.
return (['downloading', 'seeding'].indexOf(torrent.status) !== -1)
})
.map((torrent) => { // Pause all active torrents except the one that started playing.
.forEach((torrent) => { // Pause all active torrents except the one that started playing.
if (infoHash === torrent.infoHash) return
// Pause torrent without playing sounds.
@@ -175,7 +173,7 @@ module.exports = class TorrentListController {
resumePausedTorrents () {
console.log('Playback Priority: resuming paused torrents')
if (!this.state.saved.torrentsToResume || !this.state.saved.torrentsToResume.length) return
this.state.saved.torrentsToResume.map((infoHash) => {
this.state.saved.torrentsToResume.forEach((infoHash) => {
this.toggleTorrent(infoHash)
})
@@ -201,26 +199,38 @@ module.exports = class TorrentListController {
}
}
confirmDeleteAllTorrents (deleteData) {
this.state.modal = {
id: 'delete-all-torrents-modal',
deleteData
}
}
// TODO: use torrentKey, not infoHash
deleteTorrent (infoHash, deleteData) {
ipcRenderer.send('wt-stop-torrenting', infoHash)
const index = this.state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
if (index > -1) {
const summary = this.state.saved.torrents[index]
// remove torrent and poster file
deleteFile(TorrentSummary.getTorrentPath(summary))
deleteFile(TorrentSummary.getPosterPath(summary))
// optionally delete the torrent data
if (deleteData) moveItemToTrash(summary)
deleteTorrentFile(summary, deleteData)
// remove torrent from saved list
this.state.saved.torrents.splice(index, 1)
dispatch('stateSave')
// prevent user from going forward to a deleted torrent
this.state.location.clearForward('player')
sound.play('DELETE')
} else {
throw new TorrentKeyNotFoundError(infoHash)
}
}
deleteAllTorrents (deleteData) {
this.state.saved.torrents.forEach((summary) => deleteTorrentFile(summary, deleteData))
this.state.saved.torrents = []
dispatch('stateSave')
// prevent user from going forward to a deleted torrent
this.state.location.clearForward('player')
@@ -237,77 +247,88 @@ module.exports = class TorrentListController {
openTorrentContextMenu (infoHash) {
const torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
const menu = new electron.remote.Menu()
const menu = new remote.Menu()
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
label: 'Remove From List',
click: () => dispatch('confirmDeleteTorrent', torrentSummary.infoHash, false)
}))
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
label: 'Remove Data File',
click: () => dispatch('confirmDeleteTorrent', torrentSummary.infoHash, true)
}))
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
type: 'separator'
}))
if (torrentSummary.files) {
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
label: process.platform === 'darwin' ? 'Show in Finder' : 'Show in Folder',
click: () => showItemInFolder(torrentSummary)
}))
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
type: 'separator'
}))
}
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
label: 'Copy Magnet Link to Clipboard',
click: () => electron.clipboard.writeText(torrentSummary.magnetURI)
click: () => clipboard.writeText(torrentSummary.magnetURI)
}))
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
label: 'Copy Instant.io Link to Clipboard',
click: () => electron.clipboard.writeText(`https://instant.io/#${torrentSummary.infoHash}`)
click: () => clipboard.writeText(`https://instant.io/#${torrentSummary.infoHash}`)
}))
menu.append(new electron.remote.MenuItem({
menu.append(new remote.MenuItem({
label: 'Save Torrent File As...',
click: () => dispatch('saveTorrentFileAs', torrentSummary.torrentKey),
enabled: torrentSummary.torrentFileName != null
}))
menu.popup(electron.remote.getCurrentWindow())
menu.append(new remote.MenuItem({
type: 'separator'
}))
const sortedByName = this.state.saved.prefs.sortByName
menu.append(new remote.MenuItem({
label: `${sortedByName ? '✓ ' : ''}Sort by Name`,
click: () => dispatch('updatePreferences', 'sortByName', !sortedByName)
}))
menu.popup({ window: remote.getCurrentWindow() })
}
// Takes a torrentSummary or torrentKey
// Shows a Save File dialog, then saves the .torrent file wherever the user requests
saveTorrentFileAs (torrentKey) {
const torrentSummary = TorrentSummary.getByKey(this.state, torrentKey)
if (!torrentSummary) throw new Error('Missing torrentKey: ' + torrentKey)
if (!torrentSummary) throw new TorrentKeyNotFoundError(torrentKey)
const downloadPath = this.state.saved.prefs.downloadPath
const newFileName = path.parse(torrentSummary.name).name + '.torrent'
const win = electron.remote.getCurrentWindow()
const win = remote.getCurrentWindow()
const opts = {
title: 'Save Torrent File',
defaultPath: path.join(downloadPath, newFileName),
filters: [
{ name: 'Torrent Files', extensions: ['torrent'] },
{ name: 'All Files', extensions: ['*'] }
]
],
buttonLabel: 'Save'
}
electron.remote.dialog.showSaveDialog(win, opts, function (savePath) {
console.log('Saving torrent ' + torrentKey + ' to ' + savePath)
if (!savePath) return // They clicked Cancel
const torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
fs.readFile(torrentPath, function (err, torrentFile) {
const savePath = remote.dialog.showSaveDialogSync(win, opts)
if (!savePath) return // They clicked Cancel
console.log('Saving torrent ' + torrentKey + ' to ' + savePath)
const torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
fs.readFile(torrentPath, function (err, torrentFile) {
if (err) return dispatch('error', err)
fs.writeFile(savePath, torrentFile, function (err) {
if (err) return dispatch('error', err)
fs.writeFile(savePath, torrentFile, function (err) {
if (err) return dispatch('error', err)
})
})
})
}
@@ -323,7 +344,7 @@ function findFilesRecursive (paths, cb_) {
findFilesRecursive([path], function (fileObjs) {
ret.push(...fileObjs)
if (++numComplete === paths.length) {
ret.sort((a, b) => a.path < b.path ? -1 : a.path > b.path)
ret.sort((a, b) => a.path < b.path ? -1 : Number(a.path > b.path))
cb_(ret)
}
})
@@ -371,3 +392,14 @@ function moveItemToTrash (torrentSummary) {
function showItemInFolder (torrentSummary) {
ipcRenderer.send('showItemInFolder', TorrentSummary.getFileOrFolder(torrentSummary))
}
function deleteTorrentFile (torrentSummary, deleteData) {
ipcRenderer.send('wt-stop-torrenting', torrentSummary.infoHash)
// remove torrent and poster file
deleteFile(TorrentSummary.getTorrentPath(torrentSummary))
deleteFile(TorrentSummary.getPosterPath(torrentSummary))
// optionally delete the torrent data
if (deleteData) moveItemToTrash(torrentSummary)
}

View File

@@ -13,7 +13,7 @@ module.exports = class UpdateController {
console.log('new version skipped by user: v' + version)
return
}
this.state.modal = { id: 'update-available-modal', version: version }
this.state.modal = { id: 'update-available-modal', version }
}
// Don't show the modal again until the next version

View File

@@ -1,11 +1,11 @@
const mediaExtensions = {
audio: [
'.aac', '.aif', '.aiff', '.asf', '.dff', '.dsf', '.flac', '.m2a',
'.m4a', '.m4b', '.mp2', '.mp3', '.mpc', '.oga', '.ogg', '.opus',
'.spx', '.wma', '.wav', '.wv', '.wvp'],
'.m2a', '.m4a', '.mpc', '.m4b', '.mka', '.mp2', '.mp3', '.mpc', '.oga',
'.ogg', '.opus', '.spx', '.wma', '.wav', '.wv', '.wvp'],
video: [
'.avi', '.mp4', '.m4v', '.webm', '.mov', '.mkv', '.mpg', '.mpeg',
'.ogv', '.webm', '.wmv'],
'.ogv', '.webm', '.wmv', '.m2ts'],
image: ['.gif', '.jpg', '.jpeg', '.png']
}

View File

@@ -29,13 +29,14 @@ function run (state) {
if (semver.lt(version, '0.17.0')) migrate_0_17_0(saved)
if (semver.lt(version, '0.17.2')) migrate_0_17_2(saved)
if (semver.lt(version, '0.21.0')) migrate_0_21_0(saved)
if (semver.lt(version, '0.22.0')) migrate_0_22_0(saved)
// Config is now on the new version
state.saved.version = config.APP_VERSION
}
function migrate_0_7_0 (saved) {
const cpFile = require('cp-file')
const { copyFileSync } = require('fs')
const path = require('path')
saved.torrents.forEach(function (ts) {
@@ -57,7 +58,7 @@ function migrate_0_7_0 (saved) {
dst = path.join(config.TORRENT_PATH, infoHash + '.torrent')
// Synchronous FS calls aren't ideal, but probably OK in a migration
// that only runs once
if (src !== dst) cpFile.sync(src, dst)
if (src !== dst) copyFileSync(src, dst)
delete ts.torrentPath
ts.torrentFileName = infoHash + '.torrent'
@@ -72,7 +73,7 @@ function migrate_0_7_0 (saved) {
dst = path.join(config.POSTER_PATH, infoHash + extension)
// Synchronous FS calls aren't ideal, but probably OK in a migration
// that only runs once
if (src !== dst) cpFile.sync(src, dst)
if (src !== dst) copyFileSync(src, dst)
delete ts.posterURL
ts.posterFileName = infoHash + extension
@@ -156,7 +157,7 @@ function migrate_0_17_2 (saved) {
// folders/files that end in a trailing dot (.) or space are not deletable from
// Windows Explorer. See: https://github.com/webtorrent/webtorrent-desktop/issues/905
const cpFile = require('cp-file')
const { copyFileSync } = require('fs')
const rimraf = require('rimraf')
const OLD_NAME = 'The WIRED CD - Rip. Sample. Mash. Share.'
@@ -191,7 +192,7 @@ function migrate_0_17_2 (saved) {
ts.posterFileName = NEW_HASH + '.jpg'
rimraf.sync(path.join(config.TORRENT_PATH, ts.torrentFileName))
cpFile.sync(
copyFileSync(
path.join(config.STATIC_PATH, 'wiredCd.torrent'),
path.join(config.TORRENT_PATH, NEW_HASH + '.torrent')
)
@@ -214,3 +215,9 @@ function migrate_0_21_0 (saved) {
saved.prefs.soundNotifications = true
}
}
function migrate_0_22_0 (saved) {
if (saved.prefs.externalPlayerPath == null) {
saved.prefs.externalPlayerPath = ''
}
}

View File

@@ -105,14 +105,18 @@ function getDefaultPlayState () {
selectedIndex: -1, /* current subtitle track */
showMenu: false /* popover menu, above the video */
},
audioTracks: {
tracks: [],
selectedIndex: 0, /* current audio track */
showMenu: false /* popover menu, above the video */
},
aspectRatio: 0 /* aspect ratio of the video */
}
}
/* If the saved state file doesn't exist yet, here's what we use instead */
function setupStateSaved (cb) {
const cpFile = require('cp-file')
const fs = require('fs')
function setupStateSaved () {
const { copyFileSync, mkdirSync, readFileSync } = require('fs')
const parseTorrent = require('parse-torrent')
const saved = {
@@ -120,7 +124,7 @@ function setupStateSaved (cb) {
downloadPath: config.DEFAULT_DOWNLOAD_PATH,
isFileHandler: false,
openExternalPlayer: false,
externalPlayerPath: null,
externalPlayerPath: '',
startup: false,
soundNotifications: true,
autoAddTorrents: false,
@@ -132,33 +136,28 @@ function setupStateSaved (cb) {
version: config.APP_VERSION /* make sure we can upgrade gracefully later */
}
const tasks = []
// TODO: Doing several sync calls during first startup is not ideal
mkdirSync(config.POSTER_PATH, { recursive: true })
mkdirSync(config.TORRENT_PATH, { recursive: true })
config.DEFAULT_TORRENTS.forEach((t, i) => {
const infoHash = saved.torrents[i].infoHash
tasks.push(
cpFile(
path.join(config.STATIC_PATH, t.posterFileName),
path.join(config.POSTER_PATH, infoHash + path.extname(t.posterFileName))
)
// TODO: Doing several sync calls during first startup is not ideal
copyFileSync(
path.join(config.STATIC_PATH, t.posterFileName),
path.join(config.POSTER_PATH, infoHash + path.extname(t.posterFileName))
)
tasks.push(
cpFile(
path.join(config.STATIC_PATH, t.torrentFileName),
path.join(config.TORRENT_PATH, infoHash + '.torrent')
)
copyFileSync(
path.join(config.STATIC_PATH, t.torrentFileName),
path.join(config.TORRENT_PATH, infoHash + '.torrent')
)
})
Promise.all(tasks)
.then(
() => cb(null, saved),
err => cb(err)
)
return saved
function createTorrentObject (t) {
// TODO: Doing several fs.readFileSync calls during first startup is not ideal
const torrent = fs.readFileSync(path.join(config.STATIC_PATH, t.torrentFileName))
// TODO: Doing several sync calls during first startup is not ideal
const torrent = readFileSync(path.join(config.STATIC_PATH, t.torrentFileName))
const parsedTorrent = parseTorrent(torrent)
return {
@@ -203,15 +202,20 @@ function shouldHidePlayerControls () {
this.playing.playbackRate === 1
}
function load (cb) {
appConfig.read(function (err, saved) {
if (err || !saved.version) {
console.log('Missing config file: Creating new one')
setupStateSaved(onSavedState)
} else {
onSavedState(null, saved)
async function load (cb) {
let saved = await appConfig.read()
if (!saved || !saved.version) {
console.log('Missing config file: Creating new one')
try {
saved = setupStateSaved()
} catch (err) {
onSavedState(err)
return
}
})
}
onSavedState(null, saved)
function onSavedState (err, saved) {
if (err) return cb(err)
@@ -229,7 +233,7 @@ function load (cb) {
}
// Write state.saved to the JSON state file
function saveImmediate (state, cb) {
async function saveImmediate (state, cb) {
console.log('Saving state to ' + appConfig.filePath)
// Clean up, so that we're not saving any pending state
@@ -252,8 +256,10 @@ function saveImmediate (state, cb) {
return torrent
})
appConfig.write(copy, (err) => {
if (err) console.error(err)
else State.emit('stateSaved')
})
try {
await appConfig.write(copy)
State.emit('stateSaved')
} catch (err) {
console.error(err)
}
}

View File

@@ -7,7 +7,7 @@ module.exports = {
logPlayAttempt
}
const electron = require('electron')
const { remote } = require('electron')
const config = require('../../config')
@@ -74,7 +74,7 @@ function reset () {
// Track screen resolution
function getScreenInfo () {
return electron.remote.screen.getAllDisplays().map((screen) => ({
return remote.screen.getAllDisplays().map((screen) => ({
width: screen.size.width,
height: screen.size.height,
scaleFactor: screen.scaleFactor

View File

@@ -74,7 +74,7 @@ function getLargestFileByExtension (torrent, extensions) {
* Filter file on a list extension, can be used to find al image files
* @param torrent Torrent to filter files from
* @param extensions File extensions to filter on
* @returns {number} Array of torrent file objects matching one of the given extensions
* @returns {Array} Array of torrent file objects matching one of the given extensions
*/
function filterOnExtension (torrent, extensions) {
return torrent.files.filter(file => {
@@ -117,7 +117,7 @@ function torrentPosterFromAudio (torrent, cb) {
const bestCover = imageFiles.map(file => {
return {
file: file,
file,
score: scoreAudioCoverFile(file)
}
}).reduce((a, b) => {
@@ -166,7 +166,8 @@ function torrentPosterFromVideo (torrent, cb) {
function onSeeked () {
video.removeEventListener('seeked', onSeeked)
const buf = captureFrame(video)
const frame = captureFrame(video)
const buf = frame && frame.image
// unload video element
video.pause()

View File

@@ -14,9 +14,6 @@ Module.prototype.require = function (id) {
console.time('init')
const crashReporter = require('../crash-reporter')
crashReporter.init()
// Perf optimization: Start asynchronously read on config file before all the
// blocking require() calls below.
@@ -99,6 +96,10 @@ function onState (err, _state) {
const SubtitlesController = require('./controllers/subtitles-controller')
return new SubtitlesController(state)
}),
audioTracks: createGetter(() => {
const AudioTracksController = require('./controllers/audio-tracks-controller')
return new AudioTracksController(state)
}),
torrent: createGetter(() => {
const TorrentController = require('./controllers/torrent-controller')
return new TorrentController(state)
@@ -129,7 +130,10 @@ function onState (err, _state) {
resumeTorrents()
// Initialize ReactDOM
app = ReactDOM.render(<App state={state} />, document.querySelector('#body'))
ReactDOM.render(
<App state={state} ref={elem => { app = elem }} />,
document.querySelector('#body')
)
// Calling update() updates the UI given the current state
// Do this at least once a second to give every file in every torrentSummary
@@ -251,6 +255,10 @@ const dispatchHandlers = {
controllers.torrentList().confirmDeleteTorrent(infoHash, deleteData),
deleteTorrent: (infoHash, deleteData) =>
controllers.torrentList().deleteTorrent(infoHash, deleteData),
confirmDeleteAllTorrents: (deleteData) =>
controllers.torrentList().confirmDeleteAllTorrents(deleteData),
deleteAllTorrents: (deleteData) =>
controllers.torrentList().deleteAllTorrents(deleteData),
toggleSelectTorrent: (infoHash) =>
controllers.torrentList().toggleSelectTorrent(infoHash),
openTorrentContextMenu: (infoHash) =>
@@ -269,10 +277,12 @@ const dispatchHandlers = {
previousTrack: () => controllers.playback().previousTrack(),
skip: (time) => controllers.playback().skip(time),
skipTo: (time) => controllers.playback().skipTo(time),
preview: (x) => controllers.playback().preview(x),
clearPreview: () => controllers.playback().clearPreview(),
changePlaybackRate: (dir) => controllers.playback().changePlaybackRate(dir),
changeVolume: (delta) => controllers.playback().changeVolume(delta),
setVolume: (vol) => controllers.playback().setVolume(vol),
openItem: (infoHash, index) => controllers.playback().openItem(infoHash, index),
openPath: (infoHash, index) => controllers.playback().openPath(infoHash, index),
// Subtitles
openSubtitles: () => controllers.subtitles().openSubtitles(),
@@ -281,6 +291,10 @@ const dispatchHandlers = {
checkForSubtitles: () => controllers.subtitles().checkForSubtitles(),
addSubtitles: (files, autoSelect) => controllers.subtitles().addSubtitles(files, autoSelect),
// Audio Tracks
selectAudioTrack: (index) => controllers.audioTracks().selectAudioTrack(index),
toggleAudioTracksMenu: () => controllers.audioTracks().toggleAudioTracksMenu(),
// Local media: <video>, <audio>, external players
mediaStalled: () => controllers.media().mediaStalled(),
mediaError: (err) => controllers.media().mediaError(err),
@@ -300,7 +314,7 @@ const dispatchHandlers = {
// Preferences screen
preferences: () => controllers.prefs().show(),
updatePreferences: (key, value) => controllers.prefs().update(key, value),
checkDownloadPath: checkDownloadPath,
checkDownloadPath,
startFolderWatcher: () => controllers.folderWatcher().start(),
stopFolderWatcher: () => controllers.folderWatcher().stop(),
@@ -310,20 +324,20 @@ const dispatchHandlers = {
// Navigation between screens (back, forward, ESC, etc)
exitModal: () => { state.modal = null },
backToList: backToList,
escapeBack: escapeBack,
backToList,
escapeBack,
back: () => state.location.back(),
forward: () => state.location.forward(),
cancel: () => state.location.cancel(),
// Controlling the window
setDimensions: setDimensions,
setDimensions,
toggleFullScreen: (setTo) => ipcRenderer.send('toggleFullScreen', setTo),
setTitle: (title) => { state.window.title = title },
resetTitle: () => { state.window.title = config.APP_WINDOW_TITLE },
// Everything else
onOpen: onOpen,
onOpen,
error: onError,
uncaughtError: (proc, err) => telemetry.logUncaughtError(proc, err),
stateSave: () => State.save(state),
@@ -512,6 +526,9 @@ function onPaste (e) {
}
function onKeydown (e) {
// prevent event fire on user input elements
if (editableHtmlTags.has(e.target.tagName.toLowerCase())) return
const key = e.key
if (key === 'ArrowLeft') {
@@ -551,7 +568,7 @@ function onBlur () {
}
function onVisibilityChange () {
state.window.isVisible = !document.webkitHidden
state.window.isVisible = !document.hidden
}
function onFullscreenChanged (e, isFullScreen) {

View File

@@ -24,7 +24,9 @@ const Modals = {
),
'remove-torrent-modal': createGetter(() => require('../components/remove-torrent-modal')),
'update-available-modal': createGetter(() => require('../components/update-available-modal')),
'unsupported-media-modal': createGetter(() => require('../components/unsupported-media-modal'))
'unsupported-media-modal': createGetter(() => require('../components/unsupported-media-modal')),
'delete-all-torrents-modal':
createGetter(() => require('../components/delete-all-torrents-modal'))
}
const fontFamily = process.platform === 'win32'

View File

@@ -1,7 +1,5 @@
/* global HTMLMediaElement */
const React = require('react')
const Bitfield = require('bitfield')
const BitField = require('bitfield').default
const prettyBytes = require('prettier-bytes')
const TorrentSummary = require('../lib/torrent-summary')
@@ -97,6 +95,13 @@ function renderMedia (state) {
delete file.selectedSubtitle
}
// Switch to selected audio track
const audioTracks = mediaElement.audioTracks || []
for (let j = 0; j < audioTracks.length; j++) {
const isSelectedTrack = j === state.playing.audioTracks.selectedIndex
audioTracks[j].enabled = isSelectedTrack
}
state.playing.volume = mediaElement.volume
}
@@ -109,9 +114,9 @@ function renderMedia (state) {
trackTags.push(
<track
key={i}
default={isSelected ? 'default' : ''}
default={isSelected}
label={track.label}
type='subtitles'
kind='subtitles'
src={track.buffer}
/>
)
@@ -130,7 +135,6 @@ function renderMedia (state) {
onError={dispatcher('mediaError')}
onTimeUpdate={dispatcher('mediaTimeUpdate')}
onEncrypted={dispatcher('mediaEncrypted')}
onCanPlay={onCanPlay}
>
{trackTags}
</MediaTagName>
@@ -148,15 +152,50 @@ function renderMedia (state) {
</div>
)
// As soon as we know the video dimensions, resize the window
function onLoadedMetadata (e) {
if (state.playing.type !== 'video') return
const video = e.target
const dimensions = {
width: video.videoWidth,
height: video.videoHeight
const mediaElement = e.target
// check if we can decode video and audio track
if (state.playing.type === 'video') {
if (mediaElement.videoTracks.length === 0) {
dispatch('mediaError', 'Video codec unsupported')
}
if (mediaElement.audioTracks.length === 0) {
dispatch('mediaError', 'Audio codec unsupported')
}
dispatch('mediaSuccess')
const dimensions = {
width: mediaElement.videoWidth,
height: mediaElement.videoHeight
}
// As soon as we know the video dimensions, resize the window
dispatch('setDimensions', dimensions)
// set audioTracks
const tracks = []
for (let i = 0; i < mediaElement.audioTracks.length; i++) {
tracks.push({
label: mediaElement.audioTracks[i].label || `Track ${i + 1}`,
language: mediaElement.audioTracks[i].language
})
}
state.playing.audioTracks.tracks = tracks
state.playing.audioTracks.selectedIndex = 0
}
// check if we can decode audio track
if (state.playing.type === 'audio') {
if (mediaElement.audioTracks.length === 0) {
dispatch('mediaError', 'Audio codec unsupported')
}
dispatch('mediaSuccess')
}
dispatch('setDimensions', dimensions)
}
function onEnded (e) {
@@ -168,20 +207,6 @@ function renderMedia (state) {
if (state.window.isFullScreen) dispatch('toggleFullScreen')
}
}
function onCanPlay (e) {
const elem = e.target
if (elem.readyState < HTMLMediaElement.HAVE_FUTURE_DATA) return
if (state.playing.type === 'video' &&
elem.webkitVideoDecodedByteCount === 0) {
dispatch('mediaError', 'Video codec unsupported')
} else if (elem.webkitAudioDecodedByteCount === 0) {
dispatch('mediaError', 'Audio codec unsupported')
} else {
dispatch('mediaSuccess')
elem.play()
}
}
}
function renderOverlay (state) {
@@ -402,22 +427,77 @@ function renderCastScreen (state) {
const isStarting = state.playing.location.endsWith('-pending')
const castName = state.playing.castName
const fileName = state.getPlayingFileSummary().name || ''
let castStatus
if (isCast && isStarting) castStatus = 'Connecting to ' + castName + '...'
else if (isCast && !isStarting) castStatus = 'Connected to ' + castName
else castStatus = ''
const prog = state.getPlayingTorrentSummary().progress || {}
// Show a nice title image, if possible
const style = {
backgroundImage: cssBackgroundImagePoster(state)
}
function renderEta (total, downloaded) {
const missing = (total || 0) - (downloaded || 0)
const downloadSpeed = prog.downloadSpeed || 0
if (downloadSpeed === 0 || missing === 0) return
const rawEta = missing / downloadSpeed
const hours = Math.floor(rawEta / 3600) % 24
const minutes = Math.floor(rawEta / 60) % 60
const seconds = Math.floor(rawEta % 60)
const hoursStr = hours ? hours + 'h' : ''
const minutesStr = (hours || minutes) ? minutes + 'm' : ''
const secondsStr = seconds + 's'
return (<span>{hoursStr} {minutesStr} {secondsStr} remaining</span>)
}
function renderDownloadProgress () {
if (!prog.files) return
const fileProg = prog.files[state.playing.fileIndex]
const fileProgress = fileProg.numPiecesPresent / fileProg.numPieces
const fileLength = state.getPlayingFileSummary().length
const fileDownloaded = fileProgress * fileLength
const progress = Math.round(100 * fileProgress)
const total = prettyBytes(fileLength)
const completed = prettyBytes(fileDownloaded)
const downloadSpeed = prettyBytes(prog.downloadSpeed || 0)
const uploadSpeed = prettyBytes(prog.uploadSpeed || 0)
let sizes
if (fileProgress < 1) {
sizes = <span> | {completed} / {total}</span>
} else {
sizes = <span> | {completed}</span>
}
return (
<div key='download-progress'>
<span className='progress'>{progress}% downloaded {sizes}</span>
<br />
<span>↓ {downloadSpeed}/s ↑ {uploadSpeed}/s | {prog.numPeers || 0} peer(s)</span>
<br />
{renderEta(fileLength, fileDownloaded)}
</div>
)
}
return (
<div key='cast' className='letterbox' style={style}>
<div className='cast-screen'>
<i className='icon'>{castIcon}</i>
<div key='type' className='cast-type'>{castType}</div>
<div key='status' className='cast-status'>{castStatus}</div>
<div key='name' className='name'>{fileName}</div>
{renderDownloadProgress()}
</div>
</div>
)
@@ -475,6 +555,27 @@ function renderSubtitleOptions (state) {
)
}
function renderAudioTrackOptions (state) {
const audioTracks = state.playing.audioTracks
if (!audioTracks.tracks.length || !audioTracks.showMenu) return
const items = audioTracks.tracks.map(function (track, ix) {
const isSelected = state.playing.audioTracks.selectedIndex === ix
return (
<li key={ix} onClick={dispatcher('selectAudioTrack', ix)}>
<i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
{track.label}
</li>
)
})
return (
<ul key='audio-track-options' className='options-list'>
{items}
</ul>
)
}
function renderPlayerControls (state) {
const positionPercent = 100 * state.playing.currentTime / state.playing.duration
const playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 3px)' }
@@ -483,10 +584,15 @@ function renderPlayerControls (state) {
: state.playing.subtitles.selectedIndex >= 0
? 'active'
: ''
const multiAudioClass = state.playing.audioTracks.tracks.length > 1
? 'active'
: 'disabled'
const prevClass = Playlist.hasPrevious(state) ? '' : 'disabled'
const nextClass = Playlist.hasNext(state) ? '' : 'disabled'
const elements = [
renderPreview(state),
<div key='playback-bar' className='playback-bar'>
{renderLoadingBar(state)}
<div
@@ -497,7 +603,9 @@ function renderPlayerControls (state) {
<div
key='scrub-bar'
className='scrub-bar'
draggable='true'
draggable
onMouseMove={handleScrubPreview}
onMouseOut={clearPreview}
onDragStart={handleDragStart}
onClick={handleScrub}
onDrag={handleScrub}
@@ -547,6 +655,14 @@ function renderPlayerControls (state) {
>
closed_caption
</i>
), (
<i
key='audio-tracks'
className={'icon multi-audio float-right ' + multiAudioClass}
onClick={handleAudioTracks}
>
library_music
</i>
))
}
@@ -598,10 +714,14 @@ function renderPlayerControls (state) {
// Render volume slider
const volume = state.playing.volume
const volumeIcon = 'volume_' + (
volume === 0 ? 'off'
: volume < 0.3 ? 'mute'
: volume < 0.6 ? 'down'
: 'up')
volume === 0
? 'off'
: volume < 0.3
? 'mute'
: volume < 0.6
? 'down'
: 'up'
)
const volumeStyle = {
background: '-webkit-gradient(linear, left top, right top, ' +
'color-stop(' + (volume * 100) + '%, #eee), ' +
@@ -653,6 +773,7 @@ function renderPlayerControls (state) {
{elements}
{renderCastOptions(state)}
{renderSubtitleOptions(state)}
{renderAudioTrackOptions(state)}
</div>
)
@@ -664,6 +785,19 @@ function renderPlayerControls (state) {
}
}
// Handles a scrub hover (preview another position in the video)
function handleScrubPreview (e) {
// Only show for videos
if (!e.clientX || state.playing.type !== 'video') return
dispatch('mediaMouseMoved')
dispatch('preview', e.clientX)
}
function clearPreview (e) {
if (state.playing.type !== 'video') return
dispatch('clearPreview')
}
// Handles a click or drag to scrub (jump to another position in the video)
function handleScrub (e) {
if (!e.clientX) return
@@ -696,6 +830,60 @@ function renderPlayerControls (state) {
dispatch('toggleSubtitlesMenu')
}
}
function handleAudioTracks (e) {
dispatch('toggleAudioTracksMenu')
}
}
function renderPreview (state) {
const { previewXCoord = null } = state.playing
// Calculate time from x-coord as fraction of track width
const windowWidth = document.querySelector('body').clientWidth
const fraction = previewXCoord / windowWidth
const time = fraction * state.playing.duration /* seconds */
const height = 70
let width = 0
const previewEl = document.querySelector('video#preview')
if (previewEl !== null && previewXCoord !== null) {
previewEl.currentTime = time
// Auto adjust width to maintain video aspect ratio
width = Math.floor((previewEl.videoWidth / previewEl.videoHeight) * height)
}
// Center preview window on mouse cursor,
// while avoiding falling off the left or right edges
const xPos = Math.min(Math.max(previewXCoord - (width / 2), 5), windowWidth - width - 5)
return (
<div
key='preview' style={{
position: 'absolute',
bottom: 50,
left: xPos,
display: previewXCoord == null && 'none' // Hide preview when XCoord unset
}}
>
<div style={{ width, height, backgroundColor: 'black' }}>
<video
src={Playlist.getCurrentLocalURL(state)}
id='preview'
style={{ border: '1px solid lightgrey', borderRadius: 2 }}
/>
</div>
<p
style={{
textAlign: 'center', margin: 5, textShadow: '0 0 2px rgba(0,0,0,.5)', color: '#eee'
}}
>
{formatTime(time, state.playing.duration)}
</p>
</div>
)
}
// Renders the loading bar. Shows which parts of the torrent are loaded, which
@@ -717,7 +905,7 @@ function renderLoadingBar (state) {
const parts = []
let lastPiecePresent = false
for (let i = fileProg.startPiece; i <= fileProg.endPiece; i++) {
const partPresent = Bitfield.prototype.get.call(prog.bitfield, i)
const partPresent = BitField.prototype.get.call(prog.bitfield, i)
if (partPresent && !lastPiecePresent) {
parts.push({ start: i - fileProg.startPiece, count: 1 })
} else if (partPresent) {

View File

@@ -212,7 +212,9 @@ module.exports = class TorrentList extends React.Component {
else if (torrentSummary.progress.progress === 1) status = 'Not seeding'
else status = 'Paused'
} else if (torrentSummary.status === 'downloading') {
status = 'Downloading'
if (!torrentSummary.progress) status = ''
else if (!torrentSummary.progress.ready) status = 'Verifying'
else status = 'Downloading'
} else if (torrentSummary.status === 'seeding') {
status = 'Seeding'
} else { // torrentSummary.status is 'new' or something unexpected
@@ -282,10 +284,17 @@ module.exports = class TorrentList extends React.Component {
)
} else {
// We do know the files. List them and show download stats for each one
const fileRows = torrentSummary.files
const sortByName = this.props.state.saved.prefs.sortByName
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' })
let fileRows = torrentSummary.files
.filter((file) => !file.path.includes('/.____padding_file/'))
.map((file, index) => ({ file, index }))
.map((object) => this.renderFileRow(torrentSummary, object.file, object.index))
if (sortByName) {
fileRows = fileRows.sort((a, b) => collator.compare(a.file.name, b.file.name))
}
fileRows = fileRows.map((obj) => this.renderFileRow(torrentSummary, obj.file, obj.index))
filesElement = (
<div key='files' className='files'>
@@ -316,7 +325,7 @@ module.exports = class TorrentList extends React.Component {
torrentSummary.progress.files[index]) {
const fileProg = torrentSummary.progress.files[index]
isDone = fileProg.numPiecesPresent === fileProg.numPieces
progress = Math.round(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%'
progress = Math.floor(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%'
}
// Second, for media files where we saved our position, show how far we got
@@ -337,7 +346,7 @@ module.exports = class TorrentList extends React.Component {
} else {
icon = 'description' /* file icon, opens in OS default app */
handleClick = isDone
? dispatcher('openItem', infoHash, index)
? dispatcher('openPath', infoHash, index)
: (e) => e.stopPropagation() // noop if file is not ready
}
// TODO: add a css 'disabled' class to indicate that a file cannot be opened/streamed

View File

@@ -3,27 +3,19 @@
console.time('init')
const crypto = require('crypto')
const deepEqual = require('deep-equal')
const util = require('util')
const defaultAnnounceList = require('create-torrent').announceList
const electron = require('electron')
const { ipcRenderer } = require('electron')
const fs = require('fs')
const mkdirp = require('mkdirp')
const mm = require('music-metadata')
const networkAddress = require('network-address')
const path = require('path')
const WebTorrent = require('webtorrent')
const crashReporter = require('../crash-reporter')
const config = require('../config')
const { TorrentKeyNotFoundError } = require('./lib/errors')
const torrentPoster = require('./lib/torrent-poster')
// Report when the process crashes
crashReporter.init()
// Send & receive messages from the main window
const ipc = electron.ipcRenderer
// Force use of webtorrent trackers on all torrents
global.WEBTORRENT_ANNOUNCE = defaultAnnounceList
.map((arr) => arr[0])
@@ -60,7 +52,7 @@ const PEER_ID = Buffer.from(VERSION_PREFIX + crypto.randomBytes(9).toString('bas
// Connect to the WebTorrent and BitTorrent networks. WebTorrent Desktop is a hybrid
// client, as explained here: https://webtorrent.io/faq
let client = window.client = new WebTorrent({ peerId: PEER_ID })
let client = window.client = new WebTorrent({ peerId: PEER_ID, utp: true })
// WebTorrent-to-HTTP streaming sever
let server = null
@@ -73,29 +65,29 @@ init()
function init () {
listenToClientEvents()
ipc.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))
ipc.on('wt-stop-torrenting', (e, infoHash) =>
ipcRenderer.on('wt-stop-torrenting', (e, infoHash) =>
stopTorrenting(infoHash))
ipc.on('wt-create-torrent', (e, torrentKey, options) =>
ipcRenderer.on('wt-create-torrent', (e, torrentKey, options) =>
createTorrent(torrentKey, options))
ipc.on('wt-save-torrent-file', (e, torrentKey) =>
ipcRenderer.on('wt-save-torrent-file', (e, torrentKey) =>
saveTorrentFile(torrentKey))
ipc.on('wt-generate-torrent-poster', (e, torrentKey) =>
ipcRenderer.on('wt-generate-torrent-poster', (e, torrentKey) =>
generateTorrentPoster(torrentKey))
ipc.on('wt-get-audio-metadata', (e, infoHash, index) =>
ipcRenderer.on('wt-get-audio-metadata', (e, infoHash, index) =>
getAudioMetadata(infoHash, index))
ipc.on('wt-start-server', (e, infoHash) =>
ipcRenderer.on('wt-start-server', (e, infoHash) =>
startServer(infoHash))
ipc.on('wt-stop-server', (e) =>
ipcRenderer.on('wt-stop-server', (e) =>
stopServer())
ipc.on('wt-select-files', (e, infoHash, selections) =>
ipcRenderer.on('wt-select-files', (e, infoHash, selections) =>
selectFiles(infoHash, selections))
ipc.send('ipcReadyWebTorrent')
ipcRenderer.send('ipcReadyWebTorrent')
window.addEventListener('error', (e) =>
ipc.send('wt-uncaught-error', { message: e.error.message, stack: e.error.stack }),
ipcRenderer.send('wt-uncaught-error', { message: e.error.message, stack: e.error.stack }),
true)
setInterval(updateTorrentProgress, 1000)
@@ -103,8 +95,8 @@ function init () {
}
function listenToClientEvents () {
client.on('warning', (err) => ipc.send('wt-warning', null, err.message))
client.on('error', (err) => ipc.send('wt-error', null, err.message))
client.on('warning', (err) => ipcRenderer.send('wt-warning', null, err.message))
client.on('error', (err) => ipcRenderer.send('wt-error', null, err.message))
}
// Starts a given TorrentID, which can be an infohash, magnet URI, etc.
@@ -113,8 +105,8 @@ function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections)
console.log('starting torrent %s: %s', torrentKey, torrentID)
const torrent = client.add(torrentID, {
path: path,
fileModtimes: fileModtimes
path,
fileModtimes
})
torrent.key = torrentKey
@@ -138,44 +130,44 @@ function createTorrent (torrentKey, options) {
const torrent = client.seed(paths, options)
torrent.key = torrentKey
addTorrentEvents(torrent)
ipc.send('wt-new-torrent')
ipcRenderer.send('wt-new-torrent')
}
function addTorrentEvents (torrent) {
torrent.on('warning', (err) =>
ipc.send('wt-warning', torrent.key, err.message))
ipcRenderer.send('wt-warning', torrent.key, err.message))
torrent.on('error', (err) =>
ipc.send('wt-error', torrent.key, err.message))
ipcRenderer.send('wt-error', torrent.key, err.message))
torrent.on('infoHash', () =>
ipc.send('wt-parsed', torrent.key, torrent.infoHash, torrent.magnetURI))
ipcRenderer.send('wt-parsed', torrent.key, torrent.infoHash, torrent.magnetURI))
torrent.on('metadata', torrentMetadata)
torrent.on('ready', torrentReady)
torrent.on('done', torrentDone)
function torrentMetadata () {
const info = getTorrentInfo(torrent)
ipc.send('wt-metadata', torrent.key, info)
ipcRenderer.send('wt-metadata', torrent.key, info)
updateTorrentProgress()
}
function torrentReady () {
const info = getTorrentInfo(torrent)
ipc.send('wt-ready', torrent.key, info)
ipc.send('wt-ready-' + torrent.infoHash, torrent.key, info)
ipcRenderer.send('wt-ready', torrent.key, info)
ipcRenderer.send('wt-ready-' + torrent.infoHash, torrent.key, info)
updateTorrentProgress()
}
function torrentDone () {
const info = getTorrentInfo(torrent)
ipc.send('wt-done', torrent.key, info)
ipcRenderer.send('wt-done', torrent.key, info)
updateTorrentProgress()
torrent.getFileModtimes(function (err, fileModtimes) {
if (err) return onError(err)
ipc.send('wt-file-modtimes', torrent.key, fileModtimes)
ipcRenderer.send('wt-file-modtimes', torrent.key, fileModtimes)
})
}
}
@@ -212,15 +204,15 @@ function saveTorrentFile (torrentKey) {
const fileName = torrent.infoHash + '.torrent'
if (!err) {
// We've already saved the file
return ipc.send('wt-file-saved', torrentKey, fileName)
return ipcRenderer.send('wt-file-saved', torrentKey, fileName)
}
// Otherwise, save the .torrent file, under the app config folder
mkdirp(config.TORRENT_PATH, function (_) {
fs.mkdir(config.TORRENT_PATH, { recursive: true }, function (_) {
fs.writeFile(torrentPath, torrent.torrentFile, function (err) {
if (err) return console.log('error saving torrent file %s: %o', torrentPath, err)
console.log('saved torrent file %s', torrentPath)
return ipc.send('wt-file-saved', torrentKey, fileName)
return ipcRenderer.send('wt-file-saved', torrentKey, fileName)
})
})
})
@@ -233,14 +225,14 @@ function generateTorrentPoster (torrentKey) {
torrentPoster(torrent, function (err, buf, extension) {
if (err) return console.log('error generating poster: %o', err)
// save it for next time
mkdirp(config.POSTER_PATH, function (err) {
fs.mkdir(config.POSTER_PATH, { recursive: true }, function (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) {
if (err) return console.log('error saving poster: %o', err)
// show the poster
ipc.send('wt-poster', torrentKey, posterFileName)
ipcRenderer.send('wt-poster', torrentKey, posterFileName)
})
})
})
@@ -249,10 +241,10 @@ function generateTorrentPoster (torrentKey) {
function updateTorrentProgress () {
const progress = getTorrentProgress()
// TODO: diff torrent-by-torrent, not once for the whole update
if (prevProgress && deepEqual(progress, prevProgress, { strict: true })) {
if (prevProgress && util.isDeepStrictEqual(progress, prevProgress)) {
return /* don't send heavy object if it hasn't changed */
}
ipc.send('wt-progress', progress)
ipcRenderer.send('wt-progress', progress)
prevProgress = progress
}
@@ -322,8 +314,8 @@ function startServerFromReadyTorrent (torrent, cb) {
networkAddress: networkAddress()
}
ipc.send('wt-server-running', info)
ipc.send('wt-server-' + torrent.infoHash, info)
ipcRenderer.send('wt-server-running', info)
ipcRenderer.send('wt-server-' + torrent.infoHash, info)
})
}
@@ -341,25 +333,31 @@ function getAudioMetadata (infoHash, index) {
// Set initial matadata to display the filename first.
const metadata = { title: file.name }
ipc.send('wt-audio-metadata', infoHash, index, metadata)
ipcRenderer.send('wt-audio-metadata', infoHash, index, metadata)
const options = {
native: false,
skipCovers: true,
fileSize: file.length,
observer: event => {
ipc.send('wt-audio-metadata', infoHash, index, event.metadata)
ipcRenderer.send('wt-audio-metadata', infoHash, index, {
common: metadata.common,
format: metadata.format
})
}
}
const onMetaData = file.done
const onMetadata = file.done
// If completed; use direct file access
? mm.parseFile(path.join(torrent.path, file.path), options)
// otherwise stream
: mm.parseStream(file.createReadStream(), file.name, options)
onMetaData
onMetadata
.then(
() => console.log(`metadata for file='${file.name}' completed.`),
metadata => {
ipcRenderer.send('wt-audio-metadata', infoHash, index, metadata)
console.log(`metadata for file='${file.name}' completed.`)
},
err => {
console.log(
`error getting audio metadata for ${infoHash}:${index}`,

View File

@@ -32,8 +32,8 @@
<p>
Version <script>document.write(require('../package.json').version)</script>
(<script>document.write(require('webtorrent/package.json').version)</script>)
(<script>document.write(process.arch === 'x64' ? '64-bit' : '32-bit')</script>)
(<script>document.write(process.arch)</script>)
</p>
<p><script>document.write(require('../config').APP_COPYRIGHT)</script></p>
<p><script>document.write(require('../build/config').APP_COPYRIGHT)</script></p>
</body>
</html>

Binary file not shown.

Binary file not shown.

View File

@@ -1,26 +1,25 @@
[Desktop Entry]
Type=Application
<% if (version) { %>Version=<%= version %><% } %>
Name=<%= productName %>
<% if (genericName) { %>GenericName=<%= genericName %><% } %>
<% if (description) { %>Comment=<%= description %><% } %>
Icon=<%= name %>
<% if (name) { %>Exec=<%= name %> %U<% } %>
<% if (name) { %>Exec=<%= name %> --no-sandbox %U<% } %><%/*HACK: --no-sandbox fixes an Electron 6 bug. See: #1703*/%>
Terminal=false
Actions=CreateNewTorrent;OpenTorrentFile;OpenTorrentAddress;
<% if (mimeType && mimeType.length) { %>MimeType=<%= mimeType.join(';') %>;<% } %>
<% if (categories && categories.length) { %>Categories=<%= categories.join(';') %>;<% } %>
StartupNotify=true
<% if (name) { %>StartupWMClass=<%= name %> <% } %>
StartupWMClass=<%= productName %>
[Desktop Action CreateNewTorrent]
Name=Create New Torrent...
<% if (name) { %>Exec=<%= name %> -n <% } %>
<% if (name) { %>Exec=<%= name %> --no-sandbox -n <% } %><%/*HACK: --no-sandbox fixes an Electron 6 bug. See: #1703*/%>
[Desktop Action OpenTorrentFile]
Name=Open Torrent File...
<% if (name) { %>Exec=<%= name %> -o <% } %>
<% if (name) { %>Exec=<%= name %> --no-sandbox -o <% } %><%/*HACK: --no-sandbox fixes an Electron 6 bug. See: #1703*/%>
[Desktop Action OpenTorrentAddress]
Name=Open Torrent Address...
<% if (name) { %>Exec=<%= name %> -u <% } %>
<% if (name) { %>Exec=<%= name %> --no-sandbox -u <% } %><%/*HACK: --no-sandbox fixes an Electron 6 bug. See: #1703*/%>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -558,6 +558,13 @@ body.drag .app::after {
width: 100%;
}
.player .name {
font-size: 20px;
font-weight: bold;
line-height: 1.5em;
margin-bottom: 6px;
}
/*
* PLAYER CONTROLS
*/
@@ -623,6 +630,11 @@ body.drag .app::after {
margin-top: 6px;
}
.player .controls .icon.multi-audio {
font-size: 26px;
margin-top: 6px;
}
.player .controls .icon.fullscreen {
font-size: 26px;
margin-right: 15px;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,15 +1,18 @@
const electron = require('electron')
const config = require('./config')
console.log('Mocking electron.dialog.showOpenDialog...')
electron.dialog.showOpenDialog = function (win, opts, cb) {
const ret = /select.*torrent file/i.test(opts.title)
console.log('Mocking electron.dialog.showOpenDialogSync...')
electron.dialog.showOpenDialogSync = showOpenDialogSync
function showOpenDialogSync (win, opts) {
return /select.*torrent file/i.test(opts.title)
? config.TORRENT_FILES
: config.SEED_FILES
cb(ret)
}
console.log('Mocking electron.remote.dialog.showSaveDialog...')
electron.dialog.showSaveDialog = function (win, opts, cb) {
cb(config.SAVED_TORRENT_FILE)
console.log('Mocking electron.dialog.showSaveDialogSync...')
electron.dialog.showSaveDialogSync = showSaveDialogSync
function showSaveDialogSync (win, opts) {
return config.SAVED_TORRENT_FILE
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 899 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 351 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 705 KiB

After

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 KiB

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 KiB

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 KiB

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 515 KiB

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 KiB

After

Width:  |  Height:  |  Size: 681 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 KiB

After

Width:  |  Height:  |  Size: 746 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1003 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1019 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1003 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 KiB

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 705 KiB

After

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 915 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 904 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 905 KiB

Some files were not shown because too many files have changed in this diff Show More