Merge branch 'master' into master
2
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github: feross
|
||||||
|
custom: https://paypal.me/borewit
|
||||||
4
.gitignore
vendored
@@ -2,3 +2,7 @@ node_modules/
|
|||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
|
|
||||||
|
# JetBrains IntelliJ IDEA project files
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|||||||
22
AUTHORS.md
@@ -43,9 +43,31 @@
|
|||||||
- Borewit (borewit@users.noreply.github.com)
|
- Borewit (borewit@users.noreply.github.com)
|
||||||
- greenkeeper[bot] (greenkeeper[bot]@users.noreply.github.com)
|
- greenkeeper[bot] (greenkeeper[bot]@users.noreply.github.com)
|
||||||
- Auyer (rafa_auyer@icloud.com)
|
- Auyer (rafa_auyer@icloud.com)
|
||||||
|
- Jon Koops (jonkoops@gmail.com)
|
||||||
|
- Michael George Attard (michaelgeorgeattard@gmail.com)
|
||||||
- SimplyAhmazing (ahmad19526@gmail.com)
|
- SimplyAhmazing (ahmad19526@gmail.com)
|
||||||
- Cezar Carneiro (cezargcarneiro@gmail.com)
|
- Cezar Carneiro (cezargcarneiro@gmail.com)
|
||||||
|
- Bilal Elmoussaoui (bil.elmoussaoui@gmail.com)
|
||||||
- Terry Hau (terryhau@gmail.com)
|
- Terry Hau (terryhau@gmail.com)
|
||||||
- Vítor Galvão (info@vitorgalvao.com)
|
- Vítor Galvão (info@vitorgalvao.com)
|
||||||
|
- Borewit (Borewit@users.noreply.github.com)
|
||||||
|
- Diego Rodríguez (diegorbaquero@gmail.com)
|
||||||
|
- Dan Flettre (flettre@gmail.com)
|
||||||
|
- Sibiraj (dev.sibiraj@outlook.com)
|
||||||
|
- clujin (clujin@gmail.com)
|
||||||
|
- Linus Unnebäck (linus@folkdatorn.se)
|
||||||
|
- Adrian Tombu (adrian@otso.fr)
|
||||||
|
- Lucas (5874806+RecoX@users.noreply.github.com)
|
||||||
|
- David Ernst (dsernst@users.noreply.github.com)
|
||||||
|
- David Ernst (git@dsernst.com)
|
||||||
|
- Jimmy Wärting (jimmy@warting.se)
|
||||||
|
- Recox (5874806+RecoX@users.noreply.github.com)
|
||||||
|
- greenkeeper[bot] (23040076+greenkeeper[bot]@users.noreply.github.com)
|
||||||
|
- hicom150 (hicom150@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)
|
||||||
|
|
||||||
#### Generated by bin/update-authors.sh.
|
#### Generated by bin/update-authors.sh.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<h4 align="center">The streaming torrent app. For Mac, Windows, and Linux.</h4>
|
<h4 align="center">The streaming torrent app. For Mac, Windows, and Linux.</h4>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://gitter.im/webtorrent/webtorrent"><img src="https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg" alt="gitter"></a>
|
<a href="https://discord.gg/cnXkm4Z"><img src="https://img.shields.io/discord/612575111718895616" alt="discord"></a>
|
||||||
<a href="https://travis-ci.org/webtorrent/webtorrent-desktop"><img src="https://img.shields.io/travis/webtorrent/webtorrent-desktop/master.svg" alt="travis"></a>
|
<a href="https://travis-ci.org/webtorrent/webtorrent-desktop"><img src="https://img.shields.io/travis/webtorrent/webtorrent-desktop/master.svg" alt="travis"></a>
|
||||||
<a href="https://github.com/webtorrent/webtorrent-desktop/releases"><img src="https://img.shields.io/github/release/webtorrent/webtorrent-desktop.svg" alt="github release version"></a>
|
<a href="https://github.com/webtorrent/webtorrent-desktop/releases"><img src="https://img.shields.io/github/release/webtorrent/webtorrent-desktop.svg" alt="github release version"></a>
|
||||||
<a href="https://github.com/webtorrent/webtorrent-desktop/releases"><img src="https://img.shields.io/github/downloads/webtorrent/webtorrent-desktop/total.svg" alt="github release downloads"></a>
|
<a href="https://github.com/webtorrent/webtorrent-desktop/releases"><img src="https://img.shields.io/github/downloads/webtorrent/webtorrent-desktop/total.svg" alt="github release downloads"></a>
|
||||||
@@ -97,7 +97,7 @@ comparing each one to a reference. Why screenshots?
|
|||||||
https://github.com/blog/817-behold-image-view-modes
|
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
|
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.
|
For Windows, you'll need Windows 10 with a 1366x768 screen.
|
||||||
|
|
||||||
@@ -158,6 +158,11 @@ The Mac app can only be packaged from **macOS**.
|
|||||||
|
|
||||||
The Linux app can be packaged from **any** platform.
|
The Linux app can be packaged from **any** platform.
|
||||||
|
|
||||||
|
If packaging from Mac, install system dependencies with Homebrew by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run install-system-deps
|
||||||
|
```
|
||||||
|
|
||||||
#### Recommended readings to start working in the app
|
#### Recommended readings to start working in the app
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const { CONFIG_PATH } = require('../src/config')
|
const { CONFIG_PATH } = require('../src/config')
|
||||||
const opn = require('opn')
|
const open = require('open')
|
||||||
|
|
||||||
opn(CONFIG_PATH)
|
open(CONFIG_PATH)
|
||||||
|
|||||||
165
bin/package.js
@@ -39,8 +39,7 @@ const argv = minimist(process.argv.slice(2), {
|
|||||||
function build () {
|
function build () {
|
||||||
console.log('Reinstalling node_modules...')
|
console.log('Reinstalling node_modules...')
|
||||||
rimraf.sync(NODE_MODULES_PATH)
|
rimraf.sync(NODE_MODULES_PATH)
|
||||||
cp.execSync('npm install', { stdio: 'inherit' })
|
cp.execSync('npm ci', { stdio: 'inherit' })
|
||||||
cp.execSync('npm dedupe', { stdio: 'inherit' })
|
|
||||||
|
|
||||||
console.log('Nuking dist/ and build/...')
|
console.log('Nuking dist/ and build/...')
|
||||||
rimraf.sync(DIST_PATH)
|
rimraf.sync(DIST_PATH)
|
||||||
@@ -119,7 +118,7 @@ const darwin = {
|
|||||||
// Build for Mac
|
// Build for Mac
|
||||||
platform: 'darwin',
|
platform: 'darwin',
|
||||||
|
|
||||||
// Build x64 binaries only.
|
// Build x64 binary only.
|
||||||
arch: 'x64',
|
arch: 'x64',
|
||||||
|
|
||||||
// The bundle identifier to use in the application's plist (Mac only).
|
// The bundle identifier to use in the application's plist (Mac only).
|
||||||
@@ -140,8 +139,8 @@ const win32 = {
|
|||||||
// Build for Windows.
|
// Build for Windows.
|
||||||
platform: 'win32',
|
platform: 'win32',
|
||||||
|
|
||||||
// Build ia32 and x64 binaries.
|
// Build x64 binary only.
|
||||||
arch: ['ia32', 'x64'],
|
arch: 'x64',
|
||||||
|
|
||||||
// Object hash of application metadata to embed into the executable (Windows only)
|
// Object hash of application metadata to embed into the executable (Windows only)
|
||||||
win32metadata: {
|
win32metadata: {
|
||||||
@@ -174,8 +173,8 @@ const linux = {
|
|||||||
// Build for Linux.
|
// Build for Linux.
|
||||||
platform: 'linux',
|
platform: 'linux',
|
||||||
|
|
||||||
// Build ia32 and x64 binaries.
|
// Build x64 and arm64 binaries.
|
||||||
arch: ['ia32', 'x64', 'arm64']
|
arch: ['x64', 'arm64']
|
||||||
|
|
||||||
// Note: Application icon for Linux is specified via the BrowserWindow `icon` option.
|
// Note: Application icon for Linux is specified via the BrowserWindow `icon` option.
|
||||||
}
|
}
|
||||||
@@ -186,8 +185,7 @@ function buildDarwin (cb) {
|
|||||||
const plist = require('plist')
|
const plist = require('plist')
|
||||||
|
|
||||||
console.log('Mac: Packaging electron...')
|
console.log('Mac: Packaging electron...')
|
||||||
electronPackager(Object.assign({}, all, darwin), function (err, buildPath) {
|
electronPackager(Object.assign({}, all, darwin)).then(function (buildPath) {
|
||||||
if (err) return cb(err)
|
|
||||||
console.log('Mac: Packaged electron. ' + buildPath)
|
console.log('Mac: Packaged electron. ' + buildPath)
|
||||||
|
|
||||||
const appPath = path.join(buildPath[0], config.APP_NAME + '.app')
|
const appPath = path.join(buildPath[0], config.APP_NAME + '.app')
|
||||||
@@ -356,6 +354,8 @@ function buildDarwin (cb) {
|
|||||||
cb(null)
|
cb(null)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}).catch(function (err) {
|
||||||
|
cb(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +376,7 @@ function buildWin32 (cb) {
|
|||||||
CERT_PATH = path.join(os.homedir(), 'Desktop')
|
CERT_PATH = path.join(os.homedir(), 'Desktop')
|
||||||
}
|
}
|
||||||
|
|
||||||
electronPackager(Object.assign({}, all, win32), function (err, buildPath) {
|
electronPackager(Object.assign({}, all, win32)).then(function (buildPath) {
|
||||||
if (err) return cb(err)
|
|
||||||
console.log('Windows: Packaged electron. ' + buildPath)
|
console.log('Windows: Packaged electron. ' + buildPath)
|
||||||
|
|
||||||
let signWithParams
|
let signWithParams
|
||||||
@@ -396,21 +395,17 @@ function buildWin32 (cb) {
|
|||||||
|
|
||||||
const tasks = []
|
const tasks = []
|
||||||
buildPath.forEach(function (filesPath) {
|
buildPath.forEach(function (filesPath) {
|
||||||
const destArch = filesPath.split('-').pop()
|
|
||||||
|
|
||||||
if (argv.package === 'exe' || argv.package === 'all') {
|
if (argv.package === 'exe' || argv.package === 'all') {
|
||||||
tasks.push((cb) => packageInstaller(filesPath, destArch, cb))
|
tasks.push((cb) => packageInstaller(filesPath, cb))
|
||||||
}
|
}
|
||||||
if (argv.package === 'portable' || argv.package === 'all') {
|
if (argv.package === 'portable' || argv.package === 'all') {
|
||||||
tasks.push((cb) => packagePortable(filesPath, destArch, cb))
|
tasks.push((cb) => packagePortable(filesPath, cb))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
series(tasks, cb)
|
series(tasks, cb)
|
||||||
|
|
||||||
function packageInstaller (filesPath, destArch, cb) {
|
function packageInstaller (filesPath, cb) {
|
||||||
console.log(`Windows: Creating ${destArch} installer...`)
|
console.log('Windows: Creating installer...')
|
||||||
|
|
||||||
const archStr = destArch === 'ia32' ? '-ia32' : ''
|
|
||||||
|
|
||||||
installer.createWindowsInstaller({
|
installer.createWindowsInstaller({
|
||||||
appDirectory: filesPath,
|
appDirectory: filesPath,
|
||||||
@@ -423,26 +418,17 @@ function buildWin32 (cb) {
|
|||||||
noMsi: true,
|
noMsi: true,
|
||||||
outputDirectory: DIST_PATH,
|
outputDirectory: DIST_PATH,
|
||||||
productName: config.APP_NAME,
|
productName: config.APP_NAME,
|
||||||
/**
|
|
||||||
* Only create delta updates for the Windows x64 build because 90% of our
|
|
||||||
* users have Windows x64 and the delta files take a *very* long time to
|
|
||||||
* generate. Also, the ia32 files on GitHub have non-standard Squirrel
|
|
||||||
* names (i.e. RELEASES-ia32 instead of RELEASES) and so Squirrel won't
|
|
||||||
* find them unless we proxy the requests.
|
|
||||||
*/
|
|
||||||
// TODO: Re-enable Windows 64-bit delta updates when we confirm that they
|
// TODO: Re-enable Windows 64-bit delta updates when we confirm that they
|
||||||
// work correctly in the presence of the "ia32" .nupkg files. I
|
// work correctly in the presence of the "ia32" .nupkg files. I
|
||||||
// (feross) noticed them listed in the 64-bit RELEASES file and
|
// (feross) noticed them listed in the 64-bit RELEASES file and
|
||||||
// manually edited them out for the v0.17 release. Shipping only
|
// manually edited them out for the v0.17 release. Shipping only
|
||||||
// full updates for now will work fine, with no ill-effects.
|
// full updates for now will work fine, with no ill-effects.
|
||||||
// remoteReleases: destArch === 'x64'
|
// remoteReleases: config.GITHUB_URL,
|
||||||
// ? config.GITHUB_URL
|
|
||||||
// : undefined,
|
|
||||||
/**
|
/**
|
||||||
* If you hit a "GitHub API rate limit exceeded" error, set this token!
|
* If you hit a "GitHub API rate limit exceeded" error, set this token!
|
||||||
*/
|
*/
|
||||||
// remoteToken: process.env.WEBTORRENT_GITHUB_API_TOKEN,
|
// remoteToken: process.env.WEBTORRENT_GITHUB_API_TOKEN,
|
||||||
setupExe: config.APP_NAME + 'Setup-v' + config.APP_VERSION + archStr + '.exe',
|
setupExe: config.APP_NAME + 'Setup-v' + config.APP_VERSION + '.exe',
|
||||||
setupIcon: config.APP_ICON + '.ico',
|
setupIcon: config.APP_ICON + '.ico',
|
||||||
signWithParams: signWithParams,
|
signWithParams: signWithParams,
|
||||||
title: config.APP_NAME,
|
title: config.APP_NAME,
|
||||||
@@ -450,7 +436,7 @@ function buildWin32 (cb) {
|
|||||||
version: pkg.version
|
version: pkg.version
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
console.log(`Windows: Created ${destArch} installer.`)
|
console.log('Windows: Created installer.')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete extraneous Squirrel files (i.e. *.nupkg delta files for older
|
* Delete extraneous Squirrel files (i.e. *.nupkg delta files for older
|
||||||
@@ -462,42 +448,13 @@ function buildWin32 (cb) {
|
|||||||
fs.unlinkSync(path.join(DIST_PATH, filename))
|
fs.unlinkSync(path.join(DIST_PATH, filename))
|
||||||
})
|
})
|
||||||
|
|
||||||
if (destArch === 'ia32') {
|
|
||||||
console.log('Windows: Renaming ia32 installer files...')
|
|
||||||
|
|
||||||
// RELEASES -> RELEASES-ia32
|
|
||||||
const relPath = path.join(DIST_PATH, 'RELEASES-ia32')
|
|
||||||
fs.renameSync(
|
|
||||||
path.join(DIST_PATH, 'RELEASES'),
|
|
||||||
relPath
|
|
||||||
)
|
|
||||||
|
|
||||||
// WebTorrent-vX.X.X-full.nupkg -> WebTorrent-vX.X.X-ia32-full.nupkg
|
|
||||||
fs.renameSync(
|
|
||||||
path.join(DIST_PATH, `${config.APP_NAME}-${config.APP_VERSION}-full.nupkg`),
|
|
||||||
path.join(DIST_PATH, `${config.APP_NAME}-${config.APP_VERSION}-ia32-full.nupkg`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Change file name inside RELEASES-ia32 to match renamed file
|
|
||||||
const relContent = fs.readFileSync(relPath, 'utf8')
|
|
||||||
const relContent32 = relContent.replace('full.nupkg', 'ia32-full.nupkg')
|
|
||||||
fs.writeFileSync(relPath, relContent32)
|
|
||||||
|
|
||||||
if (relContent === relContent32) {
|
|
||||||
// Sanity check
|
|
||||||
throw new Error('Fixing RELEASES-ia32 failed. Replacement did not modify the file.')
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Windows: Renamed ia32 installer files.')
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(null)
|
cb(null)
|
||||||
})
|
})
|
||||||
.catch(cb)
|
.catch(cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
function packagePortable (filesPath, destArch, cb) {
|
function packagePortable (filesPath, cb) {
|
||||||
console.log(`Windows: Creating ${destArch} portable app...`)
|
console.log('Windows: Creating portable app...')
|
||||||
|
|
||||||
const portablePath = path.join(filesPath, 'Portable Settings')
|
const portablePath = path.join(filesPath, 'Portable Settings')
|
||||||
mkdirp.sync(portablePath)
|
mkdirp.sync(portablePath)
|
||||||
@@ -508,84 +465,76 @@ function buildWin32 (cb) {
|
|||||||
const tempPath = path.join(portablePath, 'Temp')
|
const tempPath = path.join(portablePath, 'Temp')
|
||||||
mkdirp.sync(tempPath)
|
mkdirp.sync(tempPath)
|
||||||
|
|
||||||
const archStr = destArch === 'ia32' ? '-ia32' : ''
|
|
||||||
|
|
||||||
const inPath = path.join(DIST_PATH, path.basename(filesPath))
|
const inPath = path.join(DIST_PATH, path.basename(filesPath))
|
||||||
const outPath = path.join(DIST_PATH, BUILD_NAME + '-win' + archStr + '.zip')
|
const outPath = path.join(DIST_PATH, BUILD_NAME + '-win.zip')
|
||||||
zip.zipSync(inPath, outPath)
|
zip.zipSync(inPath, outPath)
|
||||||
|
|
||||||
console.log(`Windows: Created ${destArch} portable app.`)
|
console.log('Windows: Created portable app.')
|
||||||
cb(null)
|
cb(null)
|
||||||
}
|
}
|
||||||
|
}).catch(function (err) {
|
||||||
|
cb(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildLinux (cb) {
|
function buildLinux (cb) {
|
||||||
console.log('Linux: Packaging electron...')
|
console.log('Linux: Packaging electron...')
|
||||||
electronPackager(Object.assign({}, all, linux), function (err, buildPath) {
|
|
||||||
if (err) return cb(err)
|
electronPackager(Object.assign({}, all, linux)).then(function (buildPath) {
|
||||||
console.log('Linux: Packaged electron. ' + buildPath)
|
console.log('Linux: Packaged electron. ' + buildPath)
|
||||||
|
|
||||||
const tasks = []
|
const tasks = []
|
||||||
buildPath.forEach(function (filesPath) {
|
buildPath.forEach(function (filesPath) {
|
||||||
const destArch = filesPath.split('-').pop()
|
|
||||||
|
|
||||||
if (argv.package === 'deb' || argv.package === 'all') {
|
if (argv.package === 'deb' || argv.package === 'all') {
|
||||||
tasks.push((cb) => packageDeb(filesPath, destArch, cb))
|
tasks.push((cb) => packageDeb(filesPath, cb))
|
||||||
}
|
}
|
||||||
if (argv.package === 'zip' || argv.package === 'all') {
|
if (argv.package === 'zip' || argv.package === 'all') {
|
||||||
tasks.push((cb) => packageZip(filesPath, destArch, cb))
|
tasks.push((cb) => packageZip(filesPath, cb))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
series(tasks, cb)
|
series(tasks, cb)
|
||||||
|
}).catch(function (err) {
|
||||||
|
cb(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
function packageDeb (filesPath, destArch, cb) {
|
function packageDeb (filesPath, cb) {
|
||||||
// Create .deb file for Debian-based platforms
|
// Create .deb file for Debian-based platforms
|
||||||
console.log(`Linux: Creating ${destArch} deb...`)
|
console.log('Linux: Creating deb...')
|
||||||
|
|
||||||
const deb = require('nobin-debian-installer')()
|
const installer = require('electron-installer-debian')
|
||||||
const destPath = path.join('/opt', pkg.name)
|
|
||||||
|
|
||||||
deb.pack({
|
const options = {
|
||||||
package: pkg,
|
src: filesPath + '/',
|
||||||
info: {
|
dest: DIST_PATH,
|
||||||
arch: destArch === 'x64' ? 'amd64' : 'i386',
|
arch: 'amd64',
|
||||||
targetDir: DIST_PATH,
|
bin: 'WebTorrent',
|
||||||
depends: 'gconf2, libgtk2.0-0, libnss3, libxss1',
|
icon: {
|
||||||
scripts: {
|
'48x48': path.join(config.STATIC_PATH, 'linux/share/icons/hicolor/48x48/apps/webtorrent-desktop.png'),
|
||||||
postinst: path.join(config.STATIC_PATH, 'linux', 'postinst'),
|
'256x256': path.join(config.STATIC_PATH, 'linux/share/icons/hicolor/256x256/apps/webtorrent-desktop.png')
|
||||||
prerm: path.join(config.STATIC_PATH, 'linux', 'prerm')
|
},
|
||||||
}
|
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')
|
||||||
src: ['./**'],
|
}
|
||||||
dest: destPath,
|
|
||||||
expand: true,
|
installer(options).then(
|
||||||
cwd: filesPath
|
() => {
|
||||||
}, {
|
console.log('Linux: Created deb.')
|
||||||
src: ['./**'],
|
cb(null)
|
||||||
dest: path.join('/usr', 'share'),
|
},
|
||||||
expand: true,
|
(err) => cb(err)
|
||||||
cwd: path.join(config.STATIC_PATH, 'linux', 'share')
|
)
|
||||||
}], function (err) {
|
|
||||||
if (err) return cb(err)
|
|
||||||
console.log(`Linux: Created ${destArch} deb.`)
|
|
||||||
cb(null)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function packageZip (filesPath, destArch, cb) {
|
function packageZip (filesPath, cb) {
|
||||||
// Create .zip file for Linux
|
// Create .zip file for Linux
|
||||||
console.log(`Linux: Creating ${destArch} zip...`)
|
console.log('Linux: Creating zip...')
|
||||||
|
|
||||||
const archStr = destArch === 'ia32' ? '-ia32' : ''
|
|
||||||
|
|
||||||
const inPath = path.join(DIST_PATH, path.basename(filesPath))
|
const inPath = path.join(DIST_PATH, path.basename(filesPath))
|
||||||
const outPath = path.join(DIST_PATH, BUILD_NAME + '-linux' + archStr + '.zip')
|
const outPath = path.join(DIST_PATH, BUILD_NAME + '-linux.zip')
|
||||||
zip.zipSync(inPath, outPath)
|
zip.zipSync(inPath, outPath)
|
||||||
|
|
||||||
console.log(`Linux: Created ${destArch} zip.`)
|
console.log('Linux: Created zip.')
|
||||||
cb(null)
|
cb(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3791
package-lock.json
generated
90
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "webtorrent-desktop",
|
"name": "webtorrent-desktop",
|
||||||
"description": "WebTorrent, the streaming torrent client. For Mac, Windows, and Linux.",
|
"description": "WebTorrent, the streaming torrent client. For Mac, Windows, and Linux.",
|
||||||
"version": "0.20.0",
|
"version": "0.21.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "WebTorrent, LLC",
|
"name": "WebTorrent, LLC",
|
||||||
"email": "feross@webtorrent.io",
|
"email": "feross@webtorrent.io",
|
||||||
@@ -11,65 +11,62 @@
|
|||||||
"url": "https://github.com/webtorrent/webtorrent-desktop/issues"
|
"url": "https://github.com/webtorrent/webtorrent-desktop/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"airplayer": "^2.0.0",
|
"airplayer": "github:webtorrent/airplayer#fix-security",
|
||||||
"application-config": "^1.0.0",
|
"application-config": "^1.0.1",
|
||||||
"arch": "^2.0.0",
|
"arch": "^2.1.1",
|
||||||
"auto-launch": "^5.0.5",
|
"auto-launch": "^5.0.5",
|
||||||
"bitfield": "^1.0.2",
|
"bitfield": "^3.0.0",
|
||||||
"capture-frame": "^3.0.0",
|
"capture-frame": "^3.0.0",
|
||||||
"chokidar": "^2.0.4",
|
"chokidar": "^3.0.2",
|
||||||
"chromecasts": "^1.9.1",
|
"chromecasts": "^1.9.1",
|
||||||
"cp-file": "^7.0.0",
|
"create-torrent": "^4.4.1",
|
||||||
"create-torrent": "^4.0.0",
|
"debounce": "^1.2.0",
|
||||||
"debounce": "^1.0.0",
|
"deep-equal": "^1.1.0",
|
||||||
"deep-equal": "^1.0.1",
|
|
||||||
"dlnacasts": "^0.1.0",
|
"dlnacasts": "^0.1.0",
|
||||||
"drag-drop": "^4.1.0",
|
"drag-drop": "^5.0.1",
|
||||||
"es6-error": "^4.0.0",
|
"es6-error": "^4.1.1",
|
||||||
"fn-getter": "^1.0.0",
|
"fn-getter": "^1.0.0",
|
||||||
"iso-639-1": "^2.0.5",
|
"iso-639-1": "^2.1.0",
|
||||||
"languagedetect": "^1.2.0",
|
"languagedetect": "^1.2.0",
|
||||||
"location-history": "^1.0.0",
|
"location-history": "^1.1.1",
|
||||||
"material-ui": "^0.20.2",
|
"material-ui": "^0.20.2",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"music-metadata": "^4.2.0",
|
"music-metadata": "^4.5.3",
|
||||||
"network-address": "^1.1.0",
|
"network-address": "^1.1.2",
|
||||||
"parse-torrent": "^7.0.0",
|
"parse-torrent": "^7.0.1",
|
||||||
"prettier-bytes": "^1.0.1",
|
"prettier-bytes": "^1.0.4",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^16.5.2",
|
"react": "^16.9.0",
|
||||||
"react-dom": "^16.5.2",
|
"react-dom": "^16.9.0",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.0",
|
||||||
"run-parallel": "^1.1.6",
|
"run-parallel": "^1.1.9",
|
||||||
"semver": "^6.0.0",
|
"semver": "^6.3.0",
|
||||||
"simple-concat": "^1.0.0",
|
"simple-concat": "^1.0.0",
|
||||||
"simple-get": "^3.0.3",
|
"simple-get": "^3.0.3",
|
||||||
"srt-to-vtt": "^1.1.1",
|
"srt-to-vtt": "^1.1.3",
|
||||||
"vlc-command": "^1.0.1",
|
"vlc-command": "^1.2.0",
|
||||||
"webtorrent": "0.x",
|
"webtorrent": ">=0.107.16",
|
||||||
"winreg": "^1.2.0",
|
"winreg": "^1.2.4"
|
||||||
"zero-fill": "^2.2.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^10.0.2",
|
"babel-eslint": "^10.0.3",
|
||||||
"buble": "^0.19.6",
|
"buble": "^0.19.8",
|
||||||
"cross-zip": "^2.0.1",
|
"cross-zip": "^2.1.6",
|
||||||
"depcheck": "^0.8.0",
|
"depcheck": "^0.8.3",
|
||||||
"electron": "~6.0.1",
|
"electron": "~6.0.9",
|
||||||
"electron-osx-sign": "^0.4.11",
|
"electron-osx-sign": "^0.4.13",
|
||||||
"electron-packager": "^14.0.4",
|
"electron-packager": "^14.0.6",
|
||||||
"electron-winstaller": "^2.6.4",
|
"electron-winstaller": "^4.0.0",
|
||||||
"gh-release": "^3.4.0",
|
"gh-release": "^3.5.0",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"nobin-debian-installer": "0.0.10",
|
"nodemon": "^1.19.2",
|
||||||
"nodemon": "^1.18.8",
|
"open": "^6.4.0",
|
||||||
"opn": "^6.0.0",
|
|
||||||
"plist": "^3.0.1",
|
"plist": "^3.0.1",
|
||||||
"pngjs": "^3.0.0",
|
"pngjs": "^3.4.0",
|
||||||
"run-series": "^1.1.4",
|
"run-series": "^1.1.8",
|
||||||
"spectron": "^3.3.0",
|
"spectron": "^8.0.0",
|
||||||
"standard": "*",
|
"standard": "*",
|
||||||
"tape": "^4.9.1",
|
"tape": "^4.11.0",
|
||||||
"walk-sync": "^2.0.2"
|
"walk-sync": "^2.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -89,7 +86,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"appdmg": "^0.4.3"
|
"appdmg": "^0.6.0",
|
||||||
|
"electron-installer-debian": "^2.0.0"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"productName": "WebTorrent",
|
"productName": "WebTorrent",
|
||||||
@@ -101,9 +99,9 @@
|
|||||||
"build": "buble src --output build",
|
"build": "buble src --output build",
|
||||||
"clean": "node ./bin/clean.js",
|
"clean": "node ./bin/clean.js",
|
||||||
"gh-release": "gh-release",
|
"gh-release": "gh-release",
|
||||||
|
"install-system-deps": "brew install fakeroot dpkg",
|
||||||
"open-config": "node ./bin/open-config.js",
|
"open-config": "node ./bin/open-config.js",
|
||||||
"package": "node ./bin/package.js",
|
"package": "node ./bin/package.js",
|
||||||
"prepublish": "npm run build",
|
|
||||||
"start": "npm run build && electron .",
|
"start": "npm run build && electron .",
|
||||||
"test": "standard && depcheck --ignores=standard,babel-eslint --ignore-dirs=build,dist && node ./bin/extra-lint.js",
|
"test": "standard && depcheck --ignores=standard,babel-eslint --ignore-dirs=build,dist && node ./bin/extra-lint.js",
|
||||||
"test-integration": "npm run build && node ./test",
|
"test-integration": "npm run build && node ./test",
|
||||||
|
|||||||
@@ -73,8 +73,10 @@ module.exports = {
|
|||||||
GITHUB_URL: 'https://github.com/webtorrent/webtorrent-desktop',
|
GITHUB_URL: 'https://github.com/webtorrent/webtorrent-desktop',
|
||||||
GITHUB_URL_ISSUES: 'https://github.com/webtorrent/webtorrent-desktop/issues',
|
GITHUB_URL_ISSUES: 'https://github.com/webtorrent/webtorrent-desktop/issues',
|
||||||
GITHUB_URL_RAW: 'https://raw.githubusercontent.com/webtorrent/webtorrent-desktop/master',
|
GITHUB_URL_RAW: 'https://raw.githubusercontent.com/webtorrent/webtorrent-desktop/master',
|
||||||
|
GITHUB_URL_RELEASES: 'https://github.com/webtorrent/webtorrent-desktop/releases',
|
||||||
|
|
||||||
HOME_PAGE_URL: 'https://webtorrent.io',
|
HOME_PAGE_URL: 'https://webtorrent.io',
|
||||||
|
TWITTER_PAGE_URL: 'https://twitter.com/WebTorrentApp',
|
||||||
|
|
||||||
IS_PORTABLE: IS_PORTABLE,
|
IS_PORTABLE: IS_PORTABLE,
|
||||||
IS_PRODUCTION: IS_PRODUCTION,
|
IS_PRODUCTION: IS_PRODUCTION,
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ function install () {
|
|||||||
break
|
break
|
||||||
case 'win32': installWin32()
|
case 'win32': installWin32()
|
||||||
break
|
break
|
||||||
case 'linux': installLinux()
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,8 +21,6 @@ function uninstall () {
|
|||||||
break
|
break
|
||||||
case 'win32': uninstallWin32()
|
case 'win32': uninstallWin32()
|
||||||
break
|
break
|
||||||
case 'linux': uninstallLinux()
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,100 +265,3 @@ function uninstallWin32 () {
|
|||||||
function commandToArgs (command) {
|
function commandToArgs (command) {
|
||||||
return command.map((arg) => `"${arg}"`).join(' ')
|
return command.map((arg) => `"${arg}"`).join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
function installLinux () {
|
|
||||||
const fs = require('fs')
|
|
||||||
const os = require('os')
|
|
||||||
const path = require('path')
|
|
||||||
|
|
||||||
const config = require('../config')
|
|
||||||
const log = require('./log')
|
|
||||||
|
|
||||||
// Do not install in user dir if running on system
|
|
||||||
if (/^\/opt/.test(process.execPath)) return
|
|
||||||
|
|
||||||
installDesktopFile()
|
|
||||||
installIconFile()
|
|
||||||
|
|
||||||
function installDesktopFile () {
|
|
||||||
const templatePath = path.join(
|
|
||||||
config.STATIC_PATH, 'linux', 'webtorrent-desktop.desktop'
|
|
||||||
)
|
|
||||||
fs.readFile(templatePath, 'utf8', writeDesktopFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeDesktopFile (err, desktopFile) {
|
|
||||||
if (err) return log.error(err.message)
|
|
||||||
|
|
||||||
const appPath = config.IS_PRODUCTION
|
|
||||||
? path.dirname(process.execPath)
|
|
||||||
: config.ROOT_PATH
|
|
||||||
|
|
||||||
desktopFile = desktopFile
|
|
||||||
.replace(/\$APP_NAME/g, config.APP_NAME)
|
|
||||||
.replace(/\$APP_PATH/g, appPath)
|
|
||||||
.replace(/\$EXEC_PATH/g, EXEC_COMMAND.join(' '))
|
|
||||||
.replace(/\$TRY_EXEC_PATH/g, process.execPath)
|
|
||||||
|
|
||||||
const desktopFilePath = path.join(
|
|
||||||
os.homedir(),
|
|
||||||
'.local',
|
|
||||||
'share',
|
|
||||||
'applications',
|
|
||||||
'webtorrent-desktop.desktop'
|
|
||||||
)
|
|
||||||
fs.mkdirp(path.dirname(desktopFilePath))
|
|
||||||
fs.writeFile(desktopFilePath, desktopFile, err => {
|
|
||||||
if (err) return log.error(err.message)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function installIconFile () {
|
|
||||||
const iconStaticPath = path.join(config.STATIC_PATH, 'WebTorrent.png')
|
|
||||||
fs.readFile(iconStaticPath, writeIconFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeIconFile (err, iconFile) {
|
|
||||||
if (err) return log.error(err.message)
|
|
||||||
|
|
||||||
const mkdirp = require('mkdirp')
|
|
||||||
|
|
||||||
const iconFilePath = path.join(
|
|
||||||
os.homedir(),
|
|
||||||
'.local',
|
|
||||||
'share',
|
|
||||||
'icons',
|
|
||||||
'webtorrent-desktop.png'
|
|
||||||
)
|
|
||||||
mkdirp(path.dirname(iconFilePath), err => {
|
|
||||||
if (err) return log.error(err.message)
|
|
||||||
fs.writeFile(iconFilePath, iconFile, err => {
|
|
||||||
if (err) log.error(err.message)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function uninstallLinux () {
|
|
||||||
const os = require('os')
|
|
||||||
const path = require('path')
|
|
||||||
const rimraf = require('rimraf')
|
|
||||||
|
|
||||||
const desktopFilePath = path.join(
|
|
||||||
os.homedir(),
|
|
||||||
'.local',
|
|
||||||
'share',
|
|
||||||
'applications',
|
|
||||||
'webtorrent-desktop.desktop'
|
|
||||||
)
|
|
||||||
rimraf.sync(desktopFilePath)
|
|
||||||
|
|
||||||
const iconFilePath = path.join(
|
|
||||||
os.homedir(),
|
|
||||||
'.local',
|
|
||||||
'share',
|
|
||||||
'icons',
|
|
||||||
'webtorrent-desktop.png'
|
|
||||||
)
|
|
||||||
rimraf.sync(iconFilePath)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -302,6 +302,13 @@ function getMenuTemplate () {
|
|||||||
shell.openExternal(config.HOME_PAGE_URL)
|
shell.openExternal(config.HOME_PAGE_URL)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Release Notes',
|
||||||
|
click: () => {
|
||||||
|
const shell = require('./shell')
|
||||||
|
shell.openExternal(config.GITHUB_URL_RELEASES)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Contribute on GitHub',
|
label: 'Contribute on GitHub',
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -318,6 +325,13 @@ function getMenuTemplate () {
|
|||||||
const shell = require('./shell')
|
const shell = require('./shell')
|
||||||
shell.openExternal(config.GITHUB_URL_ISSUES)
|
shell.openExternal(config.GITHUB_URL_ISSUES)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Follow us on Twitter',
|
||||||
|
click: () => {
|
||||||
|
const shell = require('./shell')
|
||||||
|
shell.openExternal(config.TWITTER_PAGE_URL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const TextField = require('material-ui/TextField').default
|
const TextField = require('material-ui/TextField').default
|
||||||
|
const { clipboard } = require('electron')
|
||||||
|
|
||||||
const ModalOKCancel = require('./modal-ok-cancel')
|
const ModalOKCancel = require('./modal-ok-cancel')
|
||||||
const { dispatch, dispatcher } = require('../lib/dispatcher')
|
const { dispatch, dispatcher } = require('../lib/dispatcher')
|
||||||
|
const { isMagnetLink } = require('../lib/torrent-player')
|
||||||
|
|
||||||
module.exports = class OpenTorrentAddressModal extends React.Component {
|
module.exports = class OpenTorrentAddressModal extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
@@ -30,6 +32,12 @@ module.exports = class OpenTorrentAddressModal extends React.Component {
|
|||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.torrentURL.input.focus()
|
this.torrentURL.input.focus()
|
||||||
|
const clipboardContent = clipboard.readText()
|
||||||
|
|
||||||
|
if (isMagnetLink(clipboardContent)) {
|
||||||
|
this.torrentURL.input.value = clipboardContent
|
||||||
|
this.torrentURL.input.select()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const path = require('path')
|
||||||
|
|
||||||
const colors = require('material-ui/styles/colors')
|
const colors = require('material-ui/styles/colors')
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const React = require('react')
|
const React = require('react')
|
||||||
@@ -16,7 +18,6 @@ class PathSelector extends React.Component {
|
|||||||
return {
|
return {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
dialog: PropTypes.object,
|
dialog: PropTypes.object,
|
||||||
displayValue: PropTypes.string,
|
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
@@ -31,7 +32,7 @@ class PathSelector extends React.Component {
|
|||||||
|
|
||||||
handleClick () {
|
handleClick () {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
defaultPath: this.props.value,
|
defaultPath: this.props.value && path.dirname(this.props.value),
|
||||||
properties: ['openFile', 'openDirectory']
|
properties: ['openFile', 'openDirectory']
|
||||||
}, this.props.dialog)
|
}, this.props.dialog)
|
||||||
|
|
||||||
@@ -65,8 +66,7 @@ class PathSelector extends React.Component {
|
|||||||
const textFieldStyle = {
|
const textFieldStyle = {
|
||||||
flex: '1'
|
flex: '1'
|
||||||
}
|
}
|
||||||
|
const text = this.props.value || ''
|
||||||
const text = this.props.displayValue || this.props.value || ''
|
|
||||||
const buttonStyle = {
|
const buttonStyle = {
|
||||||
marginLeft: 10
|
marginLeft: 10
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ module.exports = class PlaybackController {
|
|||||||
// update state
|
// update state
|
||||||
state.playing.infoHash = infoHash
|
state.playing.infoHash = infoHash
|
||||||
state.playing.fileIndex = index
|
state.playing.fileIndex = index
|
||||||
|
state.playing.fileName = fileSummary.name
|
||||||
state.playing.type = TorrentPlayer.isVideo(fileSummary) ? 'video'
|
state.playing.type = TorrentPlayer.isVideo(fileSummary) ? 'video'
|
||||||
: TorrentPlayer.isAudio(fileSummary) ? 'audio'
|
: TorrentPlayer.isAudio(fileSummary) ? 'audio'
|
||||||
: 'other'
|
: 'other'
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module.exports = class TorrentController {
|
|||||||
this.state = state
|
this.state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
torrentInfoHash (torrentKey, infoHash) {
|
torrentParsed (torrentKey, infoHash, magnetURI) {
|
||||||
let torrentSummary = this.getTorrentSummary(torrentKey)
|
let torrentSummary = this.getTorrentSummary(torrentKey)
|
||||||
console.log('got infohash for %s torrent %s',
|
console.log('got infohash for %s torrent %s',
|
||||||
torrentSummary ? 'existing' : 'new', torrentKey)
|
torrentSummary ? 'existing' : 'new', torrentKey)
|
||||||
@@ -33,6 +33,7 @@ module.exports = class TorrentController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
torrentSummary.infoHash = infoHash
|
torrentSummary.infoHash = infoHash
|
||||||
|
torrentSummary.magnetURI = magnetURI
|
||||||
dispatch('update')
|
dispatch('update')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +63,6 @@ module.exports = class TorrentController {
|
|||||||
torrentSummary.status = 'downloading'
|
torrentSummary.status = 'downloading'
|
||||||
torrentSummary.name = torrentSummary.displayName || torrentInfo.name
|
torrentSummary.name = torrentSummary.displayName || torrentInfo.name
|
||||||
torrentSummary.path = torrentInfo.path
|
torrentSummary.path = torrentInfo.path
|
||||||
torrentSummary.magnetURI = torrentInfo.magnetURI
|
|
||||||
// TODO: make torrentInfo immutable, save separately as torrentSummary.info
|
// TODO: make torrentInfo immutable, save separately as torrentSummary.info
|
||||||
// For now, check whether torrentSummary.files has already been set:
|
// For now, check whether torrentSummary.files has already been set:
|
||||||
const hasDetailedFileInfo = torrentSummary.files && torrentSummary.files[0].path
|
const hasDetailedFileInfo = torrentSummary.files && torrentSummary.files[0].path
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function run (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function migrate_0_7_0 (saved) {
|
function migrate_0_7_0 (saved) {
|
||||||
const cpFile = require('cp-file')
|
const { copyFileSync } = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
saved.torrents.forEach(function (ts) {
|
saved.torrents.forEach(function (ts) {
|
||||||
@@ -57,7 +57,7 @@ function migrate_0_7_0 (saved) {
|
|||||||
dst = path.join(config.TORRENT_PATH, infoHash + '.torrent')
|
dst = path.join(config.TORRENT_PATH, infoHash + '.torrent')
|
||||||
// Synchronous FS calls aren't ideal, but probably OK in a migration
|
// Synchronous FS calls aren't ideal, but probably OK in a migration
|
||||||
// that only runs once
|
// that only runs once
|
||||||
if (src !== dst) cpFile.sync(src, dst)
|
if (src !== dst) copyFileSync(src, dst)
|
||||||
|
|
||||||
delete ts.torrentPath
|
delete ts.torrentPath
|
||||||
ts.torrentFileName = infoHash + '.torrent'
|
ts.torrentFileName = infoHash + '.torrent'
|
||||||
@@ -72,7 +72,7 @@ function migrate_0_7_0 (saved) {
|
|||||||
dst = path.join(config.POSTER_PATH, infoHash + extension)
|
dst = path.join(config.POSTER_PATH, infoHash + extension)
|
||||||
// Synchronous FS calls aren't ideal, but probably OK in a migration
|
// Synchronous FS calls aren't ideal, but probably OK in a migration
|
||||||
// that only runs once
|
// that only runs once
|
||||||
if (src !== dst) cpFile.sync(src, dst)
|
if (src !== dst) copyFileSync(src, dst)
|
||||||
|
|
||||||
delete ts.posterURL
|
delete ts.posterURL
|
||||||
ts.posterFileName = infoHash + extension
|
ts.posterFileName = infoHash + extension
|
||||||
@@ -156,7 +156,7 @@ function migrate_0_17_2 (saved) {
|
|||||||
// folders/files that end in a trailing dot (.) or space are not deletable from
|
// 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
|
// 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 rimraf = require('rimraf')
|
||||||
|
|
||||||
const OLD_NAME = 'The WIRED CD - Rip. Sample. Mash. Share.'
|
const OLD_NAME = 'The WIRED CD - Rip. Sample. Mash. Share.'
|
||||||
@@ -191,7 +191,7 @@ function migrate_0_17_2 (saved) {
|
|||||||
ts.posterFileName = NEW_HASH + '.jpg'
|
ts.posterFileName = NEW_HASH + '.jpg'
|
||||||
|
|
||||||
rimraf.sync(path.join(config.TORRENT_PATH, ts.torrentFileName))
|
rimraf.sync(path.join(config.TORRENT_PATH, ts.torrentFileName))
|
||||||
cpFile.sync(
|
copyFileSync(
|
||||||
path.join(config.STATIC_PATH, 'wiredCd.torrent'),
|
path.join(config.STATIC_PATH, 'wiredCd.torrent'),
|
||||||
path.join(config.TORRENT_PATH, NEW_HASH + '.torrent')
|
path.join(config.TORRENT_PATH, NEW_HASH + '.torrent')
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ function getPreviousIndex (state) {
|
|||||||
|
|
||||||
function getCurrentLocalURL (state) {
|
function getCurrentLocalURL (state) {
|
||||||
return state.server
|
return state.server
|
||||||
? state.server.localURL + '/' + state.playing.fileIndex
|
? state.server.localURL + '/' + state.playing.fileIndex + '/' +
|
||||||
|
encodeURIComponent(state.playing.fileName)
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ function init (appState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function play (name) {
|
function play (name) {
|
||||||
|
if (state == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!state.saved.prefs.soundNotifications) {
|
if (!state.saved.prefs.soundNotifications) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ function getDefaultPlayState () {
|
|||||||
return {
|
return {
|
||||||
infoHash: null, /* the info hash of the torrent we're playing */
|
infoHash: null, /* the info hash of the torrent we're playing */
|
||||||
fileIndex: null, /* the zero-based index within the torrent */
|
fileIndex: null, /* the zero-based index within the torrent */
|
||||||
|
fileName: null, /* name of the file that is playing */
|
||||||
location: 'local', /* 'local', 'chromecast', 'airplay' */
|
location: 'local', /* 'local', 'chromecast', 'airplay' */
|
||||||
type: null, /* 'audio' or 'video', could be 'other' if ever support eg streaming to VLC */
|
type: null, /* 'audio' or 'video', could be 'other' if ever support eg streaming to VLC */
|
||||||
currentTime: 0, /* seconds */
|
currentTime: 0, /* seconds */
|
||||||
@@ -109,9 +110,8 @@ function getDefaultPlayState () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If the saved state file doesn't exist yet, here's what we use instead */
|
/* If the saved state file doesn't exist yet, here's what we use instead */
|
||||||
function setupStateSaved (cb) {
|
function setupStateSaved () {
|
||||||
const cpFile = require('cp-file')
|
const { copyFileSync, mkdirSync, readFileSync } = require('fs')
|
||||||
const fs = require('fs')
|
|
||||||
const parseTorrent = require('parse-torrent')
|
const parseTorrent = require('parse-torrent')
|
||||||
|
|
||||||
const saved = {
|
const saved = {
|
||||||
@@ -131,31 +131,28 @@ function setupStateSaved (cb) {
|
|||||||
version: config.APP_VERSION /* make sure we can upgrade gracefully later */
|
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) => {
|
config.DEFAULT_TORRENTS.forEach((t, i) => {
|
||||||
const infoHash = saved.torrents[i].infoHash
|
const infoHash = saved.torrents[i].infoHash
|
||||||
tasks.push(
|
// TODO: Doing several sync calls during first startup is not ideal
|
||||||
cpFile(
|
copyFileSync(
|
||||||
path.join(config.STATIC_PATH, t.posterFileName),
|
path.join(config.STATIC_PATH, t.posterFileName),
|
||||||
path.join(config.POSTER_PATH, infoHash + path.extname(t.posterFileName))
|
path.join(config.POSTER_PATH, infoHash + path.extname(t.posterFileName))
|
||||||
)
|
|
||||||
)
|
)
|
||||||
tasks.push(
|
copyFileSync(
|
||||||
cpFile(
|
path.join(config.STATIC_PATH, t.torrentFileName),
|
||||||
path.join(config.STATIC_PATH, t.torrentFileName),
|
path.join(config.TORRENT_PATH, infoHash + '.torrent')
|
||||||
path.join(config.TORRENT_PATH, infoHash + '.torrent')
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
Promise.all(tasks)
|
return saved
|
||||||
.then(() => cb(null, saved))
|
|
||||||
.catch(err => cb(err))
|
|
||||||
|
|
||||||
function createTorrentObject (t) {
|
function createTorrentObject (t) {
|
||||||
// TODO: Doing several fs.readFileSync calls during first startup is not ideal
|
// TODO: Doing several sync calls during first startup is not ideal
|
||||||
const torrent = fs.readFileSync(path.join(config.STATIC_PATH, t.torrentFileName))
|
const torrent = readFileSync(path.join(config.STATIC_PATH, t.torrentFileName))
|
||||||
const parsedTorrent = parseTorrent(torrent)
|
const parsedTorrent = parseTorrent(torrent)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -204,10 +201,14 @@ function load (cb) {
|
|||||||
appConfig.read(function (err, saved) {
|
appConfig.read(function (err, saved) {
|
||||||
if (err || !saved.version) {
|
if (err || !saved.version) {
|
||||||
console.log('Missing config file: Creating new one')
|
console.log('Missing config file: Creating new one')
|
||||||
setupStateSaved(onSavedState)
|
try {
|
||||||
} else {
|
saved = setupStateSaved()
|
||||||
onSavedState(null, saved)
|
} catch (err) {
|
||||||
|
onSavedState(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
onSavedState(null, saved)
|
||||||
})
|
})
|
||||||
|
|
||||||
function onSavedState (err, saved) {
|
function onSavedState (err, saved) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module.exports = {
|
|||||||
isVideo,
|
isVideo,
|
||||||
isAudio,
|
isAudio,
|
||||||
isTorrent,
|
isTorrent,
|
||||||
|
isMagnetLink,
|
||||||
isPlayableTorrentSummary
|
isPlayableTorrentSummary
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,9 +32,15 @@ function isAudio (file) {
|
|||||||
// - a file object where obj.name is ends in .torrent
|
// - a file object where obj.name is ends in .torrent
|
||||||
// - a string that's a magnet link (magnet://...)
|
// - a string that's a magnet link (magnet://...)
|
||||||
function isTorrent (file) {
|
function isTorrent (file) {
|
||||||
const isTorrentFile = getFileExtension(file) === '.torrent'
|
return isTorrentFile(file) || isMagnetLink(file)
|
||||||
const isMagnet = typeof file === 'string' && /^(stream-)?magnet:/.test(file)
|
}
|
||||||
return isTorrentFile || isMagnet
|
|
||||||
|
function isTorrentFile (file) {
|
||||||
|
return getFileExtension(file) === '.torrent'
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMagnetLink (link) {
|
||||||
|
return typeof link === 'string' && /^(stream-)?magnet:/.test(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFileExtension (file) {
|
function getFileExtension (file) {
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ function setupIpc () {
|
|||||||
ipcRenderer.on('windowBoundsChanged', onWindowBoundsChanged)
|
ipcRenderer.on('windowBoundsChanged', onWindowBoundsChanged)
|
||||||
|
|
||||||
const tc = controllers.torrent()
|
const tc = controllers.torrent()
|
||||||
ipcRenderer.on('wt-infohash', (e, ...args) => tc.torrentInfoHash(...args))
|
ipcRenderer.on('wt-parsed', (e, ...args) => tc.torrentParsed(...args))
|
||||||
ipcRenderer.on('wt-metadata', (e, ...args) => tc.torrentMetadata(...args))
|
ipcRenderer.on('wt-metadata', (e, ...args) => tc.torrentMetadata(...args))
|
||||||
ipcRenderer.on('wt-done', (e, ...args) => tc.torrentDone(...args))
|
ipcRenderer.on('wt-done', (e, ...args) => tc.torrentDone(...args))
|
||||||
ipcRenderer.on('wt-done', () => controllers.torrentList().resumePausedTorrents())
|
ipcRenderer.on('wt-done', () => controllers.torrentList().resumePausedTorrents())
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ class CreateTorrentPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create React event handlers only once
|
// Create React event handlers only once
|
||||||
this.setIsPrivate = (_, isPrivate) => this.setState({ isPrivate })
|
this.handleSetIsPrivate = (_, isPrivate) => this.setState({ isPrivate })
|
||||||
this.setComment = (_, comment) => this.setState({ comment })
|
this.handleSetComment = (_, comment) => this.setState({ comment })
|
||||||
this.setTrackers = (_, trackers) => this.setState({ trackers })
|
this.handleSetTrackers = (_, trackers) => this.setState({ trackers })
|
||||||
this.handleSubmit = handleSubmit.bind(this)
|
this.handleSubmit = handleSubmit.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class CreateTorrentPage extends React.Component {
|
|||||||
className='torrent-is-private control'
|
className='torrent-is-private control'
|
||||||
style={{ display: '' }}
|
style={{ display: '' }}
|
||||||
checked={this.state.isPrivate}
|
checked={this.state.isPrivate}
|
||||||
onCheck={this.setIsPrivate}
|
onCheck={this.handleSetIsPrivate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div key='trackers' className='torrent-attribute'>
|
<div key='trackers' className='torrent-attribute'>
|
||||||
@@ -159,7 +159,7 @@ class CreateTorrentPage extends React.Component {
|
|||||||
rows={2}
|
rows={2}
|
||||||
rowsMax={10}
|
rowsMax={10}
|
||||||
value={this.state.trackers}
|
value={this.state.trackers}
|
||||||
onChange={this.setTrackers}
|
onChange={this.handleSetTrackers}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div key='comment' className='torrent-attribute'>
|
<div key='comment' className='torrent-attribute'>
|
||||||
@@ -173,7 +173,7 @@ class CreateTorrentPage extends React.Component {
|
|||||||
rows={2}
|
rows={2}
|
||||||
rowsMax={10}
|
rowsMax={10}
|
||||||
value={this.state.comment}
|
value={this.state.comment}
|
||||||
onChange={this.setComment}
|
onChange={this.handleSetComment}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div key='files' className='torrent-attribute'>
|
<div key='files' className='torrent-attribute'>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
const React = require('react')
|
const React = require('react')
|
||||||
const Bitfield = require('bitfield')
|
const Bitfield = require('bitfield')
|
||||||
const prettyBytes = require('prettier-bytes')
|
const prettyBytes = require('prettier-bytes')
|
||||||
const zeroFill = require('zero-fill')
|
|
||||||
|
|
||||||
const TorrentSummary = require('../lib/torrent-summary')
|
const TorrentSummary = require('../lib/torrent-summary')
|
||||||
const Playlist = require('../lib/playlist')
|
const Playlist = require('../lib/playlist')
|
||||||
@@ -300,7 +299,7 @@ function renderAudioMetadata (state) {
|
|||||||
}
|
}
|
||||||
elems.push((
|
elems.push((
|
||||||
<div key='release' className='audio-release'>
|
<div key='release' className='audio-release'>
|
||||||
<label>Release</label>{ releaseInfo.join(', ') }
|
<label>Release</label>{releaseInfo.join(', ')}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -327,7 +326,7 @@ function renderAudioMetadata (state) {
|
|||||||
if (format.length > 0) {
|
if (format.length > 0) {
|
||||||
elems.push((
|
elems.push((
|
||||||
<div key='format' className='audio-format'>
|
<div key='format' className='audio-format'>
|
||||||
<label>Format</label>{ format.join(', ') }
|
<label>Format</label>{format.join(', ')}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -762,10 +761,10 @@ function formatTime (time, total) {
|
|||||||
const totalMinutes = Math.floor(total / 60)
|
const totalMinutes = Math.floor(total / 60)
|
||||||
const hours = Math.floor(time / 3600)
|
const hours = Math.floor(time / 3600)
|
||||||
let minutes = Math.floor(time % 3600 / 60)
|
let minutes = Math.floor(time % 3600 / 60)
|
||||||
if (totalMinutes > 9) {
|
if (totalMinutes > 9 && minutes < 10) {
|
||||||
minutes = zeroFill(2, minutes)
|
minutes = '0' + minutes
|
||||||
}
|
}
|
||||||
const seconds = zeroFill(2, Math.floor(time % 60))
|
const seconds = `0${Math.floor(time % 60)}`.slice(-2)
|
||||||
|
|
||||||
return (totalHours > 0 ? hours + ':' : '') + minutes + ':' + seconds
|
return (totalHours > 0 ? hours + ':' : '') + minutes + ':' + seconds
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const path = require('path')
|
|
||||||
const React = require('react')
|
const React = require('react')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ class PreferencesPage extends React.Component {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={!this.props.state.saved.prefs.openExternalPlayer}
|
checked={!this.props.state.saved.prefs.openExternalPlayer}
|
||||||
label={'Play torrent media files using WebTorrent'}
|
label='Play torrent media files using WebTorrent'
|
||||||
onCheck={this.handleOpenExternalPlayerChange}
|
onCheck={this.handleOpenExternalPlayerChange}
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
@@ -74,7 +73,7 @@ class PreferencesPage extends React.Component {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.highestPlaybackPriority}
|
checked={this.props.state.saved.prefs.highestPlaybackPriority}
|
||||||
label={'Highest Playback Priority'}
|
label='Highest Playback Priority'
|
||||||
onCheck={this.handleHighestPlaybackPriorityChange}
|
onCheck={this.handleHighestPlaybackPriorityChange}
|
||||||
/>
|
/>
|
||||||
<p>Pauses all active torrents to allow playback to use all of the available bandwidth.</p>
|
<p>Pauses all active torrents to allow playback to use all of the available bandwidth.</p>
|
||||||
@@ -102,10 +101,9 @@ class PreferencesPage extends React.Component {
|
|||||||
title: 'Select media player app',
|
title: 'Select media player app',
|
||||||
properties: ['openFile']
|
properties: ['openFile']
|
||||||
}}
|
}}
|
||||||
displayValue={playerName}
|
|
||||||
onChange={this.handleExternalPlayerPathChange}
|
onChange={this.handleExternalPlayerPathChange}
|
||||||
title='External player'
|
title='External player'
|
||||||
value={playerPath ? path.dirname(playerPath) : null}
|
value={playerPath}
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
@@ -121,7 +119,7 @@ class PreferencesPage extends React.Component {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.autoAddTorrents}
|
checked={this.props.state.saved.prefs.autoAddTorrents}
|
||||||
label={'Watch for new .torrent files and add them immediately'}
|
label='Watch for new .torrent files and add them immediately'
|
||||||
onCheck={(e, value) => { this.handleAutoAddTorrentsChange(e, value) }}
|
onCheck={(e, value) => { this.handleAutoAddTorrentsChange(e, value) }}
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
@@ -139,11 +137,11 @@ class PreferencesPage extends React.Component {
|
|||||||
dispatch('updatePreferences', 'autoAddTorrents', isChecked)
|
dispatch('updatePreferences', 'autoAddTorrents', isChecked)
|
||||||
|
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
dispatch('startFolderWatcher', null)
|
dispatch('startFolderWatcher')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch('stopFolderWatcher', null)
|
dispatch('stopFolderWatcher')
|
||||||
}
|
}
|
||||||
|
|
||||||
torrentsFolderPathSelector () {
|
torrentsFolderPathSelector () {
|
||||||
@@ -156,16 +154,15 @@ class PreferencesPage extends React.Component {
|
|||||||
title: 'Select folder to watch for new torrents',
|
title: 'Select folder to watch for new torrents',
|
||||||
properties: ['openDirectory']
|
properties: ['openDirectory']
|
||||||
}}
|
}}
|
||||||
displayValue={torrentsFolderPath || ''}
|
onChange={this.handleTorrentsFolderPathChange}
|
||||||
onChange={this.handletorrentsFolderPathChange}
|
|
||||||
title='Folder to watch'
|
title='Folder to watch'
|
||||||
value={torrentsFolderPath ? path.dirname(torrentsFolderPath) : null}
|
value={torrentsFolderPath}
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
handletorrentsFolderPathChange (filePath) {
|
handleTorrentsFolderPathChange (filePath) {
|
||||||
dispatch('updatePreferences', 'torrentsFolderPath', filePath)
|
dispatch('updatePreferences', 'torrentsFolderPath', filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +201,7 @@ class PreferencesPage extends React.Component {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.startup}
|
checked={this.props.state.saved.prefs.startup}
|
||||||
label={'Open WebTorrent on startup'}
|
label='Open WebTorrent on startup'
|
||||||
onCheck={this.handleStartupChange}
|
onCheck={this.handleStartupChange}
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
@@ -217,7 +214,7 @@ class PreferencesPage extends React.Component {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
className='control'
|
className='control'
|
||||||
checked={this.props.state.saved.prefs.soundNotifications}
|
checked={this.props.state.saved.prefs.soundNotifications}
|
||||||
label={'Enable sounds'}
|
label='Enable sounds'
|
||||||
onCheck={this.handleSoundNotificationsChange}
|
onCheck={this.handleSoundNotificationsChange}
|
||||||
/>
|
/>
|
||||||
</Preference>
|
</Preference>
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
<i
|
<i
|
||||||
key='play-button'
|
key='play-button'
|
||||||
title='Start streaming'
|
title='Start streaming'
|
||||||
className={'icon play'}
|
className='icon play'
|
||||||
onClick={dispatcher('playFile', infoHash)}
|
onClick={dispatcher('playFile', infoHash)}
|
||||||
>
|
>
|
||||||
play_circle_outline
|
play_circle_outline
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const mm = require('music-metadata')
|
|||||||
const networkAddress = require('network-address')
|
const networkAddress = require('network-address')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const WebTorrent = require('webtorrent')
|
const WebTorrent = require('webtorrent')
|
||||||
const zeroFill = require('zero-fill')
|
|
||||||
|
|
||||||
const crashReporter = require('../crash-reporter')
|
const crashReporter = require('../crash-reporter')
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
@@ -41,10 +40,9 @@ const VERSION = require('../../package.json').version
|
|||||||
* '0.16.1' -> '0016'
|
* '0.16.1' -> '0016'
|
||||||
* '1.2.5' -> '0102'
|
* '1.2.5' -> '0102'
|
||||||
*/
|
*/
|
||||||
const VERSION_STR = VERSION.match(/([0-9]+)/g)
|
const VERSION_STR = VERSION
|
||||||
.slice(0, 2)
|
.replace(/\d*./g, v => `0${v % 100}`.slice(-2))
|
||||||
.map((v) => zeroFill(2, v))
|
.slice(0, 4)
|
||||||
.join('')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version prefix string (used in peer ID). WebTorrent uses the Azureus-style
|
* Version prefix string (used in peer ID). WebTorrent uses the Azureus-style
|
||||||
@@ -149,7 +147,7 @@ function addTorrentEvents (torrent) {
|
|||||||
torrent.on('error', (err) =>
|
torrent.on('error', (err) =>
|
||||||
ipc.send('wt-error', torrent.key, err.message))
|
ipc.send('wt-error', torrent.key, err.message))
|
||||||
torrent.on('infoHash', () =>
|
torrent.on('infoHash', () =>
|
||||||
ipc.send('wt-infohash', torrent.key, torrent.infoHash))
|
ipc.send('wt-parsed', torrent.key, torrent.infoHash, torrent.magnetURI))
|
||||||
torrent.on('metadata', torrentMetadata)
|
torrent.on('metadata', torrentMetadata)
|
||||||
torrent.on('ready', torrentReady)
|
torrent.on('ready', torrentReady)
|
||||||
torrent.on('done', torrentDone)
|
torrent.on('done', torrentDone)
|
||||||
@@ -360,11 +358,15 @@ function getAudioMetadata (infoHash, index) {
|
|||||||
: mm.parseStream(file.createReadStream(), file.name, options)
|
: mm.parseStream(file.createReadStream(), file.name, options)
|
||||||
|
|
||||||
onMetaData
|
onMetaData
|
||||||
.then(() => {
|
.then(
|
||||||
console.log(`metadata for file='${file.name}' completed.`)
|
() => console.log(`metadata for file='${file.name}' completed.`),
|
||||||
}).catch(function (err) {
|
err => {
|
||||||
return console.log('error getting audio metadata for ' + infoHash + ':' + index, err)
|
console.log(
|
||||||
})
|
`error getting audio metadata for ${infoHash}:${index}`,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectFiles (torrentOrInfoHash, selections) {
|
function selectFiles (torrentOrInfoHash, selections) {
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
chmod +x /opt/webtorrent-desktop/WebTorrent
|
|
||||||
ln -s -f /opt/webtorrent-desktop/WebTorrent /usr/bin/webtorrent-desktop
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
rm /usr/bin/webtorrent-desktop
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Name=$APP_NAME
|
|
||||||
Version=1.0
|
|
||||||
GenericName=BitTorrent Client
|
|
||||||
X-GNOME-FullName=$APP_NAME
|
|
||||||
Comment=Download and share files over BitTorrent
|
|
||||||
Type=Application
|
|
||||||
Icon=webtorrent-desktop
|
|
||||||
Terminal=false
|
|
||||||
Path=$APP_PATH
|
|
||||||
Exec=$EXEC_PATH %U
|
|
||||||
TryExec=$TRY_EXEC_PATH
|
|
||||||
StartupNotify=false
|
|
||||||
Categories=Network;FileTransfer;P2P;
|
|
||||||
MimeType=application/x-bittorrent;x-scheme-handler/magnet;x-scheme-handler/stream-magnet;
|
|
||||||
|
|
||||||
Actions=CreateNewTorrent;OpenTorrentFile;OpenTorrentAddress;
|
|
||||||
|
|
||||||
[Desktop Action CreateNewTorrent]
|
|
||||||
Name=Create New Torrent...
|
|
||||||
Exec=$EXEC_PATH -n
|
|
||||||
|
|
||||||
[Desktop Action OpenTorrentFile]
|
|
||||||
Name=Open Torrent File...
|
|
||||||
Exec=$EXEC_PATH -o
|
|
||||||
|
|
||||||
[Desktop Action OpenTorrentAddress]
|
|
||||||
Name=Open Torrent Address...
|
|
||||||
Exec=$EXEC_PATH -u
|
|
||||||
26
static/linux/webtorrent-desktop.ejs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[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<% } %>
|
||||||
|
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 %> <% } %>
|
||||||
|
|
||||||
|
[Desktop Action CreateNewTorrent]
|
||||||
|
Name=Create New Torrent...
|
||||||
|
<% if (name) { %>Exec=<%= name %> -n <% } %>
|
||||||
|
|
||||||
|
[Desktop Action OpenTorrentFile]
|
||||||
|
Name=Open Torrent File...
|
||||||
|
<% if (name) { %>Exec=<%= name %> -o <% } %>
|
||||||
|
|
||||||
|
[Desktop Action OpenTorrentAddress]
|
||||||
|
Name=Open Torrent Address...
|
||||||
|
<% if (name) { %>Exec=<%= name %> -u <% } %>
|
||||||
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 359 KiB After Width: | Height: | Size: 400 KiB |
|
Before Width: | Height: | Size: 705 KiB After Width: | Height: | Size: 737 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 627 KiB After Width: | Height: | Size: 681 KiB |
|
Before Width: | Height: | Size: 870 KiB After Width: | Height: | Size: 873 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 559 KiB After Width: | Height: | Size: 575 KiB |
|
Before Width: | Height: | Size: 705 KiB After Width: | Height: | Size: 737 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
@@ -1,5 +1,5 @@
|
|||||||
const Application = require('spectron').Application
|
const Application = require('spectron').Application
|
||||||
const cpFile = require('cp-file')
|
const { copyFileSync } = require('fs')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const mkdirp = require('mkdirp')
|
const mkdirp = require('mkdirp')
|
||||||
const parseTorrent = require('parse-torrent')
|
const parseTorrent = require('parse-torrent')
|
||||||
@@ -28,10 +28,15 @@ module.exports = {
|
|||||||
// Returns a promise that resolves to a Spectron Application once the app has loaded.
|
// Returns a promise that resolves to a Spectron Application once the app has loaded.
|
||||||
// Takes a Tape test. Makes some basic assertions to verify that the app loaded correctly.
|
// Takes a Tape test. Makes some basic assertions to verify that the app loaded correctly.
|
||||||
function createApp (t) {
|
function createApp (t) {
|
||||||
|
const userDataDir = process.platform === 'win32'
|
||||||
|
? path.join('C:\\Windows\\Temp', 'WebTorrentTest')
|
||||||
|
: path.join('/tmp', 'WebTorrentTest')
|
||||||
|
|
||||||
return new Application({
|
return new Application({
|
||||||
path: path.join(__dirname, '..', 'node_modules', '.bin',
|
path: path.join(__dirname, '..', 'node_modules', '.bin',
|
||||||
'electron' + (process.platform === 'win32' ? '.cmd' : '')),
|
'electron' + (process.platform === 'win32' ? '.cmd' : '')),
|
||||||
args: ['-r', path.join(__dirname, 'mocks.js'), path.join(__dirname, '..')],
|
args: ['-r', path.join(__dirname, 'mocks.js'), path.join(__dirname, '..')],
|
||||||
|
chromeDriverArgs: [`--user-data-dir=${userDataDir}`],
|
||||||
env: { NODE_ENV: 'test' },
|
env: { NODE_ENV: 'test' },
|
||||||
waitTimeout: 10e3
|
waitTimeout: 10e3
|
||||||
})
|
})
|
||||||
@@ -78,6 +83,12 @@ function endTest (app, t, err) {
|
|||||||
// Otherwise, create the reference screenshot: test/screenshots/<platform>/<name>.png
|
// Otherwise, create the reference screenshot: test/screenshots/<platform>/<name>.png
|
||||||
function screenshotCreateOrCompare (app, t, name) {
|
function screenshotCreateOrCompare (app, t, name) {
|
||||||
const ssDir = path.join(__dirname, 'screenshots', process.platform)
|
const ssDir = path.join(__dirname, 'screenshots', process.platform)
|
||||||
|
|
||||||
|
// check that path exists otherwise create it
|
||||||
|
if (!fs.existsSync(ssDir)) {
|
||||||
|
fs.mkdirSync(ssDir)
|
||||||
|
}
|
||||||
|
|
||||||
const ssPath = path.join(ssDir, name + '.png')
|
const ssPath = path.join(ssDir, name + '.png')
|
||||||
let ssBuf
|
let ssBuf
|
||||||
|
|
||||||
@@ -210,7 +221,7 @@ function extractImportantFields (parsedTorrent) {
|
|||||||
|
|
||||||
function copy (pathFrom, pathTo) {
|
function copy (pathFrom, pathTo) {
|
||||||
try {
|
try {
|
||||||
cpFile.sync(pathFrom, pathTo)
|
copyFileSync(pathFrom, pathTo)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Windows lets us create files and folders under C:\Windows\Temp,
|
// Windows lets us create files and folders under C:\Windows\Temp,
|
||||||
// but when you try to `copySync` into one of those folders, you get EPERM
|
// but when you try to `copySync` into one of those folders, you get EPERM
|
||||||
|
|||||||
@@ -47,10 +47,8 @@ test('create-torrent', function (t) {
|
|||||||
'wss://tracker.fastcast.nz',
|
'wss://tracker.fastcast.nz',
|
||||||
'wss://tracker.openwebtorrent.com'
|
'wss://tracker.openwebtorrent.com'
|
||||||
],
|
],
|
||||||
comment: undefined,
|
infoHash: 'b31a80b3dd807c2fdde4c4da1a0db6123fa35883',
|
||||||
infoHash: '4b087858a32e31a0d313b5f9e0a2e13c08c5403f',
|
|
||||||
name: 'tmp.jpg',
|
name: 'tmp.jpg',
|
||||||
private: false,
|
|
||||||
urlList: []
|
urlList: []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||