Fix player flakiness
* No more pause icon in the file list * Reset state.playng completely after each play * Fixes #318: false "cannot add dupe torrent" error
This commit is contained in:
@@ -20,6 +20,7 @@ var TorrentPlayer = require('./lib/torrent-player')
|
|||||||
var util = require('./util')
|
var util = require('./util')
|
||||||
var {setDispatch} = require('./lib/dispatcher')
|
var {setDispatch} = require('./lib/dispatcher')
|
||||||
setDispatch(dispatch)
|
setDispatch(dispatch)
|
||||||
|
var State = require('./state')
|
||||||
|
|
||||||
// This dependency is the slowest-loading, so we lazy load it
|
// This dependency is the slowest-loading, so we lazy load it
|
||||||
var Cast = null
|
var Cast = null
|
||||||
@@ -34,7 +35,7 @@ var crashReporter = electron.crashReporter
|
|||||||
var dialog = remote.require('dialog')
|
var dialog = remote.require('dialog')
|
||||||
|
|
||||||
// For easy debugging in Developer Tools
|
// For easy debugging in Developer Tools
|
||||||
var state = global.state = require('./state')
|
var state = global.state = State.getInitialState()
|
||||||
|
|
||||||
var vdomLoop
|
var vdomLoop
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ function init () {
|
|||||||
function lazyLoadCast () {
|
function lazyLoadCast () {
|
||||||
if (!Cast) {
|
if (!Cast) {
|
||||||
Cast = require('./lib/cast')
|
Cast = require('./lib/cast')
|
||||||
Cast.init(update) // Search the local network for Chromecast and Airplays
|
Cast.init(state, update) // Search the local network for Chromecast and Airplays
|
||||||
}
|
}
|
||||||
return Cast
|
return Cast
|
||||||
}
|
}
|
||||||
@@ -391,7 +392,7 @@ function loadState (cb) {
|
|||||||
console.log('loaded state from ' + cfg.filePath)
|
console.log('loaded state from ' + cfg.filePath)
|
||||||
|
|
||||||
// populate defaults if they're not there
|
// populate defaults if they're not there
|
||||||
state.saved = Object.assign({}, state.defaultSavedState, data)
|
state.saved = Object.assign({}, State.getDefaultSavedState(), data)
|
||||||
state.saved.torrents.forEach(function (torrentSummary) {
|
state.saved.torrents.forEach(function (torrentSummary) {
|
||||||
if (torrentSummary.displayName) torrentSummary.name = torrentSummary.displayName
|
if (torrentSummary.displayName) torrentSummary.name = torrentSummary.displayName
|
||||||
})
|
})
|
||||||
@@ -741,8 +742,7 @@ function pickFileToPlay (files) {
|
|||||||
|
|
||||||
function stopServer () {
|
function stopServer () {
|
||||||
ipcRenderer.send('wt-stop-server')
|
ipcRenderer.send('wt-stop-server')
|
||||||
state.playing.infoHash = null
|
state.playing = State.getDefaultPlayState()
|
||||||
state.playing.fileIndex = null
|
|
||||||
state.server = null
|
state.server = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,12 +766,12 @@ function openPlayer (infoHash, index, cb) {
|
|||||||
update()
|
update()
|
||||||
}, 10000) /* give it a few seconds */
|
}, 10000) /* give it a few seconds */
|
||||||
|
|
||||||
if (['downloading', 'seeding'].includes(torrentSummary.status)) {
|
if (torrentSummary.status === 'paused') {
|
||||||
openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb)
|
|
||||||
} else {
|
|
||||||
startTorrentingSummary(torrentSummary)
|
startTorrentingSummary(torrentSummary)
|
||||||
ipcRenderer.once('wt-ready-' + torrentSummary.infoHash,
|
ipcRenderer.once('wt-ready-' + torrentSummary.infoHash,
|
||||||
() => openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb))
|
() => openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb))
|
||||||
|
} else {
|
||||||
|
openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,36 @@ var chromecasts = require('chromecasts')()
|
|||||||
var dlnacasts = require('dlnacasts')()
|
var dlnacasts = require('dlnacasts')()
|
||||||
|
|
||||||
var config = require('../../config')
|
var config = require('../../config')
|
||||||
var state = require('../state')
|
|
||||||
|
// App state. Cast modifies state.playing and state.errors in response to events
|
||||||
|
var state
|
||||||
|
|
||||||
// Callback to notify module users when state has changed
|
// Callback to notify module users when state has changed
|
||||||
var update
|
var update
|
||||||
|
|
||||||
|
// setInterval() for updating cast status
|
||||||
var statusInterval = null
|
var statusInterval = null
|
||||||
|
|
||||||
|
// Start looking for cast devices on the local network
|
||||||
|
function init (appState, callback) {
|
||||||
|
state = appState
|
||||||
|
update = callback
|
||||||
|
|
||||||
|
// Listen for devices: Chromecast, DLNA and Airplay
|
||||||
|
chromecasts.on('update', function (player) {
|
||||||
|
state.devices.chromecast = chromecastPlayer(player)
|
||||||
|
})
|
||||||
|
|
||||||
|
dlnacasts.on('update', function (player) {
|
||||||
|
state.devices.dlna = dlnaPlayer(player)
|
||||||
|
})
|
||||||
|
|
||||||
|
var browser = airplay.createBrowser()
|
||||||
|
browser.on('deviceOn', function (player) {
|
||||||
|
state.devices.airplay = airplayPlayer(player)
|
||||||
|
}).start()
|
||||||
|
}
|
||||||
|
|
||||||
// chromecast player implementation
|
// chromecast player implementation
|
||||||
function chromecastPlayer (player) {
|
function chromecastPlayer (player) {
|
||||||
function addEvents () {
|
function addEvents () {
|
||||||
@@ -238,25 +261,6 @@ function dlnaPlayer (player) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// start export functions
|
|
||||||
function init (callback) {
|
|
||||||
update = callback
|
|
||||||
|
|
||||||
// Listen for devices: Chromecast, DLNA and Airplay
|
|
||||||
chromecasts.on('update', function (player) {
|
|
||||||
state.devices.chromecast = chromecastPlayer(player)
|
|
||||||
})
|
|
||||||
|
|
||||||
dlnacasts.on('update', function (player) {
|
|
||||||
state.devices.dlna = dlnaPlayer(player)
|
|
||||||
})
|
|
||||||
|
|
||||||
var browser = airplay.createBrowser()
|
|
||||||
browser.on('deviceOn', function (player) {
|
|
||||||
state.devices.airplay = airplayPlayer(player)
|
|
||||||
}).start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start polling cast device state, whenever we're connected
|
// Start polling cast device state, whenever we're connected
|
||||||
function startStatusInterval () {
|
function startStatusInterval () {
|
||||||
statusInterval = setInterval(function () {
|
statusInterval = setInterval(function () {
|
||||||
|
|||||||
@@ -5,22 +5,62 @@ var config = require('../config')
|
|||||||
var LocationHistory = require('./lib/location-history')
|
var LocationHistory = require('./lib/location-history')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/*
|
getInitialState,
|
||||||
* Temporary state disappears once the program exits.
|
getDefaultPlayState,
|
||||||
* It can contain complex objects like open connections, etc.
|
getDefaultSavedState
|
||||||
*/
|
}
|
||||||
client: null, /* the WebTorrent client */
|
|
||||||
server: null, /* local WebTorrent-to-HTTP server */
|
function getInitialState () {
|
||||||
prev: {}, /* used for state diffing in updateElectron() */
|
return {
|
||||||
location: new LocationHistory(),
|
/*
|
||||||
window: {
|
* Temporary state disappears once the program exits.
|
||||||
bounds: null, /* {x, y, width, height } */
|
* It can contain complex objects like open connections, etc.
|
||||||
isFocused: true,
|
*/
|
||||||
isFullScreen: false,
|
client: null, /* the WebTorrent client */
|
||||||
title: config.APP_WINDOW_TITLE
|
server: null, /* local WebTorrent-to-HTTP server */
|
||||||
},
|
prev: {}, /* used for state diffing in updateElectron() */
|
||||||
selectedInfoHash: null, /* the torrent we've selected to view details. see state.torrents */
|
location: new LocationHistory(),
|
||||||
playing: { /* the media (audio or video) that we're currently playing */
|
window: {
|
||||||
|
bounds: null, /* {x, y, width, height } */
|
||||||
|
isFocused: true,
|
||||||
|
isFullScreen: false,
|
||||||
|
title: config.APP_WINDOW_TITLE
|
||||||
|
},
|
||||||
|
selectedInfoHash: null, /* the torrent we've selected to view details. see state.torrents */
|
||||||
|
playing: getDefaultPlayState(), /* the media (audio or video) that we're currently playing */
|
||||||
|
devices: { /* playback devices like Chromecast and AppleTV */
|
||||||
|
airplay: null, /* airplay client. finds and manages AppleTVs */
|
||||||
|
chromecast: null /* chromecast client. finds and manages Chromecasts */
|
||||||
|
},
|
||||||
|
dock: {
|
||||||
|
badge: 0,
|
||||||
|
progress: 0
|
||||||
|
},
|
||||||
|
modal: null, /* modal popover */
|
||||||
|
errors: [], /* user-facing errors */
|
||||||
|
nextTorrentKey: 1, /* identify torrents for IPC between the main and webtorrent windows */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Saved state is read from and written to a file every time the app runs.
|
||||||
|
* It should be simple and minimal and must be JSON.
|
||||||
|
*
|
||||||
|
* Config path:
|
||||||
|
*
|
||||||
|
* OS X ~/Library/Application Support/WebTorrent/config.json
|
||||||
|
* Linux (XDG) $XDG_CONFIG_HOME/WebTorrent/config.json
|
||||||
|
* Linux (Legacy) ~/.config/WebTorrent/config.json
|
||||||
|
* Windows (> Vista) %LOCALAPPDATA%/WebTorrent/config.json
|
||||||
|
* Windows (XP, 2000) %USERPROFILE%/Local Settings/Application Data/WebTorrent/config.json
|
||||||
|
*
|
||||||
|
* Also accessible via `require('application-config')('WebTorrent').filePath`
|
||||||
|
*/
|
||||||
|
saved: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whenever we stop playing video or audio, here's what we reset state.playing to */
|
||||||
|
function getDefaultPlayState () {
|
||||||
|
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 */
|
||||||
location: 'local', /* 'local', 'chromecast', 'airplay' */
|
location: 'local', /* 'local', 'chromecast', 'airplay' */
|
||||||
@@ -31,37 +71,12 @@ module.exports = {
|
|||||||
isStalled: false,
|
isStalled: false,
|
||||||
lastTimeUpdate: 0, /* Unix time in ms */
|
lastTimeUpdate: 0, /* Unix time in ms */
|
||||||
mouseStationarySince: 0 /* Unix time in ms */
|
mouseStationarySince: 0 /* Unix time in ms */
|
||||||
},
|
}
|
||||||
devices: { /* playback devices like Chromecast and AppleTV */
|
}
|
||||||
airplay: null, /* airplay client. finds and manages AppleTVs */
|
|
||||||
chromecast: null /* chromecast client. finds and manages Chromecasts */
|
|
||||||
},
|
|
||||||
dock: {
|
|
||||||
badge: 0,
|
|
||||||
progress: 0
|
|
||||||
},
|
|
||||||
modal: null, /* modal popover */
|
|
||||||
errors: [], /* user-facing errors */
|
|
||||||
nextTorrentKey: 1, /* identify torrents for IPC between the main and webtorrent windows */
|
|
||||||
|
|
||||||
/*
|
/* If the saved state file doesn't exist yet, here's what we use instead */
|
||||||
* Saved state is read from and written to a file every time the app runs.
|
function getDefaultSavedState () {
|
||||||
* It should be simple and minimal and must be JSON.
|
return {
|
||||||
*
|
|
||||||
* Config path:
|
|
||||||
*
|
|
||||||
* OS X ~/Library/Application Support/WebTorrent/config.json
|
|
||||||
* Linux (XDG) $XDG_CONFIG_HOME/WebTorrent/config.json
|
|
||||||
* Linux (Legacy) ~/.config/WebTorrent/config.json
|
|
||||||
* Windows (> Vista) %LOCALAPPDATA%/WebTorrent/config.json
|
|
||||||
* Windows (XP, 2000) %USERPROFILE%/Local Settings/Application Data/WebTorrent/config.json
|
|
||||||
*
|
|
||||||
* Also accessible via `require('application-config')('WebTorrent').filePath`
|
|
||||||
*/
|
|
||||||
saved: {},
|
|
||||||
|
|
||||||
/* If the saved state file doesn't exist yet, here's what we use instead */
|
|
||||||
defaultSavedState: {
|
|
||||||
version: 1, /* make sure we can upgrade gracefully later */
|
version: 1, /* make sure we can upgrade gracefully later */
|
||||||
torrents: [
|
torrents: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ function TorrentList (state) {
|
|||||||
// First, find out how much of the file we've downloaded
|
// First, find out how much of the file we've downloaded
|
||||||
var isDone = file.numPiecesPresent === file.numPieces
|
var isDone = file.numPiecesPresent === file.numPieces
|
||||||
var progress = ''
|
var progress = ''
|
||||||
if (torrentSummary.progress) {
|
if (torrentSummary.progress && torrentSummary.progress.files) {
|
||||||
var fileProg = torrentSummary.progress.files[index]
|
var fileProg = torrentSummary.progress.files[index]
|
||||||
progress = Math.round(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%'
|
progress = Math.round(100 * fileProg.numPiecesPresent / fileProg.numPieces) + '%'
|
||||||
}
|
}
|
||||||
@@ -211,10 +211,7 @@ function TorrentList (state) {
|
|||||||
var icon
|
var icon
|
||||||
var rowClass = ''
|
var rowClass = ''
|
||||||
var handleClick
|
var handleClick
|
||||||
if (state.playing.infoHash === infoHash && state.playing.fileIndex === index) {
|
if (TorrentPlayer.isPlayable(file)) {
|
||||||
icon = 'pause_arrow' /* playing? add option to pause */
|
|
||||||
handleClick = undefined // TODO: pause audio
|
|
||||||
} else if (TorrentPlayer.isPlayable(file)) {
|
|
||||||
icon = 'play_arrow' /* playable? add option to play */
|
icon = 'play_arrow' /* playable? add option to play */
|
||||||
handleClick = dispatcher('play', infoHash, index)
|
handleClick = dispatcher('play', infoHash, index)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user