Compare commits

..

10 Commits

Author SHA1 Message Date
DC
44c3421e92 0.6.1 2016-05-26 03:46:32 -07:00
DC
7de3d3cc41 Clean up showCreateTorrent 2016-05-26 02:23:34 -07:00
DC
3d7f46da65 Disable WebRTC on Windows to work around Electron crash 2016-05-26 02:17:08 -07:00
DC
72d902e548 Fix selections migration
Should fix #583
2016-05-26 02:17:08 -07:00
DC
955fe76c3c Allow dropping files on dock icon
Fixes #584
2016-05-26 02:17:08 -07:00
Feross Aboukhadijeh
839bec0363 Merge pull request #588 from feross/dc/cleanup
Show error when drag-dropping hidden files
2016-05-26 01:06:46 -07:00
Feross Aboukhadijeh
9af4ce9a6b Merge pull request #589 from feross/dc/shortcuts
Simplify shortcuts. Go Back menu item
2016-05-26 00:54:30 -07:00
DC
205bf75c7e Simplify shortcuts. Go Back menu item
Fixes #585
2016-05-25 23:31:32 -07:00
DC
bafbf3d841 Show error when drag-dropping hidden files
...or anytime the user tries to create a torrent consisting only of hidden files, specifically dotfiles

Fixes #586
2016-05-25 23:15:26 -07:00
DC
1b0833fb45 Clean up player.js 2016-05-25 22:44:30 -07:00
8 changed files with 143 additions and 71 deletions

View File

@@ -12,7 +12,6 @@ var handlers = require('./handlers')
var ipc = require('./ipc')
var log = require('./log')
var menu = require('./menu')
var shortcuts = require('./shortcuts')
var squirrelWin32 = require('./squirrel-win32')
var tray = require('./tray')
var updater = require('./updater')
@@ -64,7 +63,6 @@ function init () {
windows.createMainWindow()
windows.createWebTorrentHiddenWindow()
menu.init()
shortcuts.init()
// To keep app startup fast, some code is delayed.
setTimeout(delayedInit, config.DELAYED_INIT)
@@ -132,6 +130,7 @@ function sliceArgv (argv) {
}
function processArgv (argv) {
var pathsToOpen = []
argv.forEach(function (arg) {
if (arg === '-n') {
menu.showOpenSeedFiles()
@@ -143,7 +142,15 @@ function processArgv (argv) {
// Ignore OS X launchd "process serial number" argument
// More: https://github.com/feross/webtorrent-desktop/issues/214
} else {
windows.main.send('dispatch', 'onOpen', arg)
pathsToOpen.push(arg)
}
})
if (pathsToOpen.length > 0) openFilePaths(pathsToOpen)
}
// Send files to the renderer process
// Opening files means either adding torrents, creating and seeding a torrent
// from files, or adding subtitles
function openFilePaths (paths) {
windows.main.send('dispatch', 'onOpen', paths)
}

View File

@@ -118,7 +118,15 @@ function decreasePlaybackRate () {
// Open the preferences window
function showPreferences () {
windows.main.send('dispatch', 'preferences')
if (windows.main) {
windows.main.send('dispatch', 'preferences')
}
}
function escapeBack () {
if (windows.main) {
windows.main.send('dispatch', 'escapeBack')
}
}
function onWindowShow () {
@@ -181,8 +189,7 @@ function showOpenSeedFile () {
properties: [ 'openFile' ]
}, function (selectedPaths) {
if (!Array.isArray(selectedPaths)) return
var selectedPath = selectedPaths[0]
windows.main.send('dispatch', 'showCreateTorrent', selectedPath)
windows.main.send('dispatch', 'showCreateTorrent', selectedPaths)
})
}
@@ -194,8 +201,7 @@ function showOpenSeedFiles () {
properties: [ 'openFile', 'openDirectory' ]
}, function (selectedPaths) {
if (!Array.isArray(selectedPaths)) return
var selectedPath = selectedPaths[0]
windows.main.send('dispatch', 'showCreateTorrent', selectedPath)
windows.main.send('dispatch', 'showCreateTorrent', selectedPaths)
})
}
@@ -322,6 +328,14 @@ function getAppMenuTemplate () {
click: showWebTorrentWindow
}
]
},
{
type: 'separator'
},
{
label: 'Go Back',
accelerator: 'Esc',
click: escapeBack
}
]
},
@@ -330,7 +344,7 @@ function getAppMenuTemplate () {
submenu: [
{
label: 'Play/Pause',
accelerator: 'CmdOrCtrl+P',
accelerator: 'Space',
click: playPause,
enabled: false
},

View File

@@ -1,26 +1,11 @@
module.exports = {
init,
onPlayerClose,
onPlayerOpen
}
var electron = require('electron')
var menu = require('./menu')
var windows = require('./windows')
function init () {
var localShortcut = require('electron-localshortcut')
// Alternate shortcuts. Most shortcuts are registered in menu,js, but Electron
// does not support multiple shortcuts for a single menu item.
localShortcut.register('CmdOrCtrl+Shift+F', menu.toggleFullScreen)
localShortcut.register('Space', () => windows.main.send('dispatch', 'playPause'))
// Hidden shortcuts, i.e. not shown in the menu
localShortcut.register('Esc', () => windows.main.send('dispatch', 'escapeBack'))
}
function onPlayerOpen () {
// Register special "media key" for play/pause, available on some keyboards
electron.globalShortcut.register(

View File

@@ -1,7 +1,7 @@
{
"name": "webtorrent-desktop",
"description": "WebTorrent, the streaming torrent client. For OS X, Windows, and Linux.",
"version": "0.6.0",
"version": "0.6.1",
"author": {
"name": "WebTorrent, LLC",
"email": "feross@feross.org",
@@ -22,7 +22,6 @@
"deep-equal": "^1.0.1",
"dlnacasts": "^0.1.0",
"drag-drop": "^2.11.0",
"electron-localshortcut": "^0.6.0",
"electron-prebuilt": "1.1.1",
"fs-extra": "^0.27.0",
"hyperx": "^2.0.2",

View File

@@ -164,7 +164,7 @@ function cleanUpConfig () {
}
// Migration: add per-file selections
if (!ts.selections) {
if (!ts.selections && ts.files) {
ts.selections = ts.files.map((x) => true)
}
})
@@ -228,7 +228,7 @@ function dispatch (action, ...args) {
ipcRenderer.send('showOpenTorrentFile') /* open torrent file */
}
if (action === 'showCreateTorrent') {
showCreateTorrent(args[0] /* fileOrFolder */)
showCreateTorrent(args[0] /* paths */)
}
if (action === 'createTorrent') {
createTorrent(args[0] /* options */)
@@ -803,7 +803,9 @@ function startTorrentingSummary (torrentSummary) {
// Shows the Create Torrent page with options to seed a given file or folder
function showCreateTorrent (files) {
if (Array.isArray(files)) {
// Files will either be an array of file objects, which we can send directly
// to the create-torrent screen
if (files.length === 0 || typeof files[0] !== 'string') {
state.location.go({
url: 'create-torrent',
files: files
@@ -811,13 +813,29 @@ function showCreateTorrent (files) {
return
}
var fileOrFolder = files
findFilesRecursive(fileOrFolder, showCreateTorrent)
// ... or it will be an array of mixed file and folder paths. We have to walk
// through all the folders and find the files
findFilesRecursive(files, showCreateTorrent)
}
// Recursively finds {name, path, size} for all files in a folder
// Calls `cb` on success, calls `onError` on failure
function findFilesRecursive (fileOrFolder, cb) {
function findFilesRecursive (paths, cb) {
if (paths.length > 1) {
var numComplete = 0
var ret = []
paths.forEach(function (path) {
findFilesRecursive([path], function (fileObjs) {
ret = ret.concat(fileObjs)
if (++numComplete === paths.length) {
cb(ret)
}
})
})
return
}
var fileOrFolder = paths[0]
fs.stat(fileOrFolder, function (err, stat) {
if (err) return onError(err)
@@ -835,16 +853,8 @@ function findFilesRecursive (fileOrFolder, cb) {
var folderPath = fileOrFolder
fs.readdir(folderPath, function (err, fileNames) {
if (err) return onError(err)
var numComplete = 0
var ret = []
fileNames.forEach(function (fileName) {
findFilesRecursive(path.join(folderPath, fileName), function (fileObjs) {
ret = ret.concat(fileObjs)
if (++numComplete === fileNames.length) {
cb(ret)
}
})
})
var paths = fileNames.map((fileName) => path.join(folderPath, fileName))
findFilesRecursive(paths, cb)
})
})
}

View File

@@ -8,7 +8,7 @@ var createTorrent = require('create-torrent')
var path = require('path')
var prettyBytes = require('prettier-bytes')
var {dispatch} = require('../lib/dispatcher')
var {dispatch, dispatcher} = require('../lib/dispatcher')
function CreateTorrentPage (state) {
var info = state.location.current()
@@ -17,17 +17,14 @@ function CreateTorrentPage (state) {
var files = info.files
.filter((f) => !f.name.startsWith('.'))
.map((f) => ({name: f.name, path: f.path, size: f.size}))
if (files.length === 0) return CreateTorrentErrorPage()
// First, extract the base folder that the files are all in
var pathPrefix = info.folderPath
if (!pathPrefix) {
if (files.length > 0) {
pathPrefix = files.map((x) => x.path).reduce(findCommonPrefix)
if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) {
pathPrefix = path.dirname(pathPrefix)
}
} else {
pathPrefix = files[0]
pathPrefix = files.map((x) => x.path).reduce(findCommonPrefix)
if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) {
pathPrefix = path.dirname(pathPrefix)
}
}
@@ -133,6 +130,27 @@ function CreateTorrentPage (state) {
}
}
function CreateTorrentErrorPage () {
return hx`
<div class='create-torrent-page'>
<h2>Create torrent</h2>
<p class="torrent-info">
<p>
Sorry, you must select at least one file that is not a hidden file.
</p>
<p>
Hidden files, starting with a . character, are not included.
</p>
</p>
<p class="float-right">
<button class='button-flat light' onclick=${dispatcher('back')}>
Cancel
</button>
</p>
</div>
`
}
// Finds the longest common prefix
function findCommonPrefix (a, b) {
for (var i = 0; i < a.length && i < b.length; i++) {

View File

@@ -37,7 +37,8 @@ function renderMedia (state) {
// Unfortunately, play/pause can't be done just by modifying HTML.
// Instead, grab the DOM node and play/pause it if necessary
var mediaElement = document.querySelector(state.playing.type) /* get the <video> or <audio> tag */
// Get the <video> or <audio> tag
var mediaElement = document.querySelector(state.playing.type)
if (mediaElement !== null) {
if (state.playing.isPaused && !mediaElement.paused) {
mediaElement.pause()
@@ -61,7 +62,8 @@ function renderMedia (state) {
// Switch to the newly added subtitle track, if available
var tracks = mediaElement.textTracks
for (var j = 0; j < tracks.length; j++) {
tracks[j].mode = (j === state.playing.subtitles.selectedIndex) ? 'showing' : 'hidden'
var isSelectedTrack = j === state.playing.subtitles.selectedIndex
tracks[j].mode = isSelectedTrack ? 'showing' : 'hidden'
}
// Save video position
@@ -114,7 +116,7 @@ function renderMedia (state) {
</div>
`
// As soon as the video loads enough to know the video dimensions, resize the window
// As soon as we know the video dimensions, resize the window
function onLoadedMetadata (e) {
if (state.playing.type !== 'video') return
var video = e.target
@@ -132,7 +134,8 @@ function renderMedia (state) {
function onCanPlay (e) {
var elem = e.target
if (state.playing.type === 'video' && elem.webkitVideoDecodedByteCount === 0) {
if (state.playing.type === 'video' &&
elem.webkitVideoDecodedByteCount === 0) {
dispatch('mediaError', 'Video codec unsupported')
} else if (elem.webkitAudioDecodedByteCount === 0) {
dispatch('mediaError', 'Audio codec unsupported')
@@ -157,7 +160,8 @@ function renderOverlay (state) {
} else if (elems.length !== 0) {
style = { backgroundImage: cssBackgroundImageDarkGradient() }
} else {
return /* Video, not audio, and it isn't stalled, so no spinner. No overlay needed. */
// Video playing, so no spinner. No overlay needed
return
}
return hx`
@@ -187,15 +191,37 @@ function renderAudioMetadata (state) {
track = info.track.no + ' of ' + info.track.of
}
// Show a small info box in the middle of the screen with title/album/artist/etc
// Show a small info box in the middle of the screen with title/album/etc
var elems = []
if (artist) elems.push(hx`<div class='audio-artist'><label>Artist</label>${artist}</div>`)
if (album) elems.push(hx`<div class='audio-album'><label>Album</label>${album}</div>`)
if (track) elems.push(hx`<div class='audio-track'><label>Track</label>${track}</div>`)
if (artist) {
elems.push(hx`
<div class='audio-artist'>
<label>Artist</label>${artist}
</div>
`)
}
if (album) {
elems.push(hx`
<div class='audio-album'>
<label>Album</label>${album}
</div>
`)
}
if (track) {
elems.push(hx`
<div class='audio-track'>
<label>Track</label>${track}
</div>
`)
}
// Align the title with the artist/etc info, if available. Otherwise, center the title
// Align the title with the other info, if available. Otherwise, center title
var emptyLabel = hx`<label></label>`
elems.unshift(hx`<div class='audio-title'>${elems.length ? emptyLabel : undefined}${title}</div>`)
elems.unshift(hx`
<div class='audio-title'>
${elems.length ? emptyLabel : undefined}${title}
</div>
`)
return hx`<div class='audio-metadata'>${elems}</div>`
}
@@ -278,18 +304,19 @@ function renderSubtitlesOptions (state) {
var isSelected = state.playing.subtitles.selectedIndex === ix
return hx`
<li onclick=${dispatcher('selectSubtitle', ix)}>
<i.icon>${isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
<i.icon>${'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
${track.label}
</li>
`
})
var noneSelected = state.playing.subtitles.selectedIndex === -1
var noneClass = 'radio_button_' + (noneSelected ? 'checked' : 'unchecked')
return hx`
<ul.subtitles-list>
${items}
<li onclick=${dispatcher('selectSubtitle', -1)}>
<i.icon>${noneSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
<i.icon>${noneClass}</i>
None
</li>
</ul>
@@ -351,7 +378,9 @@ function renderPlayerControls (state) {
var isOnChromecast = state.playing.location.startsWith('chromecast')
var isOnAirplay = state.playing.location.startsWith('airplay')
var isOnDlna = state.playing.location.startsWith('dlna')
var chromecastClass, chromecastHandler, airplayClass, airplayHandler, dlnaClass, dlnaHandler
var chromecastClass, chromecastHandler
var airplayClass, airplayHandler
var dlnaClass, dlnaHandler
if (isOnChromecast) {
chromecastClass = 'active'
dlnaClass = 'disabled'
@@ -413,10 +442,15 @@ function renderPlayerControls (state) {
// render volume
var volume = state.playing.volume
var volumeIcon = 'volume_' + (volume === 0 ? 'off' : volume < 0.3 ? 'mute' : volume < 0.6 ? 'down' : 'up')
var volumeStyle = { background: '-webkit-gradient(linear, left top, right top, ' +
'color-stop(' + (volume * 100) + '%, #eee), ' +
'color-stop(' + (volume * 100) + '%, #727272))'
var volumeIcon = 'volume_' + (
volume === 0 ? 'off'
: volume < 0.3 ? 'mute'
: volume < 0.6 ? 'down'
: 'up')
var volumeStyle = {
background: '-webkit-gradient(linear, left top, right top, ' +
'color-stop(' + (volume * 100) + '%, #eee), ' +
'color-stop(' + (volume * 100) + '%, #727272))'
}
elements.push(hx`
@@ -428,7 +462,8 @@ function renderPlayerControls (state) {
</i>
<input
class='volume-slider float-right'
type='range' min='0' max='1' step='0.05' value=${volumeChanging !== false ? volumeChanging : volume}
type='range' min='0' max='1' step='0.05'
value=${volumeChanging !== false ? volumeChanging : volume}
onmousedown=${handleVolumeScrub}
onmouseup=${handleVolumeScrub}
onmousemove=${handleVolumeScrub}
@@ -438,9 +473,11 @@ function renderPlayerControls (state) {
`)
// Show video playback progress
var currentTimeStr = formatTime(state.playing.currentTime)
var durationStr = formatTime(state.playing.duration)
elements.push(hx`
<span class='time float-left'>
${formatTime(state.playing.currentTime)} / ${formatTime(state.playing.duration)}
${currentTimeStr} / ${durationStr}
</span>
`)

View File

@@ -33,7 +33,9 @@ var client = window.client = new WebTorrent({
// HACK: OS X: Disable WebRTC peers to fix 100% CPU issue caused by Chrome bug.
// Fixed in Chrome 51, so we can remove this hack once Electron updates Chrome.
// Issue: https://github.com/feross/webtorrent-desktop/issues/353
wrtc: process.platform !== 'darwin'
// HACK #2: Windows: Disable WebRTC to fix Chrome 50 / Electron 1.1.[1-3] crash.
// Issue: https://github.com/electron/electron/issues/5629
wrtc: process.platform === 'linux'
}
})