Compare commits

...

32 Commits

Author SHA1 Message Date
Feross Aboukhadijeh
93a9ba11b6 App Sandboxing (OS X) 2016-05-21 01:08:42 -07:00
Feross Aboukhadijeh
b367c0b72e electron-prebuilt@1.1.1 2016-05-20 23:57:51 -07:00
Feross Aboukhadijeh
bf3b9ced74 Merge pull request #545 from feross/add-announcement
Add announcement feature
2016-05-20 16:10:27 -07:00
Feross Aboukhadijeh
9ecc12fb7f Merge pull request #544 from feross/vlc-on-top
VLC tweaks
2016-05-20 16:10:20 -07:00
Feross Aboukhadijeh
aafb1421c6 Merge pull request #543 from feross/on-open
Improve open behavior; Fix bugs in LocationHistory
2016-05-20 16:10:11 -07:00
Feross Aboukhadijeh
76c732bafb Merge pull request #541 from feross/remove-concat-stream
Use lighter-weight simple-concat instead of concat-stream
2016-05-20 16:09:46 -07:00
Feross Aboukhadijeh
ab476c9a9c Merge pull request #540 from feross/llc
WebTorrent, LLC
2016-05-20 16:09:18 -07:00
Feross Aboukhadijeh
4470310814 Merge pull request #549 from feross/nobin-debian-installer
nobin-debian-installer@0.0.10
2016-05-20 16:08:51 -07:00
Feross Aboukhadijeh
b6ba4f45c8 nobin-debian-installer@0.0.10 2016-05-20 14:37:54 -07:00
Feross Aboukhadijeh
84c860cfcb Make dialog async 2016-05-19 20:24:25 -07:00
Feross Aboukhadijeh
47c554a5ff Announcement: Support custom window title, main message, details 2016-05-19 20:17:51 -07:00
Feross Aboukhadijeh
4e46b16c13 auto updater: code style 2016-05-19 20:03:37 -07:00
Feross Aboukhadijeh
22cdcdb468 Add announcement feature
If there's a message returned by the given remote URL, then it will
show up for the user.

Useful in situations where the auto-updater is not working, or if
there's a security issue.
2016-05-19 20:03:02 -07:00
Feross Aboukhadijeh
f238b2d105 VLC tweaks
- Start video on top, so it's not obscured by other windows.

- Don't show "video title" which is just "http://localhost:xxxx"

- return after error
2016-05-19 19:43:43 -07:00
Feross Aboukhadijeh
3a81799828 Unify onOpen and onDrag, and support more cases
I don't think it matters whether the open comes from onOpen (opening
magnet, .torrent file, dragging file to dock, menu item) or from
dragging to the window.

These should use the same code path. The only relevant information is
the page of the app that we're on.

This change unifies the two methods, and supports dragging .torrent
files or creating a torrent when the player is active, if the dragged
files are not .srt or .vtt. We go back to the list, or to the create
torrent page in these situations, so it's not confusing for the user.

Always close open modals when handling an open.
2016-05-19 19:03:47 -07:00
Feross Aboukhadijeh
5dca89b61c When player is active, and magnet link is pasted, go back to list 2016-05-19 18:56:41 -07:00
Feross Aboukhadijeh
264c035ef7 After deleting torrent, remove just the player from forward stack 2016-05-19 18:56:10 -07:00
Feross Aboukhadijeh
8f39f8a23e After creating torrent, remove create torrent page from forward stack 2016-05-19 18:55:49 -07:00
Feross Aboukhadijeh
a29dbd7a71 Cancel button on create torrent page should only go back one page 2016-05-19 18:55:06 -07:00
Feross Aboukhadijeh
60a8969abc Add location.url() shorthand
location.url() === location.current().url
2016-05-19 18:54:44 -07:00
Feross Aboukhadijeh
9747d28514 Fix bugs in LocationHistory
- Handles more than 2 pages in the history robustly now!
  - When self._pending is true, all navigations are ignored.
- No more bug with back() being called twice too quickly.
- Remove "leaky abstraction" methods like clearPending() and pending()
- Add backToFirst() that properly unloads each page as it goes back to
the first one.
- Enhance clearForward() to support removing a specific page from the
forward stack, instead of nuking the whole thing.
2016-05-19 18:53:53 -07:00
Feross Aboukhadijeh
17ccd217a9 Use lighter-weight simple-concat instead of concat-stream
These modules do the same thing.

$ browserify -r simple-concat --no-builtins | wc -c
901

$ browserify -r concat-stream --no-builtins | wc -c
91998
2016-05-19 16:57:14 -07:00
Feross Aboukhadijeh
0df6198549 WebTorrent, LLC
What is WebTorrent, LLC?

WebTorrent, LLC is the legal entity that runs the WebTorrent project.
WebTorrent is still, and always will be, non-profit, open source, free
software.

There are no plans to make a profit from WebTorrent.
2016-05-19 16:43:51 -07:00
Feross Aboukhadijeh
74ada99f2b Merge pull request #538 from feross/dc/fix
Always handle when the user clicks a magnet link or torrent file, or uses File > Open Torrent
2016-05-19 16:26:56 -07:00
DC
81d5a367da Add new torrents to top and scroll to top
This means people who add a lot of torrents will always have their latest torrents at the top when they open the app, instead of having to scroll all the way down
2016-05-19 00:44:59 -07:00
DC
189e4bdc24 Always handle when the user opens a torrent
Fixes #523
2016-05-19 00:18:51 -07:00
DC
7bd30f8a16 Clean up addSubtitles (#535)
* Fix comments from #529

* Don't unlink deselected files

  I still want to do that eventually, but needs to be supported in WebTorrent

  See https://github.com/feross/webtorrent/issues/806
2016-05-18 02:07:24 -07:00
Feross Aboukhadijeh
7c6b7e4a6d changelog 2016-05-18 00:49:06 -07:00
Feross Aboukhadijeh
fe50f76619 0.5.1 2016-05-18 00:40:37 -07:00
Feross Aboukhadijeh
973a366b94 Fix the auto updater
I'm sorry.
2016-05-18 00:36:52 -07:00
Feross Aboukhadijeh
b0116deb35 appdmg@^0.4.3 2016-05-17 22:21:29 -07:00
Feross Aboukhadijeh
511382d384 package: remove unneeded 'npm prune'
prune just removes packages in node_modules that are not in
package.json, which is not necessary since we just removed node_modules
2016-05-17 22:10:43 -07:00
19 changed files with 285 additions and 138 deletions

View File

@@ -1,5 +1,11 @@
# WebTorrent Desktop Version History
## v0.5.1 - 2016-05-18
### Fixed
- Fix auto-updater (OS X, Windows).
## v0.5.0 - 2016-05-17
### Added

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) Feross Aboukhadijeh
Copyright (c) WebTorrent, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -87,4 +87,4 @@ brew install wine
## License
MIT. Copyright (c) [Feross Aboukhadijeh](http://feross.org).
MIT. Copyright (c) [WebTorrent, LLC](https://webtorrent.io).

View File

@@ -103,7 +103,7 @@ var all = {
var darwin = {
// Build for OS X
platform: 'darwin',
platform: 'mas',
// Build 64 bit binaries only.
arch: 'x64',
@@ -211,6 +211,8 @@ function buildDarwin (cb) {
}
]
infoPlist.ElectronTeamID = '5MAMC8G3L8'
fs.writeFileSync(infoPlistPath, plist.build(infoPlist))
// Copy torrent file icon into app bundle
@@ -248,8 +250,9 @@ function buildDarwin (cb) {
*/
var signOpts = {
app: appPath,
platform: 'darwin',
verbose: true
entitlements: path.join(config.STATIC_PATH, 'parent.entitlements'),
'entitlements-inherit': path.join(config.STATIC_PATH, 'child.entitlements'),
platform: 'mas'
}
console.log('OS X: Signing app...')

View File

@@ -6,6 +6,5 @@ npm run update-authors
git diff --exit-code
rm -rf node_modules/
npm install
npm prune
npm dedupe
npm test

View File

@@ -3,12 +3,14 @@ var fs = require('fs')
var path = require('path')
var APP_NAME = 'WebTorrent'
var APP_TEAM = 'The WebTorrent Project'
var APP_TEAM = 'WebTorrent, LLC'
var APP_VERSION = require('./package.json').version
var PORTABLE_PATH = path.join(path.dirname(process.execPath), 'Portable Settings')
module.exports = {
ANNOUNCEMENT_URL: 'https://webtorrent.io/desktop/announcement',
APP_COPYRIGHT: 'Copyright © 2014-2016 ' + APP_TEAM,
APP_FILE_ICON: path.join(__dirname, 'static', 'WebTorrentFile'),
APP_ICON: path.join(__dirname, 'static', 'WebTorrent'),
@@ -17,8 +19,7 @@ module.exports = {
APP_VERSION: APP_VERSION,
APP_WINDOW_TITLE: APP_NAME + ' (BETA)',
AUTO_UPDATE_URL: 'https://webtorrent.io/desktop/update' +
'?version=' + APP_VERSION + '&platform=' + process.platform,
AUTO_UPDATE_URL: 'https://webtorrent.io/desktop/update',
CRASH_REPORT_URL: 'https://webtorrent.io/desktop/crash-report',

38
main/announcement.js Normal file
View File

@@ -0,0 +1,38 @@
module.exports = {
init
}
var electron = require('electron')
var get = require('simple-get')
var config = require('../config')
var log = require('./log')
var ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL +
'?version=' + config.APP_VERSION +
'&platform=' + process.platform
function init () {
get.concat(ANNOUNCEMENT_URL, function (err, res, data) {
if (err) return log('failed to retrieve remote message')
if (res.statusCode !== 200) return log('no remote message')
try {
data = JSON.parse(data.toString())
} catch (err) {
data = {
title: 'WebTorrent Desktop Announcement',
message: 'WebTorrent Desktop Announcement',
detail: data.toString()
}
}
electron.dialog.showMessageBox({
type: 'info',
buttons: ['OK'],
title: data.title,
message: data.message,
detail: data.detail
}, function () {})
})
}

View File

@@ -5,6 +5,7 @@ var electron = require('electron')
var app = electron.app
var ipcMain = electron.ipcMain
var announcement = require('./announcement')
var config = require('../config')
var crashReporter = require('../crash-reporter')
var handlers = require('./handlers')
@@ -25,14 +26,14 @@ if (process.platform === 'win32') {
argv = argv.filter((arg) => arg.indexOf('--squirrel') === -1)
}
if (!shouldQuit) {
// Prevent multiple instances of app from running at same time. New instances signal
// this instance and quit.
shouldQuit = app.makeSingleInstance(onAppOpen)
if (shouldQuit) {
app.quit()
}
}
// if (!shouldQuit) {
// // Prevent multiple instances of app from running at same time. New instances signal
// // this instance and quit.
// shouldQuit = app.makeSingleInstance(onAppOpen)
// if (shouldQuit) {
// app.quit()
// }
// }
if (!shouldQuit) {
init()
@@ -91,6 +92,7 @@ function init () {
}
function delayedInit () {
announcement.init()
tray.init()
handlers.install()
updater.init()

View File

@@ -107,11 +107,11 @@ function init () {
})
ipcMain.on('vlcPlay', function (e, url) {
var args = ['--play-and-exit', '--quiet', url]
var args = ['--play-and-exit', '--video-on-top', '--no-video-title-show', '--quiet', url]
console.log('Running vlc ' + args.join(' '))
vlc.spawn(args, function (err, proc) {
if (err) windows.main.send('dispatch', 'vlcNotFound')
if (err) return windows.main.send('dispatch', 'vlcNotFound')
vlcProcess = proc
// If it works, close the modal after a second

View File

@@ -9,6 +9,10 @@ var config = require('../config')
var log = require('./log')
var windows = require('./windows')
var AUTO_UPDATE_URL = config.AUTO_UPDATE_URL +
'?version=' + config.APP_VERSION +
'&platform=' + process.platform
function init () {
if (process.platform === 'linux') {
initLinux()
@@ -20,7 +24,7 @@ function init () {
// The Electron auto-updater does not support Linux yet, so manually check for updates and
// `show the user a modal notification.
function initLinux () {
get.concat(config.AUTO_UPDATE_URL, onResponse)
get.concat(AUTO_UPDATE_URL, onResponse)
function onResponse (err, res, data) {
if (err) return log(`Update error: ${err.message}`)
@@ -67,5 +71,6 @@ function initDarwinWin32 () {
(e, notes, name, date, url) => log(`Update downloaded: ${name}: ${url}`)
)
electron.autoUpdater.setFeedURL(config.AUTO_UPDATE_URL)
electron.autoUpdater.setFeedURL(AUTO_UPDATE_URL)
electron.autoUpdater.checkForUpdates()
}

View File

@@ -1,11 +1,11 @@
{
"name": "webtorrent-desktop",
"description": "WebTorrent, the streaming torrent client. For OS X, Windows, and Linux.",
"version": "0.5.0",
"version": "0.5.1",
"author": {
"name": "Feross Aboukhadijeh",
"name": "WebTorrent, LLC",
"email": "feross@feross.org",
"url": "http://feross.org"
"url": "https://webtorrent.io"
},
"bin": {
"webtorrent-desktop": "./bin/cmd.js"
@@ -16,16 +16,14 @@
"dependencies": {
"airplay-js": "guerrerocarlos/node-airplay-js",
"application-config": "^0.2.1",
"async": "^2.0.0-rc.5",
"bitfield": "^1.0.2",
"chromecasts": "^1.8.0",
"concat-stream": "^1.5.1",
"create-torrent": "^3.24.5",
"deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0",
"drag-drop": "^2.11.0",
"electron-localshortcut": "^0.6.0",
"electron-prebuilt": "1.0.2",
"electron-prebuilt": "1.1.1",
"fs-extra": "^0.27.0",
"hyperx": "^2.0.2",
"iso-639-1": "^1.2.1",
@@ -34,6 +32,8 @@
"musicmetadata": "^2.0.2",
"network-address": "^1.1.0",
"prettier-bytes": "^1.0.1",
"run-parallel": "^1.1.6",
"simple-concat": "^1.0.0",
"simple-get": "^2.0.0",
"srt-to-vtt": "^1.1.1",
"virtual-dom": "^2.1.1",
@@ -49,7 +49,7 @@
"gh-release": "^2.0.3",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"nobin-debian-installer": "^0.0.9",
"nobin-debian-installer": "^0.0.10",
"open": "0.0.5",
"plist": "^1.2.0",
"rimraf": "^2.5.2",
@@ -70,7 +70,7 @@
"license": "MIT",
"main": "index.js",
"optionalDependencies": {
"appdmg": "^0.3.6"
"appdmg": "^0.4.3"
},
"productName": "WebTorrent",
"repository": {

View File

@@ -14,12 +14,12 @@ var ipcRenderer = electron.ipcRenderer
setupIpc()
var appConfig = require('application-config')('WebTorrent')
var Async = require('async')
var concat = require('concat-stream')
var concat = require('simple-concat')
var dragDrop = require('drag-drop')
var fs = require('fs-extra')
var iso639 = require('iso-639-1')
var mainLoop = require('main-loop')
var parallel = require('run-parallel')
var path = require('path')
var createElement = require('virtual-dom/create-element')
@@ -87,7 +87,7 @@ function init () {
// OS integrations:
// ...drag and drop a torrent or video file to play or seed
dragDrop('body', (files) => dispatch('onOpen', files))
dragDrop('body', onOpen)
// ...same thing if you paste a torrent
document.addEventListener('paste', onPaste)
@@ -252,16 +252,7 @@ function dispatch (action, ...args) {
setDimensions(args[0] /* dimensions */)
}
if (action === 'backToList') {
// Exit any modals and screens with a back button
state.modal = null
while (state.location.hasBack()) state.location.back()
// Work around virtual-dom issue: it doesn't expose its redraw function,
// and only redraws on requestAnimationFrame(). That means when the user
// closes the window (hide window / minimize to tray) and we want to pause
// the video, we update the vdom but it keeps playing until you reopen!
var mediaTag = document.querySelector('video,audio')
if (mediaTag) mediaTag.pause()
backToList()
}
if (action === 'escapeBack') {
if (state.modal) {
@@ -282,15 +273,14 @@ function dispatch (action, ...args) {
playPause()
}
if (action === 'play') {
if (state.location.pending()) return
state.location.go({
url: 'player',
onbeforeload: function (cb) {
play()
openPlayer(args[0] /* infoHash */, args[1] /* index */, cb)
},
onbeforeunload: closePlayer
})
play()
}
if (action === 'playbackJump') {
jumpToTime(args[0] /* seconds */)
@@ -314,7 +304,7 @@ function dispatch (action, ...args) {
state.playing.isStalled = true
}
if (action === 'mediaError') {
if (state.location.current().url === 'player') {
if (state.location.url() === 'player') {
state.playing.location = 'error'
ipcRenderer.send('checkForVLC')
ipcRenderer.once('checkForVLC', function (e, isInstalled) {
@@ -394,7 +384,7 @@ function pause () {
}
function playPause () {
if (state.location.current().url !== 'player') return
if (state.location.url() !== 'player') return
if (state.playing.isPaused) {
play()
} else {
@@ -436,6 +426,24 @@ function openSubtitles () {
})
}
// Quits any modal popovers and returns to the torrent list screen
function backToList () {
// Exit any modals and screens with a back button
state.modal = null
state.location.backToFirst(function () {
// If we were already on the torrent list, scroll to the top
var contentTag = document.querySelector('.content')
if (contentTag) contentTag.scrollTop = 0
// Work around virtual-dom issue: it doesn't expose its redraw function,
// and only redraws on requestAnimationFrame(). That means when the user
// closes the window (hide window / minimize to tray) and we want to pause
// the video, we update the vdom but it keeps playing until you reopen!
var mediaTag = document.querySelector('video,audio')
if (mediaTag) mediaTag.pause()
})
}
// Checks whether we are connected and already casting
// Returns false if we not casting (state.playing.location === 'local')
// or if we're trying to connect but haven't yet ('chromecast-pending', etc)
@@ -546,26 +554,32 @@ function saveState () {
update()
}
// Called when the user drag-drops files onto the app
function onOpen (files) {
if (!Array.isArray(files)) files = [ files ]
// In the player, the only drag-drop function is adding subtitles
var isInPlayer = state.location.current().url === 'player'
if (isInPlayer) {
return addSubtitles(files.filter(isSubtitle), true)
if (state.modal) {
state.modal = null
}
// Otherwise, you can only drag-drop onto the home screen
var isHome = state.location.current().url === 'home' && !state.modal
if (isHome) {
var subtitles = files.filter(isSubtitle)
if (state.location.url() === 'home' || subtitles.length === 0) {
if (files.every(isTorrent)) {
// All .torrent files? Start downloading
if (state.location.url() !== 'home') {
backToList()
}
// All .torrent files? Add them.
files.forEach(addTorrent)
} else {
// Show the Create Torrent screen. Let's seed those files.
showCreateTorrent(files)
}
} else if (state.location.url() === 'player') {
addSubtitles(subtitles, true)
}
update()
}
function isTorrent (file) {
@@ -592,6 +606,7 @@ function getTorrentSummary (torrentKey) {
// Adds a torrent to the list, starts downloading/seeding. TorrentID can be a
// magnet URI, infohash, or torrent file: https://github.com/feross/webtorrent#clientaddtorrentid-opts-function-ontorrent-torrent-
function addTorrent (torrentId) {
backToList()
var torrentKey = state.nextTorrentKey++
var path = state.saved.downloadPath
if (torrentId.path) {
@@ -606,22 +621,23 @@ function addSubtitles (files, autoSelect) {
if (state.playing.type !== 'video') return
// Read the files concurrently, then add all resulting subtitle tracks
console.log(files)
var subs = state.playing.subtitles
Async.map(files, loadSubtitle, function (err, tracks) {
var jobs = files.map((file) => (cb) => loadSubtitle(file, cb))
parallel(jobs, function (err, tracks) {
if (err) return onError(err)
for (var i = 0; i < tracks.length; i++) {
// No dupes allowed
var track = tracks[i]
if (subs.tracks.some((t) => track.filePath === t.filePath)) continue
if (state.playing.subtitles.tracks.some(
(t) => track.filePath === t.filePath)) continue
// Add the track
subs.tracks.push(track)
state.playing.subtitles.tracks.push(track)
// If we're auto-selecting a track, try to find one in the user's language
if (autoSelect && (i === 0 || isSystemLanguage(track.language))) {
state.playing.subtitles.selectedIndex = subs.tracks.length - 1
state.playing.subtitles.selectedIndex =
state.playing.subtitles.tracks.length - 1
}
}
@@ -636,7 +652,12 @@ function loadSubtitle (file, cb) {
// Read the .SRT or .VTT file, parse it, add subtitle track
var filePath = file.path || file
fs.createReadStream(filePath).pipe(srtToVtt()).pipe(concat(function (buf) {
var vttStream = fs.createReadStream(filePath).pipe(srtToVtt())
concat(vttStream, function (err, buf) {
if (err) return onError(new Error('Error parsing subtitles file.'))
// Detect what language the subtitles are in
var vttContents = buf.toString().replace(/(.*-->.*)/g, '')
var langDetected = (new LanguageDetect()).detect(vttContents, 2)
@@ -655,7 +676,7 @@ function loadSubtitle (file, cb) {
}
cb(null, track)
}))
})
}
function selectSubtitle (ix) {
@@ -728,7 +749,6 @@ function startTorrentingSummary (torrentSummary) {
// Shows the Create Torrent page with options to seed a given file or folder
function showCreateTorrent (files) {
if (Array.isArray(files)) {
if (state.location.pending() || state.location.current().url !== 'home') return
state.location.go({
url: 'create-torrent',
files: files
@@ -778,6 +798,9 @@ function findFilesRecursive (fileOrFolder, cb) {
function createTorrent (options) {
var torrentKey = state.nextTorrentKey++
ipcRenderer.send('wt-create-torrent', torrentKey, options)
state.location.backToFirst(function () {
state.location.clearForward('create-torrent')
})
}
function torrentInfoHash (torrentKey, infoHash) {
@@ -790,7 +813,7 @@ function torrentInfoHash (torrentKey, infoHash) {
torrentKey: torrentKey,
status: 'new'
}
state.saved.torrents.push(torrentSummary)
state.saved.torrents.unshift(torrentSummary)
sound.play('ADD')
}
@@ -1059,7 +1082,7 @@ function deleteTorrent (infoHash) {
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
if (index > -1) state.saved.torrents.splice(index, 1)
saveStateThrottled()
state.location.clearForward() // prevent user from going forward to a deleted torrent
state.location.clearForward('player') // prevent user from going forward to a deleted torrent
sound.play('DELETE')
}
@@ -1207,7 +1230,7 @@ function showDoneNotification (torrent) {
// * The video is paused
// * The video is playing remotely on Chromecast or Airplay
function showOrHidePlayerControls () {
var hideControls = state.location.current().url === 'player' &&
var hideControls = state.location.url() === 'player' &&
state.playing.mouseStationarySince !== 0 &&
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
!state.playing.isPaused &&
@@ -1242,8 +1265,10 @@ function onPaste (e) {
torrentIds.forEach(function (torrentId) {
torrentId = torrentId.trim()
if (torrentId.length === 0) return
dispatch('addTorrent', torrentId)
addTorrent(torrentId)
})
update()
}
function onFocus (e) {

View File

@@ -4,81 +4,123 @@ function LocationHistory () {
if (!new.target) return new LocationHistory()
this._history = []
this._forward = []
this._pending = null
this._pending = false
}
LocationHistory.prototype.go = function (page, cb) {
console.log('go', page)
this.clearForward()
this._go(page, cb)
}
LocationHistory.prototype._go = function (page, cb) {
if (this._pending) return
if (page.onbeforeload) {
this._pending = page
page.onbeforeload((err) => {
if (this._pending !== page) return /* navigation was cancelled */
this._pending = null
if (err) {
if (cb) cb(err)
return
}
this._history.push(page)
if (cb) cb()
})
} else {
this._history.push(page)
if (cb) cb()
}
}
LocationHistory.prototype.back = function (cb) {
if (this._history.length <= 1) return
var page = this._history.pop()
if (page.onbeforeunload) {
// TODO: this is buggy. If the user clicks back twice, then those pages
// may end up in _forward in the wrong order depending on which onbeforeunload
// call finishes first.
page.onbeforeunload(() => {
this._forward.push(page)
if (cb) cb()
})
} else {
this._forward.push(page)
if (cb) cb()
}
}
LocationHistory.prototype.forward = function (cb) {
if (this._forward.length === 0) return
var page = this._forward.pop()
this._go(page, cb)
}
LocationHistory.prototype.clearForward = function () {
this._forward = []
LocationHistory.prototype.url = function () {
return this.current() && this.current().url
}
LocationHistory.prototype.current = function () {
return this._history[this._history.length - 1]
}
LocationHistory.prototype.go = function (page, cb) {
if (!cb) cb = noop
if (this._pending) return cb(null)
console.log('go', page)
this.clearForward()
this._go(page, cb)
}
LocationHistory.prototype.back = function (cb) {
var self = this
if (!cb) cb = noop
if (self._history.length <= 1 || self._pending) return cb(null)
var page = self._history.pop()
self._unload(page, done)
function done (err) {
if (err) return cb(err)
self._forward.push(page)
self._load(self.current(), cb)
}
}
LocationHistory.prototype.hasBack = function () {
return this._history.length > 1
}
LocationHistory.prototype.forward = function (cb) {
if (!cb) cb = noop
if (this._forward.length === 0 || this._pending) return cb(null)
var page = this._forward.pop()
this._go(page, cb)
}
LocationHistory.prototype.hasForward = function () {
return this._forward.length > 0
}
LocationHistory.prototype.pending = function () {
return this._pending
LocationHistory.prototype.clearForward = function (url) {
if (url == null) {
this._forward = []
} else {
console.log(this._forward)
console.log(url)
this._forward = this._forward.filter(function (page) {
return page.url !== url
})
}
}
LocationHistory.prototype.clearPending = function () {
this._pending = null
LocationHistory.prototype.backToFirst = function (cb) {
var self = this
if (!cb) cb = noop
if (self._history.length <= 1) return cb(null)
self.back(function (err) {
if (err) return cb(err)
self.backToFirst(cb)
})
}
LocationHistory.prototype._go = function (page, cb) {
var self = this
if (!cb) cb = noop
self._unload(self.current(), done1)
function done1 (err) {
if (err) return cb(err)
self._load(page, done2)
}
function done2 (err) {
if (err) return cb(err)
self._history.push(page)
cb(null)
}
}
LocationHistory.prototype._load = function (page, cb) {
var self = this
self._pending = true
if (page && page.onbeforeload) page.onbeforeload(done)
else done(null)
function done (err) {
self._pending = false
cb(err)
}
}
LocationHistory.prototype._unload = function (page, cb) {
var self = this
self._pending = true
if (page && page.onbeforeunload) page.onbeforeunload(done)
else done(null)
function done (err) {
self._pending = false
cb(err)
}
}
function noop () {}

View File

@@ -22,7 +22,7 @@ function App (state) {
// * The mouse is over the controls or we're scrubbing (see CSS)
// * The video is paused
// * The video is playing remotely on Chromecast or Airplay
var hideControls = state.location.current().url === 'player' &&
var hideControls = state.location.url() === 'player' &&
state.playing.mouseStationarySince !== 0 &&
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
!state.playing.isPaused &&
@@ -30,10 +30,10 @@ function App (state) {
// Hide the header on Windows/Linux when in the player
// On OSX, the header appears as part of the title bar
var hideHeader = process.platform !== 'darwin' && state.location.current().url === 'player'
var hideHeader = process.platform !== 'darwin' && state.location.url() === 'player'
var cls = [
'view-' + state.location.current().url, /* e.g. view-home, view-player */
'view-' + state.location.url(), /* e.g. view-home, view-player */
'is-' + process.platform /* e.g. is-darwin, is-win32, is-linux */
]
if (state.window.isFullScreen) cls.push('is-fullscreen')
@@ -54,12 +54,13 @@ function App (state) {
function getErrorPopover (state) {
var now = new Date().getTime()
var recentErrors = state.errors.filter((x) => now - x.time < 5000)
var hasErrors = recentErrors.length > 0
var errorElems = recentErrors.map(function (error) {
return hx`<div class='error'>${error.message}</div>`
})
return hx`
<div class='error-popover ${recentErrors.length > 0 ? 'visible' : 'hidden'}'>
<div class='error-popover ${hasErrors ? 'visible' : 'hidden'}'>
<div class='title'>Error</div>
${errorElems}
</div>
@@ -80,6 +81,6 @@ function getModal (state) {
}
function getView (state) {
var url = state.location.current().url
var url = state.location.url()
return Views[url](state)
}

View File

@@ -119,11 +119,10 @@ function CreateTorrentPage (state) {
comment: comment
}
dispatch('createTorrent', options)
dispatch('backToList')
}
function handleCancel () {
dispatch('backToList')
dispatch('back')
}
function handleToggleShowAdvanced () {

View File

@@ -37,7 +37,7 @@ function Header (state) {
}
function getAddButton () {
if (state.location.current().url !== 'player') {
if (state.location.url() !== 'player') {
return hx`
<i
class='icon add'

View File

@@ -349,10 +349,6 @@ function selectFiles (torrentOrInfoHash, selections) {
} else {
console.log('deselecting file ' + i + ' of torrent ' + torrent.name)
file.deselect()
// If we deselected a file, try to nuke it to save disk space
var filePath = path.join(torrent.path, file.path)
fs.unlink(filePath) // Ignore errors for now
}
}
}

10
static/child.entitlements Normal file
View File

@@ -0,0 +1,10 @@
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,20 @@
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>5MAMC8G3L8.io.webtorrent.webtorrent</string>
</array>
</dict>
</plist>