Refactor main.js: media and update controllers
This commit is contained in:
56
renderer/controllers/media-controller.js
Normal file
56
renderer/controllers/media-controller.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
const electron = require('electron')
|
||||||
|
|
||||||
|
const ipcRenderer = electron.ipcRenderer
|
||||||
|
|
||||||
|
// Controls local play back: the <video>/<audio> tag and VLC
|
||||||
|
// Does not control remote casting (Chromecast etc)
|
||||||
|
module.exports = class MediaController {
|
||||||
|
constructor (state) {
|
||||||
|
this.state = state
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaSuccess () {
|
||||||
|
this.state.playing.result = 'success'
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaStalled () {
|
||||||
|
this.state.playing.isStalled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaError (error) {
|
||||||
|
var state = this.state
|
||||||
|
if (state.location.url() === 'player') {
|
||||||
|
state.playing.result = 'error'
|
||||||
|
state.playing.location = 'error'
|
||||||
|
ipcRenderer.send('checkForVLC')
|
||||||
|
ipcRenderer.once('checkForVLC', function (e, isInstalled) {
|
||||||
|
state.modal = {
|
||||||
|
id: 'unsupported-media-modal',
|
||||||
|
error: error,
|
||||||
|
vlcInstalled: isInstalled
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaTimeUpdate () {
|
||||||
|
this.state.playing.lastTimeUpdate = new Date().getTime()
|
||||||
|
this.state.playing.isStalled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaMouseMoved () {
|
||||||
|
this.state.playing.mouseStationarySince = new Date().getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
vlcPlay () {
|
||||||
|
ipcRenderer.send('vlcPlay', this.state.server.localURL)
|
||||||
|
this.state.playing.location = 'vlc'
|
||||||
|
}
|
||||||
|
|
||||||
|
vlcNotFound () {
|
||||||
|
var modal = this.state.modal
|
||||||
|
if (modal && modal.id === 'unsupported-media-modal') {
|
||||||
|
modal.vlcNotFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
renderer/controllers/update-controller.js
Normal file
26
renderer/controllers/update-controller.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const State = require('../lib/state')
|
||||||
|
|
||||||
|
// Controls the UI checking for new versions of the app, prompting install
|
||||||
|
module.exports = class UpdateController {
|
||||||
|
constructor (state) {
|
||||||
|
this.state = state
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows a modal saying that we have an update
|
||||||
|
updateAvailable (version) {
|
||||||
|
var skipped = this.state.saved.skippedVersions
|
||||||
|
if (skipped && skipped.includes(version)) {
|
||||||
|
console.log('new version skipped by user: v' + version)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.state.modal = { id: 'update-available-modal', version: version }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't show the modal again until the next version
|
||||||
|
skipVersion (version) {
|
||||||
|
var skipped = this.state.saved.skippedVersions
|
||||||
|
if (!skipped) skipped = this.state.saved.skippedVersions = []
|
||||||
|
skipped.push(version)
|
||||||
|
State.saveThrottled(this.state)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
getDefaultPlayState,
|
getDefaultPlayState,
|
||||||
load,
|
load,
|
||||||
save
|
save,
|
||||||
|
saveThrottled
|
||||||
}
|
}
|
||||||
|
|
||||||
var appConfig = require('application-config')('WebTorrent')
|
var appConfig = require('application-config')('WebTorrent')
|
||||||
@@ -180,6 +181,7 @@ function load (cb) {
|
|||||||
// Write state.saved to the JSON state file
|
// Write state.saved to the JSON state file
|
||||||
function save (state, cb) {
|
function save (state, cb) {
|
||||||
console.log('Saving state to ' + appConfig.filePath)
|
console.log('Saving state to ' + appConfig.filePath)
|
||||||
|
delete state.saveStateTimeout
|
||||||
|
|
||||||
var electron = require('electron')
|
var electron = require('electron')
|
||||||
|
|
||||||
@@ -210,3 +212,12 @@ function save (state, cb) {
|
|||||||
electron.ipcRenderer.send('savedState')
|
electron.ipcRenderer.send('savedState')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write, but no more than once a second
|
||||||
|
function saveThrottled (state) {
|
||||||
|
if (state.saveStateTimeout) return
|
||||||
|
state.saveStateTimeout = setTimeout(function () {
|
||||||
|
if (!state.saveStateTimeout) return
|
||||||
|
save(state)
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|||||||
148
renderer/main.js
148
renderer/main.js
@@ -1,32 +1,38 @@
|
|||||||
console.time('init')
|
console.time('init')
|
||||||
|
|
||||||
var crashReporter = require('../crash-reporter')
|
const crashReporter = require('../crash-reporter')
|
||||||
crashReporter.init()
|
crashReporter.init()
|
||||||
|
|
||||||
var dragDrop = require('drag-drop')
|
const dragDrop = require('drag-drop')
|
||||||
var electron = require('electron')
|
const electron = require('electron')
|
||||||
var fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
var mainLoop = require('main-loop')
|
const mainLoop = require('main-loop')
|
||||||
var parallel = require('run-parallel')
|
const parallel = require('run-parallel')
|
||||||
var path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
var createElement = require('virtual-dom/create-element')
|
const createElement = require('virtual-dom/create-element')
|
||||||
var diff = require('virtual-dom/diff')
|
const diff = require('virtual-dom/diff')
|
||||||
var patch = require('virtual-dom/patch')
|
const patch = require('virtual-dom/patch')
|
||||||
|
|
||||||
var config = require('../config')
|
const config = require('../config')
|
||||||
var App = require('./views/app')
|
const App = require('./views/app')
|
||||||
var telemetry = require('./lib/telemetry')
|
const telemetry = require('./lib/telemetry')
|
||||||
var errors = require('./lib/errors')
|
const errors = require('./lib/errors')
|
||||||
var sound = require('./lib/sound')
|
const sound = require('./lib/sound')
|
||||||
var State = require('./lib/state')
|
const State = require('./lib/state')
|
||||||
var TorrentPlayer = require('./lib/torrent-player')
|
const TorrentPlayer = require('./lib/torrent-player')
|
||||||
var TorrentSummary = require('./lib/torrent-summary')
|
const TorrentSummary = require('./lib/torrent-summary')
|
||||||
|
|
||||||
|
const MediaController = require('./controllers/media-controller')
|
||||||
|
const UpdateController = require('./controllers/update-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(...)
|
||||||
require('./lib/dispatcher').setDispatch(dispatch)
|
require('./lib/dispatcher').setDispatch(dispatch)
|
||||||
|
|
||||||
|
// From dispatch(...), events are sent to one of the controllers
|
||||||
|
var controllers = null
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
@@ -48,6 +54,12 @@ function onState (err, _state) {
|
|||||||
if (err) return onError(err)
|
if (err) return onError(err)
|
||||||
state = _state
|
state = _state
|
||||||
|
|
||||||
|
// Create controllers
|
||||||
|
controllers = {
|
||||||
|
media: new MediaController(state),
|
||||||
|
update: new UpdateController(state)
|
||||||
|
}
|
||||||
|
|
||||||
// Add first page to location history
|
// Add first page to location history
|
||||||
state.location.go({ url: 'home' })
|
state.location.go({ url: 'home' })
|
||||||
|
|
||||||
@@ -250,40 +262,25 @@ function dispatch (action, ...args) {
|
|||||||
toggleSubtitlesMenu()
|
toggleSubtitlesMenu()
|
||||||
}
|
}
|
||||||
if (action === 'mediaStalled') {
|
if (action === 'mediaStalled') {
|
||||||
state.playing.isStalled = true
|
controllers.media.mediaStalled()
|
||||||
}
|
}
|
||||||
if (action === 'mediaError') {
|
if (action === 'mediaError') {
|
||||||
if (state.location.url() === 'player') {
|
controllers.media.mediaError(args[0] /* error */)
|
||||||
state.playing.result = 'error'
|
|
||||||
state.playing.location = 'error'
|
|
||||||
ipcRenderer.send('checkForVLC')
|
|
||||||
ipcRenderer.once('checkForVLC', function (e, isInstalled) {
|
|
||||||
state.modal = {
|
|
||||||
id: 'unsupported-media-modal',
|
|
||||||
error: args[0],
|
|
||||||
vlcInstalled: isInstalled
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (action === 'mediaSuccess') {
|
if (action === 'mediaSuccess') {
|
||||||
state.playing.result = 'success'
|
controllers.media.mediaSuccess()
|
||||||
}
|
}
|
||||||
if (action === 'mediaTimeUpdate') {
|
if (action === 'mediaTimeUpdate') {
|
||||||
state.playing.lastTimeUpdate = new Date().getTime()
|
controllers.media.mediaTimeUpdate()
|
||||||
state.playing.isStalled = false
|
|
||||||
}
|
}
|
||||||
if (action === 'mediaMouseMoved') {
|
if (action === 'mediaMouseMoved') {
|
||||||
state.playing.mouseStationarySince = new Date().getTime()
|
controllers.media.mediaMouseMoved()
|
||||||
}
|
}
|
||||||
if (action === 'vlcPlay') {
|
if (action === 'vlcPlay') {
|
||||||
ipcRenderer.send('vlcPlay', state.server.localURL)
|
controllers.media.vlcPlay()
|
||||||
state.playing.location = 'vlc'
|
|
||||||
}
|
}
|
||||||
if (action === 'vlcNotFound') {
|
if (action === 'vlcNotFound') {
|
||||||
if (state.modal && state.modal.id === 'unsupported-media-modal') {
|
controllers.media.vlcNotFound()
|
||||||
state.modal.vlcNotFound = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (action === 'toggleFullScreen') {
|
if (action === 'toggleFullScreen') {
|
||||||
ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */)
|
ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */)
|
||||||
@@ -292,32 +289,16 @@ function dispatch (action, ...args) {
|
|||||||
state.modal = null
|
state.modal = null
|
||||||
}
|
}
|
||||||
if (action === 'preferences') {
|
if (action === 'preferences') {
|
||||||
state.location.go({
|
goToPreferences()
|
||||||
url: 'preferences',
|
|
||||||
onbeforeload: function (cb) {
|
|
||||||
// initialize preferences
|
|
||||||
state.window.title = 'Preferences'
|
|
||||||
state.unsaved = Object.assign(state.unsaved || {}, {prefs: state.saved.prefs || {}})
|
|
||||||
cb()
|
|
||||||
},
|
|
||||||
onbeforeunload: function (cb) {
|
|
||||||
// save state after preferences
|
|
||||||
savePreferences()
|
|
||||||
state.window.title = config.APP_WINDOW_TITLE
|
|
||||||
cb()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if (action === 'updatePreferences') {
|
if (action === 'updatePreferences') {
|
||||||
updatePreferences(args[0], args[1] /* property, value */)
|
updatePreferences(args[0] /* key */, args[1] /* value */)
|
||||||
}
|
}
|
||||||
if (action === 'updateAvailable') {
|
if (action === 'updateAvailable') {
|
||||||
updateAvailable(args[0] /* version */)
|
controllers.update.updateAvailable(args[0] /* version */)
|
||||||
}
|
}
|
||||||
if (action === 'skipVersion') {
|
if (action === 'skipVersion') {
|
||||||
if (!state.saved.skippedVersions) state.saved.skippedVersions = []
|
controllers.update.skipVersion(args[0] /* version */)
|
||||||
state.saved.skippedVersions.push(args[0] /* version */)
|
|
||||||
saveStateThrottled()
|
|
||||||
}
|
}
|
||||||
if (action === 'saveState') {
|
if (action === 'saveState') {
|
||||||
State.save(state)
|
State.save(state)
|
||||||
@@ -335,15 +316,6 @@ function dispatch (action, ...args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shows a modal saying that we have an update
|
|
||||||
function updateAvailable (version) {
|
|
||||||
if (state.saved.skippedVersions && state.saved.skippedVersions.includes(version)) {
|
|
||||||
console.log('new version skipped by user: v' + version)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
state.modal = { id: 'update-available-modal', version: version }
|
|
||||||
}
|
|
||||||
|
|
||||||
function play () {
|
function play () {
|
||||||
if (!state.playing.isPaused) return
|
if (!state.playing.isPaused) return
|
||||||
state.playing.isPaused = false
|
state.playing.isPaused = false
|
||||||
@@ -448,7 +420,7 @@ function backToList () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Quits modals, full screen, or goes back. Happens when the user hits ESC
|
// Quits modals, full screen, or goes back. Happens when the user hits ESC
|
||||||
function escapeBack() {
|
function escapeBack () {
|
||||||
if (state.modal) {
|
if (state.modal) {
|
||||||
dispatch('exitModal')
|
dispatch('exitModal')
|
||||||
} else if (state.window.isFullScreen) {
|
} else if (state.window.isFullScreen) {
|
||||||
@@ -529,16 +501,6 @@ function savePreferences () {
|
|||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't write state.saved to file more than once a second
|
|
||||||
function saveStateThrottled () {
|
|
||||||
if (state.saveStateTimeout) return
|
|
||||||
state.saveStateTimeout = setTimeout(function () {
|
|
||||||
delete state.saveStateTimeout
|
|
||||||
State.save(state)
|
|
||||||
update()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the user adds files (.torrent, files to seed, subtitles) to the app
|
// 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)
|
// via any method (drag-drop, drag to app icon, command line)
|
||||||
function onOpen (files) {
|
function onOpen (files) {
|
||||||
@@ -928,20 +890,20 @@ function torrentProgress (progressInfo) {
|
|||||||
function torrentFileModtimes (torrentKey, fileModtimes) {
|
function torrentFileModtimes (torrentKey, fileModtimes) {
|
||||||
var torrentSummary = getTorrentSummary(torrentKey)
|
var torrentSummary = getTorrentSummary(torrentKey)
|
||||||
torrentSummary.fileModtimes = fileModtimes
|
torrentSummary.fileModtimes = fileModtimes
|
||||||
saveStateThrottled()
|
State.saveThrottled(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
function torrentFileSaved (torrentKey, torrentFileName) {
|
function torrentFileSaved (torrentKey, torrentFileName) {
|
||||||
console.log('torrent file saved %s: %s', torrentKey, torrentFileName)
|
console.log('torrent file saved %s: %s', torrentKey, torrentFileName)
|
||||||
var torrentSummary = getTorrentSummary(torrentKey)
|
var torrentSummary = getTorrentSummary(torrentKey)
|
||||||
torrentSummary.torrentFileName = torrentFileName
|
torrentSummary.torrentFileName = torrentFileName
|
||||||
saveStateThrottled()
|
State.saveThrottled(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
function torrentPosterSaved (torrentKey, posterFileName) {
|
function torrentPosterSaved (torrentKey, posterFileName) {
|
||||||
var torrentSummary = getTorrentSummary(torrentKey)
|
var torrentSummary = getTorrentSummary(torrentKey)
|
||||||
torrentSummary.posterFileName = posterFileName
|
torrentSummary.posterFileName = posterFileName
|
||||||
saveStateThrottled()
|
State.saveThrottled(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
function torrentAudioMetadata (infoHash, index, info) {
|
function torrentAudioMetadata (infoHash, index, info) {
|
||||||
@@ -990,6 +952,24 @@ function playFile (infoHash, index) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToPreferences () {
|
||||||
|
state.location.go({
|
||||||
|
url: 'preferences',
|
||||||
|
onbeforeload: function (cb) {
|
||||||
|
// initialize preferences
|
||||||
|
state.window.title = 'Preferences'
|
||||||
|
state.unsaved = Object.assign(state.unsaved || {}, {prefs: state.saved.prefs || {}})
|
||||||
|
cb()
|
||||||
|
},
|
||||||
|
onbeforeunload: function (cb) {
|
||||||
|
// save state after preferences
|
||||||
|
savePreferences()
|
||||||
|
state.window.title = config.APP_WINDOW_TITLE
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Opens the video player to a specific torrent
|
// Opens the video player to a specific torrent
|
||||||
function openPlayer (infoHash, index, cb) {
|
function openPlayer (infoHash, index, cb) {
|
||||||
var torrentSummary = getTorrentSummary(infoHash)
|
var torrentSummary = getTorrentSummary(infoHash)
|
||||||
@@ -1146,7 +1126,7 @@ function deleteTorrent (infoHash, deleteData) {
|
|||||||
|
|
||||||
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
||||||
if (index > -1) state.saved.torrents.splice(index, 1)
|
if (index > -1) state.saved.torrents.splice(index, 1)
|
||||||
saveStateThrottled()
|
State.saveThrottled(state)
|
||||||
state.location.clearForward('player') // prevent user from going forward to a deleted torrent
|
state.location.clearForward('player') // prevent user from going forward to a deleted torrent
|
||||||
sound.play('DELETE')
|
sound.play('DELETE')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user