Open multi-file torrents as playlists
This commit is contained in:
@@ -64,6 +64,10 @@ function init () {
|
||||
thumbar.enable()
|
||||
})
|
||||
|
||||
ipc.on('onPlayerUpdate', function (e, ...args) {
|
||||
menu.onPlayerUpdate(...args)
|
||||
})
|
||||
|
||||
ipc.on('onPlayerClose', function () {
|
||||
menu.setPlayerOpen(false)
|
||||
powerSaveBlocker.disable()
|
||||
|
||||
@@ -3,6 +3,7 @@ module.exports = {
|
||||
setPlayerOpen,
|
||||
setWindowFocus,
|
||||
setAllowNav,
|
||||
onPlayerUpdate,
|
||||
onToggleAlwaysOnTop,
|
||||
onToggleFullScreen
|
||||
}
|
||||
@@ -25,6 +26,8 @@ function init () {
|
||||
|
||||
function setPlayerOpen (flag) {
|
||||
getMenuItem('Play/Pause').enabled = flag
|
||||
getMenuItem('Skip Next').enabled = flag
|
||||
getMenuItem('Skip Previous').enabled = flag
|
||||
getMenuItem('Increase Volume').enabled = flag
|
||||
getMenuItem('Decrease Volume').enabled = flag
|
||||
getMenuItem('Step Forward').enabled = flag
|
||||
@@ -32,6 +35,16 @@ function setPlayerOpen (flag) {
|
||||
getMenuItem('Increase Speed').enabled = flag
|
||||
getMenuItem('Decrease Speed').enabled = flag
|
||||
getMenuItem('Add Subtitles File...').enabled = flag
|
||||
|
||||
if (flag === false) {
|
||||
getMenuItem('Skip Next').enabled = false
|
||||
getMenuItem('Skip Previous').enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
function onPlayerUpdate (hasNext, hasPrevious) {
|
||||
getMenuItem('Skip Next').enabled = hasNext
|
||||
getMenuItem('Skip Previous').enabled = hasPrevious
|
||||
}
|
||||
|
||||
function setWindowFocus (flag) {
|
||||
@@ -187,6 +200,21 @@ function getMenuTemplate () {
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Skip Next',
|
||||
accelerator: 'N',
|
||||
click: () => windows.main.dispatch('nextTrack'),
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
label: 'Skip Previous',
|
||||
accelerator: 'P',
|
||||
click: () => windows.main.dispatch('previousTrack'),
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Increase Volume',
|
||||
accelerator: 'CmdOrCtrl+Up',
|
||||
|
||||
@@ -12,9 +12,19 @@ function enable () {
|
||||
'MediaPlayPause',
|
||||
() => windows.main.dispatch('playPause')
|
||||
)
|
||||
electron.globalShortcut.register(
|
||||
'MediaNextTrack',
|
||||
() => windows.main.dispatch('nextTrack')
|
||||
)
|
||||
electron.globalShortcut.register(
|
||||
'MediaPreviousTrack',
|
||||
() => windows.main.dispatch('previousTrack')
|
||||
)
|
||||
}
|
||||
|
||||
function disable () {
|
||||
// Return the media key to the OS, so other apps can use it.
|
||||
electron.globalShortcut.unregister('MediaPlayPause')
|
||||
electron.globalShortcut.unregister('MediaNextTrack')
|
||||
electron.globalShortcut.unregister('MediaPreviousTrack')
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ module.exports = class MediaController {
|
||||
|
||||
openExternalPlayer () {
|
||||
var state = this.state
|
||||
ipcRenderer.send('openExternalPlayer', state.saved.prefs.externalPlayerPath, state.server.localURL, state.window.title)
|
||||
var mediaURL = state.server.localURL + '/' + state.playlist.getCurrent().fileIndex
|
||||
ipcRenderer.send('openExternalPlayer', state.saved.prefs.externalPlayerPath, mediaURL, state.window.title)
|
||||
state.playing.location = 'external'
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ const errors = require('../lib/errors')
|
||||
const sound = require('../lib/sound')
|
||||
const TorrentPlayer = require('../lib/torrent-player')
|
||||
const TorrentSummary = require('../lib/torrent-summary')
|
||||
const Playlist = require('../lib/playlist')
|
||||
const State = require('../lib/state')
|
||||
|
||||
const ipcRenderer = electron.ipcRenderer
|
||||
@@ -26,16 +27,37 @@ module.exports = class PlaybackController {
|
||||
// * Stream, if not already fully downloaded
|
||||
// * If no file index is provided, pick the default file to play
|
||||
playFile (infoHash, index /* optional */) {
|
||||
this.state.location.go({
|
||||
url: 'player',
|
||||
setup: (cb) => {
|
||||
this.play()
|
||||
this.openPlayer(infoHash, index, cb)
|
||||
},
|
||||
destroy: () => this.closePlayer()
|
||||
}, (err) => {
|
||||
if (err) dispatch('error', err)
|
||||
})
|
||||
var state = this.state
|
||||
if (state.location.url() === 'player') {
|
||||
this.play()
|
||||
state.playlist.jumpToFile(infoHash, index)
|
||||
this.updatePlayer(false, callback)
|
||||
} else {
|
||||
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||
var playlist = new Playlist(torrentSummary)
|
||||
|
||||
// automatically choose which file in the torrent to play, if necessary
|
||||
if (index === undefined) index = torrentSummary.defaultPlayFileIndex
|
||||
if (index === undefined) index = TorrentPlayer.pickFileToPlay(torrentSummary.files)
|
||||
if (index === undefined) return this.onError(new errors.UnplayableError())
|
||||
|
||||
playlist.jumpToFile(infoHash, index)
|
||||
|
||||
state.location.go({
|
||||
url: 'player',
|
||||
setup: (cb) => {
|
||||
this.play()
|
||||
this.openPlayer(playlist, cb)
|
||||
},
|
||||
destroy: () => this.closePlayer()
|
||||
}, (err) => {
|
||||
if (err) dispatch('error', err)
|
||||
})
|
||||
}
|
||||
|
||||
function callback (err) {
|
||||
if (err) this.onError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Open a file in OS default app.
|
||||
@@ -64,6 +86,30 @@ module.exports = class PlaybackController {
|
||||
else this.pause()
|
||||
}
|
||||
|
||||
// Play next file in list (if any)
|
||||
nextTrack () {
|
||||
var state = this.state
|
||||
if (state.playlist && state.playlist.hasNext()) {
|
||||
state.playlist.next()
|
||||
this.updatePlayer(false, (err) => {
|
||||
if (err) this.onError(err)
|
||||
else this.play()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Play previous track in list (if any)
|
||||
previousTrack () {
|
||||
var state = this.state
|
||||
if (state.playlist && state.playlist.hasPrevious()) {
|
||||
state.playlist.previous()
|
||||
this.updatePlayer(false, (err) => {
|
||||
if (err) this.onError(err)
|
||||
else this.play()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Play (unpause) the current media
|
||||
play () {
|
||||
var state = this.state
|
||||
@@ -167,14 +213,16 @@ module.exports = class PlaybackController {
|
||||
return false
|
||||
}
|
||||
|
||||
// Opens the video player to a specific torrent
|
||||
openPlayer (infoHash, index, cb) {
|
||||
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||
// Opens the video player to a specific playlist
|
||||
openPlayer (playlist, cb) {
|
||||
var state = this.state
|
||||
state.playlist = playlist
|
||||
|
||||
// automatically choose which file in the torrent to play, if necessary
|
||||
if (index === undefined) index = torrentSummary.defaultPlayFileIndex
|
||||
if (index === undefined) index = TorrentPlayer.pickFileToPlay(torrentSummary.files)
|
||||
if (index === undefined) return cb(new errors.UnplayableError())
|
||||
var track = playlist.getCurrent()
|
||||
if (track === undefined) return cb(new errors.UnplayableError())
|
||||
|
||||
var torrentSummary = TorrentSummary.getByKey(state, state.playlist.getInfoHash())
|
||||
state.playing.infoHash = torrentSummary.infoHash
|
||||
|
||||
// update UI to show pending playback
|
||||
if (torrentSummary.progress !== 1) sound.play('PLAY')
|
||||
@@ -191,50 +239,7 @@ module.exports = class PlaybackController {
|
||||
this.update()
|
||||
}, 10000) /* give it a few seconds */
|
||||
|
||||
if (torrentSummary.status === 'paused') {
|
||||
dispatch('startTorrentingSummary', torrentSummary.torrentKey)
|
||||
ipcRenderer.once('wt-ready-' + torrentSummary.infoHash,
|
||||
() => this.openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb))
|
||||
} else {
|
||||
this.openPlayerFromActiveTorrent(torrentSummary, index, timeout, cb)
|
||||
}
|
||||
}
|
||||
|
||||
openPlayerFromActiveTorrent (torrentSummary, index, timeout, cb) {
|
||||
var fileSummary = torrentSummary.files[index]
|
||||
|
||||
// update state
|
||||
var state = this.state
|
||||
state.playing.infoHash = torrentSummary.infoHash
|
||||
state.playing.fileIndex = index
|
||||
state.playing.type = TorrentPlayer.isVideo(fileSummary) ? 'video'
|
||||
: TorrentPlayer.isAudio(fileSummary) ? 'audio'
|
||||
: 'other'
|
||||
|
||||
// pick up where we left off
|
||||
if (fileSummary.currentTime) {
|
||||
var fraction = fileSummary.currentTime / fileSummary.duration
|
||||
var secondsLeft = fileSummary.duration - fileSummary.currentTime
|
||||
if (fraction < 0.9 && secondsLeft > 10) {
|
||||
state.playing.jumpToTime = fileSummary.currentTime
|
||||
}
|
||||
}
|
||||
|
||||
// if it's audio, parse out the metadata (artist, title, etc)
|
||||
if (state.playing.type === 'audio' && !fileSummary.audioInfo) {
|
||||
ipcRenderer.send('wt-get-audio-metadata', torrentSummary.infoHash, index)
|
||||
}
|
||||
|
||||
// if it's video, check for subtitles files that are done downloading
|
||||
dispatch('checkForSubtitles')
|
||||
|
||||
// enable previously selected subtitle track
|
||||
if (fileSummary.selectedSubtitle) {
|
||||
dispatch('addSubtitles', [fileSummary.selectedSubtitle], true)
|
||||
}
|
||||
|
||||
ipcRenderer.send('wt-start-server', torrentSummary.infoHash, index)
|
||||
ipcRenderer.once('wt-server-' + torrentSummary.infoHash, (e, info) => {
|
||||
this.startServer(torrentSummary, () => {
|
||||
clearTimeout(timeout)
|
||||
|
||||
// if we timed out (user clicked play a long time ago), don't autoplay
|
||||
@@ -245,24 +250,84 @@ module.exports = class PlaybackController {
|
||||
return this.update()
|
||||
}
|
||||
|
||||
state.window.title = torrentSummary.files[state.playing.fileIndex].name
|
||||
|
||||
// play in VLC if set as default player (Preferences / Playback / Play in VLC)
|
||||
if (this.state.saved.prefs.openExternalPlayer) {
|
||||
dispatch('openExternalPlayer')
|
||||
this.update()
|
||||
cb()
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, play the video
|
||||
this.update()
|
||||
|
||||
ipcRenderer.send('onPlayerOpen')
|
||||
cb()
|
||||
this.updatePlayer(true, cb)
|
||||
})
|
||||
}
|
||||
|
||||
// Starts WebTorrent server for media streaming
|
||||
startServer (torrentSummary, cb) {
|
||||
if (torrentSummary.status === 'paused') {
|
||||
dispatch('startTorrentingSummary', torrentSummary.torrentKey)
|
||||
ipcRenderer.once('wt-ready-' + torrentSummary.infoHash,
|
||||
() => onTorrentReady())
|
||||
} else {
|
||||
onTorrentReady()
|
||||
}
|
||||
|
||||
function onTorrentReady () {
|
||||
ipcRenderer.send('wt-start-server', torrentSummary.infoHash)
|
||||
ipcRenderer.once('wt-server-' + torrentSummary.infoHash, () => cb())
|
||||
}
|
||||
}
|
||||
|
||||
// Called each time the playlist state changes
|
||||
updatePlayer (resume, cb) {
|
||||
var state = this.state
|
||||
var track = state.playlist.getCurrent()
|
||||
|
||||
if (track === undefined) {
|
||||
return cb(new Error('Can\'t play that file'))
|
||||
}
|
||||
|
||||
var torrentSummary = TorrentSummary.getByKey(this.state, state.playlist.getInfoHash())
|
||||
var fileSummary = torrentSummary.files[track.fileIndex]
|
||||
|
||||
// update state
|
||||
state.playing.fileIndex = track.fileIndex
|
||||
state.playing.type = track.type
|
||||
|
||||
// pick up where we left off
|
||||
var jumpToTime = 0
|
||||
if (resume && fileSummary.currentTime) {
|
||||
var fraction = fileSummary.currentTime / fileSummary.duration
|
||||
var secondsLeft = fileSummary.duration - fileSummary.currentTime
|
||||
if (fraction < 0.9 && secondsLeft > 10) {
|
||||
jumpToTime = fileSummary.currentTime
|
||||
}
|
||||
}
|
||||
state.playing.jumpToTime = jumpToTime
|
||||
|
||||
// if it's audio, parse out the metadata (artist, title, etc)
|
||||
if (state.playing.type === 'audio' && !fileSummary.audioInfo) {
|
||||
ipcRenderer.send('wt-get-audio-metadata', torrentSummary.infoHash, track.fileIndex)
|
||||
}
|
||||
|
||||
// if it's video, check for subtitles files that are done downloading
|
||||
dispatch('checkForSubtitles')
|
||||
|
||||
// enable previously selected subtitle track
|
||||
if (fileSummary.selectedSubtitle) {
|
||||
dispatch('addSubtitles', [fileSummary.selectedSubtitle], true)
|
||||
}
|
||||
|
||||
state.window.title = fileSummary.name
|
||||
|
||||
// play in VLC if set as default player (Preferences / Playback / Play in VLC)
|
||||
if (this.state.saved.prefs.openExternalPlayer) {
|
||||
dispatch('openExternalPlayer')
|
||||
this.update()
|
||||
cb()
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, play the video
|
||||
this.update()
|
||||
|
||||
ipcRenderer.send('onPlayerUpdate', state.playlist.hasNext(), state.playlist.hasPrevious())
|
||||
cb()
|
||||
}
|
||||
|
||||
closePlayer () {
|
||||
console.log('closePlayer')
|
||||
|
||||
@@ -287,6 +352,7 @@ module.exports = class PlaybackController {
|
||||
|
||||
// Reset the window contents back to the home screen
|
||||
state.playing = State.getDefaultPlayState()
|
||||
state.playlist = null
|
||||
state.server = null
|
||||
|
||||
// Reset the window size and location back to where it was
|
||||
|
||||
@@ -96,7 +96,7 @@ function chromecastPlayer () {
|
||||
|
||||
function open () {
|
||||
var torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash)
|
||||
ret.device.play(state.server.networkURL, {
|
||||
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, {
|
||||
type: 'video/mp4',
|
||||
title: config.APP_NAME + ' - ' + torrentSummary.name
|
||||
}, function (err) {
|
||||
@@ -183,7 +183,7 @@ function airplayPlayer () {
|
||||
}
|
||||
|
||||
function open () {
|
||||
ret.device.play(state.server.networkURL, function (err, res) {
|
||||
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, function (err, res) {
|
||||
if (err) {
|
||||
state.playing.location = 'local'
|
||||
state.errors.push({
|
||||
@@ -275,7 +275,7 @@ function dlnaPlayer (player) {
|
||||
|
||||
function open () {
|
||||
var torrentSummary = state.saved.torrents.find((x) => x.infoHash === state.playing.infoHash)
|
||||
ret.device.play(state.server.networkURL, {
|
||||
ret.device.play(state.server.networkURL + '/' + state.playing.fileIndex, {
|
||||
type: 'video/mp4',
|
||||
title: config.APP_NAME + ' - ' + torrentSummary.name,
|
||||
seek: state.playing.currentTime > 10 ? state.playing.currentTime : 0
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
module.exports = {
|
||||
UnplayableError
|
||||
UnplayableTorrentError,
|
||||
UnplayableFileError
|
||||
}
|
||||
|
||||
function UnplayableError () {
|
||||
function UnplayableTorrentError () {
|
||||
this.message = 'Can\'t play any files in torrent'
|
||||
}
|
||||
UnplayableError.prototype = Error
|
||||
|
||||
function UnplayableFileError () {
|
||||
this.message = 'Can\'t play that file'
|
||||
}
|
||||
|
||||
UnplayableTorrentError.prototype = Error
|
||||
UnplayableFileError.prototype = Error
|
||||
|
||||
78
src/renderer/lib/playlist.js
Normal file
78
src/renderer/lib/playlist.js
Normal file
@@ -0,0 +1,78 @@
|
||||
var TorrentPlayer = require('./torrent-player')
|
||||
|
||||
module.exports = Playlist
|
||||
|
||||
function Playlist (torrentSummary) {
|
||||
this._infoHash = torrentSummary.infoHash
|
||||
this._position = 0
|
||||
this._tracks = extractTracks(torrentSummary)
|
||||
}
|
||||
|
||||
Playlist.prototype.getInfoHash = function () {
|
||||
return this._infoHash
|
||||
}
|
||||
|
||||
Playlist.prototype.getTracks = function () {
|
||||
return this._tracks
|
||||
}
|
||||
|
||||
Playlist.prototype.hasNext = function () {
|
||||
return this._position + 1 < this._tracks.length
|
||||
}
|
||||
|
||||
Playlist.prototype.hasPrevious = function () {
|
||||
return this._position > 0
|
||||
}
|
||||
|
||||
Playlist.prototype.next = function () {
|
||||
if (this.hasNext()) {
|
||||
this._position++
|
||||
return this.getCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
Playlist.prototype.previous = function () {
|
||||
if (this.hasPrevious()) {
|
||||
this._position--
|
||||
return this.getCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
Playlist.prototype.jumpToFile = function (infoHash, fileIndex) {
|
||||
this.setPosition(this._tracks.findIndex(
|
||||
(track) => track.infoHash === infoHash && track.fileIndex === fileIndex
|
||||
))
|
||||
return this.getCurrent()
|
||||
}
|
||||
|
||||
Playlist.prototype.getCurrent = function () {
|
||||
var position = this.getPosition()
|
||||
return position === undefined ? undefined : this._tracks[position]
|
||||
}
|
||||
|
||||
Playlist.prototype.getPosition = function () {
|
||||
if (this._position >= 0 && this._position < this._tracks.length) {
|
||||
return this._position
|
||||
} else return undefined
|
||||
}
|
||||
|
||||
Playlist.prototype.setPosition = function (position) {
|
||||
this._position = position
|
||||
}
|
||||
|
||||
function extractTracks (torrentSummary) {
|
||||
return torrentSummary.files.map((file, index) => ({ file, index }))
|
||||
.filter((object) => TorrentPlayer.isPlayable(object.file))
|
||||
.sort(function (a, b) {
|
||||
if (a.file.name < b.file.name) return -1
|
||||
if (b.file.name < a.file.name) return 1
|
||||
return 0
|
||||
})
|
||||
.map((object) => ({
|
||||
infoHash: torrentSummary.infoHash,
|
||||
fileIndex: object.index,
|
||||
type: TorrentPlayer.isVideo(object.file) ? 'video'
|
||||
: TorrentPlayer.isAudio(object.file) ? 'audio'
|
||||
: 'other'
|
||||
}))
|
||||
}
|
||||
@@ -39,6 +39,7 @@ function getDefaultState () {
|
||||
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 */
|
||||
playlist: null,
|
||||
dock: {
|
||||
badge: 0,
|
||||
progress: 0
|
||||
|
||||
@@ -188,6 +188,8 @@ const dispatchHandlers = {
|
||||
// Playback
|
||||
'playFile': (infoHash, index) => controllers.playback.playFile(infoHash, index),
|
||||
'playPause': () => controllers.playback.playPause(),
|
||||
'nextTrack': () => controllers.playback.nextTrack(),
|
||||
'previousTrack': () => controllers.playback.previousTrack(),
|
||||
'skip': (time) => controllers.playback.skip(time),
|
||||
'skipTo': (time) => controllers.playback.skipTo(time),
|
||||
'changePlaybackRate': (dir) => controllers.playback.changePlaybackRate(dir),
|
||||
|
||||
@@ -109,7 +109,7 @@ function renderMedia (state) {
|
||||
var MediaTagName = state.playing.type
|
||||
var mediaTag = (
|
||||
<MediaTagName
|
||||
src={state.server.localURL}
|
||||
src={state.server.localURL + '/' + state.playing.fileIndex}
|
||||
onDoubleClick={dispatcher('toggleFullScreen')}
|
||||
onLoadedMetadata={onLoadedMetadata}
|
||||
onEnded={onEnded}
|
||||
@@ -144,9 +144,13 @@ function renderMedia (state) {
|
||||
dispatch('setDimensions', dimensions)
|
||||
}
|
||||
|
||||
// When the video completes, pause the video instead of looping
|
||||
function onEnded (e) {
|
||||
state.playing.isPaused = true
|
||||
if (state.playlist.hasNext()) {
|
||||
dispatch('nextTrack')
|
||||
} else {
|
||||
// When the last video completes, pause the video instead of looping
|
||||
state.playing.isPaused = true
|
||||
}
|
||||
}
|
||||
|
||||
function onCanPlay (e) {
|
||||
@@ -378,6 +382,8 @@ function renderPlayerControls (state) {
|
||||
: state.playing.subtitles.selectedIndex >= 0
|
||||
? 'active'
|
||||
: ''
|
||||
var prevClass = state.playlist.hasPrevious() ? '' : 'disabled'
|
||||
var nextClass = state.playlist.hasNext() ? '' : 'disabled'
|
||||
|
||||
var elements = [
|
||||
<div key='playback-bar' className='playback-bar'>
|
||||
@@ -397,6 +403,13 @@ function renderPlayerControls (state) {
|
||||
/>
|
||||
</div>,
|
||||
|
||||
<i
|
||||
key='skip-previous'
|
||||
className={'icon skip-previous float-left ' + prevClass}
|
||||
onClick={dispatcher('previousTrack')}>
|
||||
skip_previous
|
||||
</i>,
|
||||
|
||||
<i
|
||||
key='play'
|
||||
className='icon play-pause float-left'
|
||||
@@ -404,6 +417,13 @@ function renderPlayerControls (state) {
|
||||
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
||||
</i>,
|
||||
|
||||
<i
|
||||
key='skip-next'
|
||||
className={'icon skip-next float-left ' + nextClass}
|
||||
onClick={dispatcher('nextTrack')}>
|
||||
skip_next
|
||||
</i>,
|
||||
|
||||
<i
|
||||
key='fullscreen'
|
||||
className='icon fullscreen float-right'
|
||||
|
||||
@@ -83,8 +83,8 @@ function init () {
|
||||
generateTorrentPoster(torrentKey))
|
||||
ipc.on('wt-get-audio-metadata', (e, infoHash, index) =>
|
||||
getAudioMetadata(infoHash, index))
|
||||
ipc.on('wt-start-server', (e, infoHash, index) =>
|
||||
startServer(infoHash, index))
|
||||
ipc.on('wt-start-server', (e, infoHash) =>
|
||||
startServer(infoHash))
|
||||
ipc.on('wt-stop-server', (e) =>
|
||||
stopServer())
|
||||
ipc.on('wt-select-files', (e, infoHash, selections) =>
|
||||
@@ -301,20 +301,20 @@ function getTorrentProgress () {
|
||||
}
|
||||
}
|
||||
|
||||
function startServer (infoHash, index) {
|
||||
function startServer (infoHash) {
|
||||
var torrent = client.get(infoHash)
|
||||
if (torrent.ready) startServerFromReadyTorrent(torrent, index)
|
||||
else torrent.once('ready', () => startServerFromReadyTorrent(torrent, index))
|
||||
if (torrent.ready) startServerFromReadyTorrent(torrent)
|
||||
else torrent.once('ready', () => startServerFromReadyTorrent(torrent))
|
||||
}
|
||||
|
||||
function startServerFromReadyTorrent (torrent, index, cb) {
|
||||
function startServerFromReadyTorrent (torrent, cb) {
|
||||
if (server) return
|
||||
|
||||
// start the streaming torrent-to-http server
|
||||
server = torrent.createServer()
|
||||
server.listen(0, function () {
|
||||
var port = server.address().port
|
||||
var urlSuffix = ':' + port + '/' + index
|
||||
var urlSuffix = ':' + port
|
||||
var info = {
|
||||
torrentKey: torrent.key,
|
||||
localURL: 'http://localhost' + urlSuffix,
|
||||
@@ -322,7 +322,7 @@ function startServerFromReadyTorrent (torrent, index, cb) {
|
||||
}
|
||||
|
||||
ipc.send('wt-server-running', info)
|
||||
ipc.send('wt-server-' + torrent.infoHash, info) // TODO: hack
|
||||
ipc.send('wt-server-' + torrent.infoHash, info)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -629,7 +629,25 @@ body.drag .app::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.player .controls .play-pause {
|
||||
.player .controls .icon.disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.player .controls .icon.skip-previous {
|
||||
font-size: 28px;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.player .controls .icon.play-pause {
|
||||
font-size: 28px;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.player .controls .icon.skip-next {
|
||||
font-size: 28px;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px;
|
||||
|
||||
Reference in New Issue
Block a user