Refactor main.js: torrent list controller
This commit is contained in:
241
renderer/controllers/torrent-list-controller.js
Normal file
241
renderer/controllers/torrent-list-controller.js
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const electron = require('electron')
|
||||||
|
|
||||||
|
const {dispatch} = require('../lib/dispatcher')
|
||||||
|
const State = require('../lib/state')
|
||||||
|
const sound = require('../lib/sound')
|
||||||
|
const TorrentSummary = require('../lib/torrent-summary')
|
||||||
|
|
||||||
|
const ipcRenderer = electron.ipcRenderer
|
||||||
|
|
||||||
|
const instantIoRegex = /^(https:\/\/)?instant\.io\/#/
|
||||||
|
|
||||||
|
// Controls the torrent list: creating, adding, deleting, & manipulating torrents
|
||||||
|
module.exports = class TorrentListController {
|
||||||
|
constructor (state) {
|
||||||
|
this.state = state
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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-
|
||||||
|
addTorrent (torrentId) {
|
||||||
|
if (torrentId.path) {
|
||||||
|
// Use path string instead of W3C File object
|
||||||
|
torrentId = torrentId.path
|
||||||
|
}
|
||||||
|
// Allow a instant.io link to be pasted
|
||||||
|
// TODO: remove this once support is added to webtorrent core
|
||||||
|
if (typeof torrentId === 'string' && instantIoRegex.test(torrentId)) {
|
||||||
|
torrentId = torrentId.slice(torrentId.indexOf('#') + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var torrentKey = this.state.nextTorrentKey++
|
||||||
|
var path = this.state.saved.prefs.downloadPath
|
||||||
|
|
||||||
|
ipcRenderer.send('wt-start-torrenting', torrentKey, torrentId, path)
|
||||||
|
|
||||||
|
dispatch('backToList')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows the Create Torrent page with options to seed a given file or folder
|
||||||
|
showCreateTorrent (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') {
|
||||||
|
this.state.location.go({
|
||||||
|
url: 'create-torrent',
|
||||||
|
files: files
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... 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, (allFiles) => this.showCreateTorrent(allFiles))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new torrent and start seeeding
|
||||||
|
createTorrent (options) {
|
||||||
|
var state = this.state
|
||||||
|
var torrentKey = state.nextTorrentKey++
|
||||||
|
ipcRenderer.send('wt-create-torrent', torrentKey, options)
|
||||||
|
state.location.backToFirst(function () {
|
||||||
|
state.location.clearForward('create-torrent')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use torrentKey, not infoHash
|
||||||
|
toggleTorrent (infoHash) {
|
||||||
|
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||||
|
if (torrentSummary.status === 'paused') {
|
||||||
|
torrentSummary.status = 'new'
|
||||||
|
ipcRenderer.send('wt-start-torrenting', torrentSummary)
|
||||||
|
sound.play('ENABLE')
|
||||||
|
} else {
|
||||||
|
torrentSummary.status = 'paused'
|
||||||
|
ipcRenderer.send('wt-stop-torrenting', torrentSummary.infoHash)
|
||||||
|
sound.play('DISABLE')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTorrentFile (infoHash, index) {
|
||||||
|
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||||
|
torrentSummary.selections[index] = !torrentSummary.selections[index]
|
||||||
|
|
||||||
|
// Let the WebTorrent process know to start or stop fetching that file
|
||||||
|
ipcRenderer.send('wt-select-files', infoHash, torrentSummary.selections)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use torrentKey, not infoHash
|
||||||
|
deleteTorrent (infoHash, deleteData) {
|
||||||
|
var state = this.state
|
||||||
|
|
||||||
|
ipcRenderer.send('wt-stop-torrenting', infoHash)
|
||||||
|
|
||||||
|
if (deleteData) {
|
||||||
|
var torrentSummary = TorrentSummary.getByKey(state, infoHash)
|
||||||
|
moveItemToTrash(torrentSummary)
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
||||||
|
if (index > -1) state.saved.torrents.splice(index, 1)
|
||||||
|
State.saveThrottled(state)
|
||||||
|
state.location.clearForward('player') // prevent user from going forward to a deleted torrent
|
||||||
|
sound.play('DELETE')
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSelectTorrent (infoHash) {
|
||||||
|
if (this.state.selectedInfoHash === infoHash) {
|
||||||
|
this.state.selectedInfoHash = null
|
||||||
|
} else {
|
||||||
|
this.state.selectedInfoHash = infoHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openTorrentContextMenu (infoHash) {
|
||||||
|
var torrentSummary = TorrentSummary.getByKey(this.state, infoHash)
|
||||||
|
var menu = new electron.remote.Menu()
|
||||||
|
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
label: 'Remove From List',
|
||||||
|
click: () => this.deleteTorrent(
|
||||||
|
torrentSummary.infoHash, false)
|
||||||
|
}))
|
||||||
|
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
label: 'Remove Data File',
|
||||||
|
click: () => this.deleteTorrent(
|
||||||
|
torrentSummary.infoHash, true)
|
||||||
|
}))
|
||||||
|
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
type: 'separator'
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (torrentSummary.files) {
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
label: process.platform === 'darwin' ? 'Show in Finder' : 'Show in Folder',
|
||||||
|
click: () => showItemInFolder(torrentSummary)
|
||||||
|
}))
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
type: 'separator'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
label: 'Copy Magnet Link to Clipboard',
|
||||||
|
click: () => electron.clipboard.writeText(torrentSummary.magnetURI)
|
||||||
|
}))
|
||||||
|
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
label: 'Copy Instant.io Link to Clipboard',
|
||||||
|
click: () => electron.clipboard.writeText(`https://instant.io/#${torrentSummary.infoHash}`)
|
||||||
|
}))
|
||||||
|
|
||||||
|
menu.append(new electron.remote.MenuItem({
|
||||||
|
label: 'Save Torrent File As...',
|
||||||
|
click: () => saveTorrentFileAs(torrentSummary)
|
||||||
|
}))
|
||||||
|
|
||||||
|
menu.popup(electron.remote.getCurrentWindow())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively finds {name, path, size} for all files in a folder
|
||||||
|
// Calls `cb` on success, calls `onError` on failure
|
||||||
|
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) {
|
||||||
|
ret.sort((a, b) => a.path < b.path ? -1 : a.path > b.path)
|
||||||
|
cb(ret)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileOrFolder = paths[0]
|
||||||
|
fs.stat(fileOrFolder, function (err, stat) {
|
||||||
|
if (err) return dispatch('onError', err)
|
||||||
|
|
||||||
|
// Files: return name, path, and size
|
||||||
|
if (!stat.isDirectory()) {
|
||||||
|
var filePath = fileOrFolder
|
||||||
|
return cb([{
|
||||||
|
name: path.basename(filePath),
|
||||||
|
path: filePath,
|
||||||
|
size: stat.size
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folders: recurse, make a list of all the files
|
||||||
|
var folderPath = fileOrFolder
|
||||||
|
fs.readdir(folderPath, function (err, fileNames) {
|
||||||
|
if (err) return dispatch('onError', err)
|
||||||
|
var paths = fileNames.map((fileName) => path.join(folderPath, fileName))
|
||||||
|
findFilesRecursive(paths, cb)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all files in a torren
|
||||||
|
function moveItemToTrash (torrentSummary) {
|
||||||
|
// TODO: delete directories, not just files
|
||||||
|
torrentSummary.files.forEach(function (file) {
|
||||||
|
var filePath = path.join(torrentSummary.path, file.path)
|
||||||
|
console.log('DEBUG DELETING ' + filePath)
|
||||||
|
ipcRenderer.send('moveItemToTrash', filePath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function showItemInFolder (torrentSummary) {
|
||||||
|
ipcRenderer.send('showItemInFolder', TorrentSummary.getTorrentPath(torrentSummary))
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveTorrentFileAs (torrentSummary) {
|
||||||
|
var downloadPath = this.state.saved.prefs.downloadPath
|
||||||
|
var newFileName = `${path.parse(torrentSummary.name).name}.torrent`
|
||||||
|
var opts = {
|
||||||
|
title: 'Save Torrent File',
|
||||||
|
defaultPath: path.join(downloadPath, newFileName),
|
||||||
|
filters: [
|
||||||
|
{ name: 'Torrent Files', extensions: ['torrent'] },
|
||||||
|
{ name: 'All Files', extensions: ['*'] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
electron.remote.dialog.showSaveDialog(electron.remote.getCurrentWindow(), opts, function (savePath) {
|
||||||
|
var torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
|
||||||
|
fs.readFile(torrentPath, function (err, torrentFile) {
|
||||||
|
if (err) return dispatch('onError', err)
|
||||||
|
fs.writeFile(savePath, torrentFile, function (err) {
|
||||||
|
if (err) return dispatch('onError', err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -116,6 +116,12 @@ function getApproxNumTorrents (state) {
|
|||||||
|
|
||||||
// An uncaught error happened in the main process or in one of the windows
|
// An uncaught error happened in the main process or in one of the windows
|
||||||
function logUncaughtError (procName, err) {
|
function logUncaughtError (procName, err) {
|
||||||
|
console.error('uncaught error', procName, err)
|
||||||
|
|
||||||
|
// Not initialized yet? Ignore.
|
||||||
|
// Hopefully uncaught errors immediately on startup are fixed in dev
|
||||||
|
if (!telemetry) return
|
||||||
|
|
||||||
var message, stack
|
var message, stack
|
||||||
if (typeof err === 'string') {
|
if (typeof err === 'string') {
|
||||||
message = err
|
message = err
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
getPosterPath,
|
getPosterPath,
|
||||||
getTorrentPath
|
getTorrentPath,
|
||||||
|
getByKey,
|
||||||
|
getTorrentID
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = require('path')
|
var path = require('path')
|
||||||
@@ -22,3 +24,22 @@ function getPosterPath (torrentSummary) {
|
|||||||
// Backslashes in URLS in CSS cause bizarre string encoding issues
|
// Backslashes in URLS in CSS cause bizarre string encoding issues
|
||||||
return posterPath.replace(/\\/g, '/')
|
return posterPath.replace(/\\/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expects a torrentSummary
|
||||||
|
// Returns a torrentID: filename, magnet URI, or infohash
|
||||||
|
function getTorrentID (torrentSummary) {
|
||||||
|
var s = torrentSummary
|
||||||
|
if (s.torrentFileName) { // Load torrent file from disk
|
||||||
|
return getTorrentPath(s)
|
||||||
|
} else { // Load torrent from DHT
|
||||||
|
return s.magnetURI || s.infoHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expects a torrentKey or infoHash
|
||||||
|
// Returns the corresponding torrentSummary, or undefined
|
||||||
|
function getByKey (state, torrentKey) {
|
||||||
|
if (!torrentKey) return undefined
|
||||||
|
return state.saved.torrents.find((x) =>
|
||||||
|
x.torrentKey === torrentKey || x.infoHash === torrentKey)
|
||||||
|
}
|
||||||
|
|||||||
483
renderer/main.js
483
renderer/main.js
@@ -26,6 +26,7 @@ const TorrentSummary = require('./lib/torrent-summary')
|
|||||||
const MediaController = require('./controllers/media-controller')
|
const MediaController = require('./controllers/media-controller')
|
||||||
const UpdateController = require('./controllers/update-controller')
|
const UpdateController = require('./controllers/update-controller')
|
||||||
const PrefsController = require('./controllers/prefs-controller')
|
const PrefsController = require('./controllers/prefs-controller')
|
||||||
|
const TorrentListController = require('./controllers/torrent-list-controller')
|
||||||
|
|
||||||
// Yo-yo pattern: state object lives here and percolates down thru all the views.
|
// Yo-yo pattern: state object lives here and percolates down thru all the views.
|
||||||
// Events come back up from the views via dispatch(...)
|
// Events come back up from the views via dispatch(...)
|
||||||
@@ -59,7 +60,8 @@ function onState (err, _state) {
|
|||||||
controllers = {
|
controllers = {
|
||||||
media: new MediaController(state),
|
media: new MediaController(state),
|
||||||
update: new UpdateController(state),
|
update: new UpdateController(state),
|
||||||
prefs: new PrefsController(state, config)
|
prefs: new PrefsController(state, config),
|
||||||
|
torrentList: new TorrentListController(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add first page to location history
|
// Add first page to location history
|
||||||
@@ -170,68 +172,44 @@ function dispatch (action, ...args) {
|
|||||||
console.log('dispatch: %s %o', action, args)
|
console.log('dispatch: %s %o', action, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'onOpen') {
|
// Torrent list: creating, deleting, selecting torrents
|
||||||
onOpen(args[0] /* files */)
|
|
||||||
}
|
|
||||||
if (action === 'addTorrent') {
|
|
||||||
addTorrent(args[0] /* torrent */)
|
|
||||||
}
|
|
||||||
if (action === 'openTorrentFile') {
|
if (action === 'openTorrentFile') {
|
||||||
ipcRenderer.send('openTorrentFile') /* open torrent file */
|
ipcRenderer.send('openTorrentFile') /* open torrent file */
|
||||||
}
|
}
|
||||||
if (action === 'openFiles') {
|
if (action === 'openFiles') {
|
||||||
ipcRenderer.send('openFiles') /* add files with dialog */
|
ipcRenderer.send('openFiles') /* add files with dialog */
|
||||||
}
|
}
|
||||||
if (action === 'showCreateTorrent') {
|
|
||||||
showCreateTorrent(args[0] /* paths */)
|
|
||||||
}
|
|
||||||
if (action === 'openTorrentAddress') {
|
if (action === 'openTorrentAddress') {
|
||||||
state.modal = { id: 'open-torrent-address-modal' }
|
state.modal = { id: 'open-torrent-address-modal' }
|
||||||
}
|
}
|
||||||
if (action === 'createTorrent') {
|
if (action === 'addTorrent') {
|
||||||
createTorrent(args[0] /* options */)
|
controllers.torrentList.addTorrent(args[0] /* torrent */)
|
||||||
}
|
}
|
||||||
if (action === 'openItem') {
|
if (action === 'showCreateTorrent') {
|
||||||
openItem(args[0] /* infoHash */, args[1] /* index */)
|
controllers.torrentList.showCreateTorrent(args[0] /* paths */)
|
||||||
|
}
|
||||||
|
if (action === 'createTorrent') {
|
||||||
|
controllers.torrentList.createTorrent(args[0] /* options */)
|
||||||
}
|
}
|
||||||
if (action === 'toggleTorrent') {
|
if (action === 'toggleTorrent') {
|
||||||
toggleTorrent(args[0] /* infoHash */)
|
controllers.torrentList.toggleTorrent(args[0] /* infoHash */)
|
||||||
}
|
|
||||||
if (action === 'deleteTorrent') {
|
|
||||||
deleteTorrent(args[0] /* infoHash */)
|
|
||||||
}
|
|
||||||
if (action === 'toggleSelectTorrent') {
|
|
||||||
toggleSelectTorrent(args[0] /* infoHash */)
|
|
||||||
}
|
}
|
||||||
if (action === 'toggleTorrentFile') {
|
if (action === 'toggleTorrentFile') {
|
||||||
toggleTorrentFile(args[0] /* infoHash */, args[1] /* index */)
|
controllers.torrentList.toggleTorrentFile(args[0] /* infoHash */, args[1] /* index */)
|
||||||
|
}
|
||||||
|
if (action === 'deleteTorrent') {
|
||||||
|
controllers.torrentList.deleteTorrent(args[0] /* infoHash */)
|
||||||
|
}
|
||||||
|
if (action === 'toggleSelectTorrent') {
|
||||||
|
controllers.torrentList.toggleSelectTorrent(args[0] /* infoHash */)
|
||||||
}
|
}
|
||||||
if (action === 'openTorrentContextMenu') {
|
if (action === 'openTorrentContextMenu') {
|
||||||
openTorrentContextMenu(args[0] /* infoHash */)
|
controllers.torrentList.openTorrentContextMenu(args[0] /* infoHash */)
|
||||||
}
|
}
|
||||||
if (action === 'toggleCastMenu') {
|
|
||||||
lazyLoadCast().toggleMenu(args[0] /* deviceType */)
|
// Playback
|
||||||
}
|
if (action === 'openItem') {
|
||||||
if (action === 'selectCastDevice') {
|
openItem(args[0] /* infoHash */, args[1] /* index */)
|
||||||
lazyLoadCast().selectDevice(args[0] /* index */)
|
|
||||||
}
|
|
||||||
if (action === 'stopCasting') {
|
|
||||||
lazyLoadCast().stop()
|
|
||||||
}
|
|
||||||
if (action === 'setDimensions') {
|
|
||||||
setDimensions(args[0] /* dimensions */)
|
|
||||||
}
|
|
||||||
if (action === 'backToList') {
|
|
||||||
backToList()
|
|
||||||
}
|
|
||||||
if (action === 'escapeBack') {
|
|
||||||
escapeBack()
|
|
||||||
}
|
|
||||||
if (action === 'back') {
|
|
||||||
state.location.back()
|
|
||||||
}
|
|
||||||
if (action === 'forward') {
|
|
||||||
state.location.forward()
|
|
||||||
}
|
}
|
||||||
if (action === 'playPause') {
|
if (action === 'playPause') {
|
||||||
playPause()
|
playPause()
|
||||||
@@ -284,30 +262,72 @@ function dispatch (action, ...args) {
|
|||||||
if (action === 'vlcNotFound') {
|
if (action === 'vlcNotFound') {
|
||||||
controllers.media.vlcNotFound()
|
controllers.media.vlcNotFound()
|
||||||
}
|
}
|
||||||
if (action === 'toggleFullScreen') {
|
|
||||||
ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */)
|
// Casting: Chromecast, Airplay, etc
|
||||||
|
if (action === 'toggleCastMenu') {
|
||||||
|
lazyLoadCast().toggleMenu(args[0] /* deviceType */)
|
||||||
}
|
}
|
||||||
if (action === 'exitModal') {
|
if (action === 'selectCastDevice') {
|
||||||
state.modal = null
|
lazyLoadCast().selectDevice(args[0] /* index */)
|
||||||
}
|
}
|
||||||
|
if (action === 'stopCasting') {
|
||||||
|
lazyLoadCast().stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preferences screen
|
||||||
if (action === 'preferences') {
|
if (action === 'preferences') {
|
||||||
controllers.prefs.show()
|
controllers.prefs.show()
|
||||||
}
|
}
|
||||||
if (action === 'updatePreferences') {
|
if (action === 'updatePreferences') {
|
||||||
controllers.prefs.update(args[0] /* key */, args[1] /* value */)
|
controllers.prefs.update(args[0] /* key */, args[1] /* value */)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update (check for new versions on Linux, where there's no auto updater)
|
||||||
if (action === 'updateAvailable') {
|
if (action === 'updateAvailable') {
|
||||||
controllers.update.updateAvailable(args[0] /* version */)
|
controllers.update.updateAvailable(args[0] /* version */)
|
||||||
}
|
}
|
||||||
if (action === 'skipVersion') {
|
if (action === 'skipVersion') {
|
||||||
controllers.update.skipVersion(args[0] /* version */)
|
controllers.update.skipVersion(args[0] /* version */)
|
||||||
}
|
}
|
||||||
if (action === 'saveState') {
|
|
||||||
State.save(state)
|
// Navigation between screens (back, forward, ESC, etc)
|
||||||
|
if (action === 'exitModal') {
|
||||||
|
state.modal = null
|
||||||
|
}
|
||||||
|
if (action === 'backToList') {
|
||||||
|
backToList()
|
||||||
|
}
|
||||||
|
if (action === 'escapeBack') {
|
||||||
|
escapeBack()
|
||||||
|
}
|
||||||
|
if (action === 'back') {
|
||||||
|
state.location.back()
|
||||||
|
}
|
||||||
|
if (action === 'forward') {
|
||||||
|
state.location.forward()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controlling the window
|
||||||
|
if (action === 'setDimensions') {
|
||||||
|
setDimensions(args[0] /* dimensions */)
|
||||||
|
}
|
||||||
|
if (action === 'toggleFullScreen') {
|
||||||
|
ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */)
|
||||||
}
|
}
|
||||||
if (action === 'setTitle') {
|
if (action === 'setTitle') {
|
||||||
state.window.title = args[0] /* title */
|
state.window.title = args[0] /* title */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Everything else
|
||||||
|
if (action === 'onOpen') {
|
||||||
|
onOpen(args[0] /* files */)
|
||||||
|
}
|
||||||
|
if (action === 'saveState') {
|
||||||
|
State.save(state)
|
||||||
|
}
|
||||||
|
if (action === 'onError') {
|
||||||
|
onError(args[0] /* user-friendly error */)
|
||||||
|
}
|
||||||
if (action === 'uncaughtError') {
|
if (action === 'uncaughtError') {
|
||||||
telemetry.logUncaughtError(args[0] /* process */, args[1] /* error */)
|
telemetry.logUncaughtError(args[0] /* process */, args[1] /* error */)
|
||||||
}
|
}
|
||||||
@@ -318,6 +338,33 @@ function dispatch (action, ...args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen to events from the main and webtorrent processes
|
||||||
|
function setupIpc () {
|
||||||
|
ipcRenderer.on('log', (e, ...args) => console.log(...args))
|
||||||
|
ipcRenderer.on('error', (e, ...args) => console.error(...args))
|
||||||
|
|
||||||
|
ipcRenderer.on('dispatch', (e, ...args) => dispatch(...args))
|
||||||
|
|
||||||
|
ipcRenderer.on('fullscreenChanged', onFullscreenChanged)
|
||||||
|
|
||||||
|
ipcRenderer.on('wt-infohash', (e, ...args) => torrentInfoHash(...args))
|
||||||
|
ipcRenderer.on('wt-metadata', (e, ...args) => torrentMetadata(...args))
|
||||||
|
ipcRenderer.on('wt-done', (e, ...args) => torrentDone(...args))
|
||||||
|
ipcRenderer.on('wt-warning', (e, ...args) => torrentWarning(...args))
|
||||||
|
ipcRenderer.on('wt-error', (e, ...args) => torrentError(...args))
|
||||||
|
|
||||||
|
ipcRenderer.on('wt-progress', (e, ...args) => torrentProgress(...args))
|
||||||
|
ipcRenderer.on('wt-file-modtimes', (e, ...args) => torrentFileModtimes(...args))
|
||||||
|
ipcRenderer.on('wt-file-saved', (e, ...args) => torrentFileSaved(...args))
|
||||||
|
ipcRenderer.on('wt-poster', (e, ...args) => torrentPosterSaved(...args))
|
||||||
|
ipcRenderer.on('wt-audio-metadata', (e, ...args) => torrentAudioMetadata(...args))
|
||||||
|
ipcRenderer.on('wt-server-running', (e, ...args) => torrentServerRunning(...args))
|
||||||
|
|
||||||
|
ipcRenderer.on('wt-uncaught-error', (e, err) => telemetry.logUncaughtError('webtorrent', err))
|
||||||
|
|
||||||
|
ipcRenderer.send('ipcReady')
|
||||||
|
}
|
||||||
|
|
||||||
function play () {
|
function play () {
|
||||||
if (!state.playing.isPaused) return
|
if (!state.playing.isPaused) return
|
||||||
state.playing.isPaused = false
|
state.playing.isPaused = false
|
||||||
@@ -441,39 +488,6 @@ function isCasting () {
|
|||||||
state.playing.location === 'dlna'
|
state.playing.location === 'dlna'
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupIpc () {
|
|
||||||
ipcRenderer.on('log', (e, ...args) => console.log(...args))
|
|
||||||
ipcRenderer.on('error', (e, ...args) => console.error(...args))
|
|
||||||
|
|
||||||
ipcRenderer.on('dispatch', (e, ...args) => dispatch(...args))
|
|
||||||
|
|
||||||
ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) {
|
|
||||||
state.window.isFullScreen = isFullScreen
|
|
||||||
if (!isFullScreen) {
|
|
||||||
// Aspect ratio gets reset in fullscreen mode, so restore it (OS X)
|
|
||||||
ipcRenderer.send('setAspectRatio', state.playing.aspectRatio)
|
|
||||||
}
|
|
||||||
update()
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcRenderer.on('wt-infohash', (e, ...args) => torrentInfoHash(...args))
|
|
||||||
ipcRenderer.on('wt-metadata', (e, ...args) => torrentMetadata(...args))
|
|
||||||
ipcRenderer.on('wt-done', (e, ...args) => torrentDone(...args))
|
|
||||||
ipcRenderer.on('wt-warning', (e, ...args) => torrentWarning(...args))
|
|
||||||
ipcRenderer.on('wt-error', (e, ...args) => torrentError(...args))
|
|
||||||
|
|
||||||
ipcRenderer.on('wt-progress', (e, ...args) => torrentProgress(...args))
|
|
||||||
ipcRenderer.on('wt-file-modtimes', (e, ...args) => torrentFileModtimes(...args))
|
|
||||||
ipcRenderer.on('wt-file-saved', (e, ...args) => torrentFileSaved(...args))
|
|
||||||
ipcRenderer.on('wt-poster', (e, ...args) => torrentPosterSaved(...args))
|
|
||||||
ipcRenderer.on('wt-audio-metadata', (e, ...args) => torrentAudioMetadata(...args))
|
|
||||||
ipcRenderer.on('wt-server-running', (e, ...args) => torrentServerRunning(...args))
|
|
||||||
|
|
||||||
ipcRenderer.on('wt-uncaught-error', (e, err) => telemetry.logUncaughtError('webtorrent', err))
|
|
||||||
|
|
||||||
ipcRenderer.send('ipcReady')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts all torrents that aren't paused on program startup
|
// Starts all torrents that aren't paused on program startup
|
||||||
function resumeTorrents () {
|
function resumeTorrents () {
|
||||||
state.saved.torrents
|
state.saved.torrents
|
||||||
@@ -481,35 +495,6 @@ function resumeTorrents () {
|
|||||||
.forEach((torrentSummary) => startTorrentingSummary(torrentSummary))
|
.forEach((torrentSummary) => startTorrentingSummary(torrentSummary))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the user adds files (.torrent, files to seed, subtitles) to the app
|
|
||||||
// via any method (drag-drop, drag to app icon, command line)
|
|
||||||
function onOpen (files) {
|
|
||||||
if (!Array.isArray(files)) files = [ files ]
|
|
||||||
|
|
||||||
if (state.modal) {
|
|
||||||
state.modal = null
|
|
||||||
}
|
|
||||||
|
|
||||||
var subtitles = files.filter(isSubtitle)
|
|
||||||
|
|
||||||
if (state.location.url() === 'home' || subtitles.length === 0) {
|
|
||||||
if (files.every(isTorrent)) {
|
|
||||||
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) {
|
function isTorrent (file) {
|
||||||
var name = typeof file === 'string' ? file : file.name
|
var name = typeof file === 'string' ? file : file.name
|
||||||
var isTorrentFile = path.extname(name).toLowerCase() === '.torrent'
|
var isTorrentFile = path.extname(name).toLowerCase() === '.torrent'
|
||||||
@@ -526,28 +511,7 @@ function isSubtitle (file) {
|
|||||||
// Gets a torrent summary {name, infoHash, status} from state.saved.torrents
|
// Gets a torrent summary {name, infoHash, status} from state.saved.torrents
|
||||||
// Returns undefined if we don't know that infoHash
|
// Returns undefined if we don't know that infoHash
|
||||||
function getTorrentSummary (torrentKey) {
|
function getTorrentSummary (torrentKey) {
|
||||||
if (!torrentKey) return undefined
|
return TorrentSummary.getByKey(state, torrentKey)
|
||||||
return state.saved.torrents.find((x) =>
|
|
||||||
x.torrentKey === torrentKey || x.infoHash === 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-
|
|
||||||
var instantIoRegex = /^(https:\/\/)?instant\.io\/#/
|
|
||||||
function addTorrent (torrentId) {
|
|
||||||
backToList()
|
|
||||||
var torrentKey = state.nextTorrentKey++
|
|
||||||
var path = state.saved.prefs.downloadPath
|
|
||||||
if (torrentId.path) {
|
|
||||||
// Use path string instead of W3C File object
|
|
||||||
torrentId = torrentId.path
|
|
||||||
}
|
|
||||||
// Allow a instant.io link to be pasted
|
|
||||||
// TODO: remove this once support is added to webtorrent core
|
|
||||||
if (typeof torrentId === 'string' && instantIoRegex.test(torrentId)) {
|
|
||||||
torrentId = torrentId.slice(torrentId.indexOf('#') + 1)
|
|
||||||
}
|
|
||||||
ipcRenderer.send('wt-start-torrenting', torrentKey, torrentId, path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSubtitles (files, autoSelect) {
|
function addSubtitles (files, autoSelect) {
|
||||||
@@ -661,90 +625,9 @@ function startTorrentingSummary (torrentSummary) {
|
|||||||
if (!s.torrentKey) s.torrentKey = state.nextTorrentKey++
|
if (!s.torrentKey) s.torrentKey = state.nextTorrentKey++
|
||||||
|
|
||||||
// Use Downloads folder by default
|
// Use Downloads folder by default
|
||||||
var path = s.path || state.saved.prefs.downloadPath
|
if (!s.path) s.path = state.saved.prefs.downloadPath
|
||||||
|
|
||||||
var torrentID
|
ipcRenderer.send('wt-start-torrenting', s)
|
||||||
if (s.torrentFileName) { // Load torrent file from disk
|
|
||||||
torrentID = TorrentSummary.getTorrentPath(torrentSummary)
|
|
||||||
} else { // Load torrent from DHT
|
|
||||||
torrentID = s.magnetURI || s.infoHash
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('start torrenting %s %s', s.torrentKey, torrentID)
|
|
||||||
ipcRenderer.send('wt-start-torrenting', s.torrentKey, torrentID, path, s.fileModtimes, s.selections)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// TORRENT MANAGEMENT
|
|
||||||
// Send commands to the WebTorrent process, handle events
|
|
||||||
//
|
|
||||||
|
|
||||||
// Shows the Create Torrent page with options to seed a given file or folder
|
|
||||||
function showCreateTorrent (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
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... 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 (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) {
|
|
||||||
ret.sort((a, b) => a.path < b.path ? -1 : a.path > b.path)
|
|
||||||
cb(ret)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileOrFolder = paths[0]
|
|
||||||
fs.stat(fileOrFolder, function (err, stat) {
|
|
||||||
if (err) return onError(err)
|
|
||||||
|
|
||||||
// Files: return name, path, and size
|
|
||||||
if (!stat.isDirectory()) {
|
|
||||||
var filePath = fileOrFolder
|
|
||||||
return cb([{
|
|
||||||
name: path.basename(filePath),
|
|
||||||
path: filePath,
|
|
||||||
size: stat.size
|
|
||||||
}])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folders: recurse, make a list of all the files
|
|
||||||
var folderPath = fileOrFolder
|
|
||||||
fs.readdir(folderPath, function (err, fileNames) {
|
|
||||||
if (err) return onError(err)
|
|
||||||
var paths = fileNames.map((fileName) => path.join(folderPath, fileName))
|
|
||||||
findFilesRecursive(paths, cb)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new torrent and start seeeding
|
|
||||||
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) {
|
function torrentInfoHash (torrentKey, infoHash) {
|
||||||
@@ -1063,96 +946,6 @@ function openItem (infoHash, index) {
|
|||||||
ipcRenderer.send('openItem', filePath)
|
ipcRenderer.send('openItem', filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use torrentKey, not infoHash
|
|
||||||
function toggleTorrent (infoHash) {
|
|
||||||
var torrentSummary = getTorrentSummary(infoHash)
|
|
||||||
if (torrentSummary.status === 'paused') {
|
|
||||||
torrentSummary.status = 'new'
|
|
||||||
startTorrentingSummary(torrentSummary)
|
|
||||||
sound.play('ENABLE')
|
|
||||||
} else {
|
|
||||||
torrentSummary.status = 'paused'
|
|
||||||
ipcRenderer.send('wt-stop-torrenting', torrentSummary.infoHash)
|
|
||||||
sound.play('DISABLE')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use torrentKey, not infoHash
|
|
||||||
function deleteTorrent (infoHash, deleteData) {
|
|
||||||
ipcRenderer.send('wt-stop-torrenting', infoHash)
|
|
||||||
|
|
||||||
if (deleteData) {
|
|
||||||
var torrentSummary = getTorrentSummary(infoHash)
|
|
||||||
moveItemToTrash(torrentSummary)
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
|
||||||
if (index > -1) state.saved.torrents.splice(index, 1)
|
|
||||||
State.saveThrottled(state)
|
|
||||||
state.location.clearForward('player') // prevent user from going forward to a deleted torrent
|
|
||||||
sound.play('DELETE')
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleSelectTorrent (infoHash) {
|
|
||||||
// toggle selection
|
|
||||||
state.selectedInfoHash = state.selectedInfoHash === infoHash ? null : infoHash
|
|
||||||
update()
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTorrentFile (infoHash, index) {
|
|
||||||
var torrentSummary = getTorrentSummary(infoHash)
|
|
||||||
torrentSummary.selections[index] = !torrentSummary.selections[index]
|
|
||||||
|
|
||||||
// Let the WebTorrent process know to start or stop fetching that file
|
|
||||||
ipcRenderer.send('wt-select-files', infoHash, torrentSummary.selections)
|
|
||||||
}
|
|
||||||
|
|
||||||
function openTorrentContextMenu (infoHash) {
|
|
||||||
var torrentSummary = getTorrentSummary(infoHash)
|
|
||||||
var menu = new electron.remote.Menu()
|
|
||||||
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
label: 'Remove From List',
|
|
||||||
click: () => deleteTorrent(torrentSummary.infoHash, false)
|
|
||||||
}))
|
|
||||||
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
label: 'Remove Data File',
|
|
||||||
click: () => deleteTorrent(torrentSummary.infoHash, true)
|
|
||||||
}))
|
|
||||||
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
type: 'separator'
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (torrentSummary.files) {
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
label: process.platform === 'darwin' ? 'Show in Finder' : 'Show in Folder',
|
|
||||||
click: () => showItemInFolder(torrentSummary)
|
|
||||||
}))
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
type: 'separator'
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
label: 'Copy Magnet Link to Clipboard',
|
|
||||||
click: () => electron.clipboard.writeText(torrentSummary.magnetURI)
|
|
||||||
}))
|
|
||||||
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
label: 'Copy Instant.io Link to Clipboard',
|
|
||||||
click: () => electron.clipboard.writeText(`https://instant.io/#${torrentSummary.infoHash}`)
|
|
||||||
}))
|
|
||||||
|
|
||||||
menu.append(new electron.remote.MenuItem({
|
|
||||||
label: 'Save Torrent File As...',
|
|
||||||
click: () => saveTorrentFileAs(torrentSummary)
|
|
||||||
}))
|
|
||||||
|
|
||||||
menu.popup(electron.remote.getCurrentWindow())
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTorrentPath (torrentSummary) {
|
function getTorrentPath (torrentSummary) {
|
||||||
var itemPath = path.join(torrentSummary.path, torrentSummary.files[0].path)
|
var itemPath = path.join(torrentSummary.path, torrentSummary.files[0].path)
|
||||||
if (torrentSummary.files.length > 1) {
|
if (torrentSummary.files.length > 1) {
|
||||||
@@ -1161,35 +954,6 @@ function getTorrentPath (torrentSummary) {
|
|||||||
return itemPath
|
return itemPath
|
||||||
}
|
}
|
||||||
|
|
||||||
function showItemInFolder (torrentSummary) {
|
|
||||||
ipcRenderer.send('showItemInFolder', getTorrentPath(torrentSummary))
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveItemToTrash (torrentSummary) {
|
|
||||||
ipcRenderer.send('moveItemToTrash', getTorrentPath(torrentSummary))
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveTorrentFileAs (torrentSummary) {
|
|
||||||
var newFileName = `${path.parse(torrentSummary.name).name}.torrent`
|
|
||||||
var opts = {
|
|
||||||
title: 'Save Torrent File',
|
|
||||||
defaultPath: path.join(state.saved.prefs.downloadPath, newFileName),
|
|
||||||
filters: [
|
|
||||||
{ name: 'Torrent Files', extensions: ['torrent'] },
|
|
||||||
{ name: 'All Files', extensions: ['*'] }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
electron.remote.dialog.showSaveDialog(electron.remote.getCurrentWindow(), opts, function (savePath) {
|
|
||||||
var torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
|
|
||||||
fs.readFile(torrentPath, function (err, torrentFile) {
|
|
||||||
if (err) return onError(err)
|
|
||||||
fs.writeFile(savePath, torrentFile, function (err) {
|
|
||||||
if (err) return onError(err)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set window dimensions to match video dimensions or fill the screen
|
// Set window dimensions to match video dimensions or fill the screen
|
||||||
function setDimensions (dimensions) {
|
function setDimensions (dimensions) {
|
||||||
// Don't modify the window size if it's already maximized
|
// Don't modify the window size if it's already maximized
|
||||||
@@ -1268,7 +1032,35 @@ function showOrHidePlayerControls () {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event handlers
|
// Called when the user adds files (.torrent, files to seed, subtitles) to the app
|
||||||
|
// via any method (drag-drop, drag to app icon, command line)
|
||||||
|
function onOpen (files) {
|
||||||
|
if (!Array.isArray(files)) files = [ files ]
|
||||||
|
|
||||||
|
if (state.modal) {
|
||||||
|
state.modal = null
|
||||||
|
}
|
||||||
|
|
||||||
|
var subtitles = files.filter(isSubtitle)
|
||||||
|
|
||||||
|
if (state.location.url() === 'home' || subtitles.length === 0) {
|
||||||
|
if (files.every(isTorrent)) {
|
||||||
|
if (state.location.url() !== 'home') {
|
||||||
|
backToList()
|
||||||
|
}
|
||||||
|
// All .torrent files? Add them.
|
||||||
|
files.forEach((file) => controllers.torrentList.addTorrent(file))
|
||||||
|
} else {
|
||||||
|
// Show the Create Torrent screen. Let's seed those files.
|
||||||
|
controllers.torrentList.showCreateTorrent(files)
|
||||||
|
}
|
||||||
|
} else if (state.location.url() === 'player') {
|
||||||
|
addSubtitles(subtitles, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
function onError (err) {
|
function onError (err) {
|
||||||
console.error(err.stack || err)
|
console.error(err.stack || err)
|
||||||
sound.play('ERROR')
|
sound.play('ERROR')
|
||||||
@@ -1276,6 +1068,7 @@ function onError (err) {
|
|||||||
time: new Date().getTime(),
|
time: new Date().getTime(),
|
||||||
message: err.message || err
|
message: err.message || err
|
||||||
})
|
})
|
||||||
|
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1290,7 +1083,7 @@ function onPaste (e) {
|
|||||||
torrentIds.forEach(function (torrentId) {
|
torrentIds.forEach(function (torrentId) {
|
||||||
torrentId = torrentId.trim()
|
torrentId = torrentId.trim()
|
||||||
if (torrentId.length === 0) return
|
if (torrentId.length === 0) return
|
||||||
addTorrent(torrentId)
|
controllers.torrentList.addTorrent(torrentId)
|
||||||
})
|
})
|
||||||
|
|
||||||
update()
|
update()
|
||||||
@@ -1310,3 +1103,13 @@ function onBlur () {
|
|||||||
function onVisibilityChange () {
|
function onVisibilityChange () {
|
||||||
state.window.isVisible = !document.webkitHidden
|
state.window.isVisible = !document.webkitHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onFullscreenChanged (e, isFullScreen) {
|
||||||
|
state.window.isFullScreen = isFullScreen
|
||||||
|
if (!isFullScreen) {
|
||||||
|
// Aspect ratio gets reset in fullscreen mode, so restore it (OS X)
|
||||||
|
ipcRenderer.send('setAspectRatio', state.playing.aspectRatio)
|
||||||
|
}
|
||||||
|
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ var path = require('path')
|
|||||||
var crashReporter = require('../crash-reporter')
|
var crashReporter = require('../crash-reporter')
|
||||||
var config = require('../config')
|
var config = require('../config')
|
||||||
var torrentPoster = require('./lib/torrent-poster')
|
var torrentPoster = require('./lib/torrent-poster')
|
||||||
|
var TorrentSummary = require('./lib/torrent-summary')
|
||||||
|
|
||||||
// Report when the process crashes
|
// Report when the process crashes
|
||||||
crashReporter.init()
|
crashReporter.init()
|
||||||
@@ -42,8 +43,8 @@ function init () {
|
|||||||
client.on('warning', (err) => ipc.send('wt-warning', null, err.message))
|
client.on('warning', (err) => ipc.send('wt-warning', null, err.message))
|
||||||
client.on('error', (err) => ipc.send('wt-error', null, err.message))
|
client.on('error', (err) => ipc.send('wt-error', null, err.message))
|
||||||
|
|
||||||
ipc.on('wt-start-torrenting', (e, torrentKey, torrentID, path, fileModtimes, selections) =>
|
ipc.on('wt-start-torrenting', (e, torrentSummary) =>
|
||||||
startTorrenting(torrentKey, torrentID, path, fileModtimes, selections))
|
startTorrenting(torrentSummary))
|
||||||
ipc.on('wt-stop-torrenting', (e, infoHash) =>
|
ipc.on('wt-stop-torrenting', (e, infoHash) =>
|
||||||
stopTorrenting(infoHash))
|
stopTorrenting(infoHash))
|
||||||
ipc.on('wt-create-torrent', (e, torrentKey, options) =>
|
ipc.on('wt-create-torrent', (e, torrentKey, options) =>
|
||||||
@@ -72,12 +73,15 @@ function init () {
|
|||||||
|
|
||||||
// Starts a given TorrentID, which can be an infohash, magnet URI, etc. Returns WebTorrent object
|
// Starts a given TorrentID, which can be an infohash, magnet URI, etc. Returns WebTorrent object
|
||||||
// See https://github.com/feross/webtorrent/blob/master/docs/api.md#clientaddtorrentid-opts-function-ontorrent-torrent-
|
// See https://github.com/feross/webtorrent/blob/master/docs/api.md#clientaddtorrentid-opts-function-ontorrent-torrent-
|
||||||
function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections) {
|
function startTorrenting (torrentSummary) {
|
||||||
|
var s = torrentSummary
|
||||||
|
var torrentKey = s.torrentKey
|
||||||
|
var torrentID = TorrentSummary.getTorrentID(s)
|
||||||
console.log('starting torrent %s: %s', torrentKey, torrentID)
|
console.log('starting torrent %s: %s', torrentKey, torrentID)
|
||||||
|
|
||||||
var torrent = client.add(torrentID, {
|
var torrent = client.add(torrentID, {
|
||||||
path: path,
|
path: s.path,
|
||||||
fileModtimes: fileModtimes
|
fileModtimes: s.fileModtimes
|
||||||
})
|
})
|
||||||
torrent.key = torrentKey
|
torrent.key = torrentKey
|
||||||
|
|
||||||
@@ -85,7 +89,7 @@ function startTorrenting (torrentKey, torrentID, path, fileModtimes, selections)
|
|||||||
addTorrentEvents(torrent)
|
addTorrentEvents(torrent)
|
||||||
|
|
||||||
// Only download the files the user wants, not necessarily all files
|
// Only download the files the user wants, not necessarily all files
|
||||||
torrent.once('ready', () => selectFiles(torrent, selections))
|
torrent.once('ready', () => selectFiles(torrent, s.selections))
|
||||||
|
|
||||||
return torrent
|
return torrent
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user