diff --git a/package.json b/package.json index fe5820cc..6a7f43b6 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "auto-launch": "^4.0.1", "bitfield": "^1.0.2", "capture-frame": "^1.0.0", + "chokidar": "^1.6.1", "chromecasts": "^1.8.0", "cp-file": "^4.0.1", "create-torrent": "^3.24.5", diff --git a/src/main/folder-watcher.js b/src/main/folder-watcher.js new file mode 100644 index 00000000..d628d35b --- /dev/null +++ b/src/main/folder-watcher.js @@ -0,0 +1,50 @@ +const chokidar = require('chokidar') +const log = require('./log') + +class FolderWatcher { + constructor ({window, state}) { + this.window = window + this.state = state + this.torrentsFolderPath = null + this.watching = false + } + + isEnabled () { + return this.state.saved.prefs.autoAddTorrents + } + + start () { + // Stop watching previous folder before + // start watching a new one. + if (this.watching) this.stop() + + const torrentsFolderPath = this.state.saved.prefs.torrentsFolderPath + this.torrentsFolderPath = torrentsFolderPath + if (!torrentsFolderPath) return + + const glob = `${torrentsFolderPath}/**/*.torrent` + log('Folder Watcher: watching: ', glob) + + const options = { + ignoreInitial: true, + awaitWriteFinish: true + } + this.watcher = chokidar.watch(glob, options) + this.watcher + .on('add', (path) => { + log('Folder Watcher: added torrent: ', path) + this.window.dispatch('addTorrent', path) + }) + + this.watching = true + } + + stop () { + log('Folder Watcher: stop.') + if (!this.watching) return + this.watcher.close() + this.watching = false + } +} + +module.exports = FolderWatcher diff --git a/src/main/index.js b/src/main/index.js index 497b9072..9d952f87 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -72,13 +72,16 @@ function init () { if (err) throw err isReady = true + const state = results.state - windows.main.init(results.state, {hidden: hidden}) + windows.main.init(state, {hidden: hidden}) windows.webtorrent.init() menu.init() // To keep app startup fast, some code is delayed. - setTimeout(delayedInit, config.DELAYED_INIT) + setTimeout(() => { + delayedInit(state) + }, config.DELAYED_INIT) // Report uncaught exceptions process.on('uncaughtException', (err) => { @@ -121,17 +124,24 @@ function init () { }) } -function delayedInit () { +function delayedInit (state) { if (app.isQuitting) return const announcement = require('./announcement') const dock = require('./dock') const updater = require('./updater') + const FolderWatcher = require('./folder-watcher') + const folderWatcher = new FolderWatcher({window: windows.main, state}) announcement.init() dock.init() updater.init() + ipc.setModule('folderWatcher', folderWatcher) + if (folderWatcher.isEnabled()) { + folderWatcher.start() + } + if (process.platform === 'win32') { const userTasks = require('./user-tasks') userTasks.init() diff --git a/src/main/ipc.js b/src/main/ipc.js index e6110626..4c0a3d42 100644 --- a/src/main/ipc.js +++ b/src/main/ipc.js @@ -1,5 +1,6 @@ module.exports = { - init + init, + setModule } const electron = require('electron') @@ -13,6 +14,14 @@ const windows = require('./windows') // Messages from the main process, to be sent once the WebTorrent process starts const messageQueueMainToWebTorrent = [] +// Will hold modules injected from the app that will be used on fired +// IPC events. +const modules = {} + +function setModule (name, module) { + modules[name] = module +} + function init () { const ipc = electron.ipcMain @@ -58,7 +67,7 @@ function init () { }) /** - * Events + * Player Events */ ipc.on('onPlayerOpen', function () { @@ -106,6 +115,28 @@ function init () { thumbar.onPlayerPause() }) + /** + * Folder Watcher Events + */ + + ipc.on('startFolderWatcher', function () { + if (!modules['folderWatcher']) { + log('IPC ERR: folderWatcher module is not defined.') + return + } + + modules['folderWatcher'].start() + }) + + ipc.on('stopFolderWatcher', function () { + if (!modules['folderWatcher']) { + log('IPC ERR: folderWatcher module is not defined.') + return + } + + modules['folderWatcher'].stop() + }) + /** * Shell */ diff --git a/src/renderer/controllers/folder-watcher-controller.js b/src/renderer/controllers/folder-watcher-controller.js new file mode 100644 index 00000000..1454dba1 --- /dev/null +++ b/src/renderer/controllers/folder-watcher-controller.js @@ -0,0 +1,13 @@ +const {ipcRenderer} = require('electron') + +module.exports = class FolderWatcherController { + start () { + console.log('-- IPC: start folder watcher') + ipcRenderer.send('startFolderWatcher') + } + + stop () { + console.log('-- IPC: stop folder watcher') + ipcRenderer.send('stopFolderWatcher') + } +} diff --git a/src/renderer/lib/state.js b/src/renderer/lib/state.js index 6a909d96..68c85bb0 100644 --- a/src/renderer/lib/state.js +++ b/src/renderer/lib/state.js @@ -121,7 +121,9 @@ function setupStateSaved (cb) { isFileHandler: false, openExternalPlayer: false, externalPlayerPath: null, - startup: false + startup: false, + autoAddTorrents: false, + torrentsFolderPath: '' }, torrents: config.DEFAULT_TORRENTS.map(createTorrentObject), torrentsToResume: [], diff --git a/src/renderer/main.js b/src/renderer/main.js index 7acb24f5..1fc431df 100644 --- a/src/renderer/main.js +++ b/src/renderer/main.js @@ -111,6 +111,10 @@ function onState (err, _state) { update: createGetter(() => { const UpdateController = require('./controllers/update-controller') return new UpdateController(state) + }), + folderWatcher: createGetter(() => { + const FolderWatcherController = require('./controllers/folder-watcher-controller') + return new FolderWatcherController() }) } @@ -296,6 +300,8 @@ const dispatchHandlers = { 'preferences': () => controllers.prefs().show(), 'updatePreferences': (key, value) => controllers.prefs().update(key, value), 'checkDownloadPath': checkDownloadPath, + 'startFolderWatcher': () => controllers.folderWatcher().start(), + 'stopFolderWatcher': () => controllers.folderWatcher().stop(), // Update (check for new versions on Linux, where there's no auto updater) 'updateAvailable': (version) => controllers.update().updateAvailable(version), diff --git a/src/renderer/pages/preferences-page.js b/src/renderer/pages/preferences-page.js index bf729141..76097109 100644 --- a/src/renderer/pages/preferences-page.js +++ b/src/renderer/pages/preferences-page.js @@ -108,6 +108,59 @@ class PreferencesPage extends React.Component { dispatch('updatePreferences', 'externalPlayerPath', filePath) } + autoAddTorrentsCheckbox () { + return ( + + { this.handleAutoAddTorrentsChange(e, value) }} + /> + + ) + } + + handleAutoAddTorrentsChange (e, isChecked) { + const torrentsFolderPath = this.props.state.unsaved.prefs.torrentsFolderPath + if (isChecked && !torrentsFolderPath) { + alert('Select a torrents folder first.') // eslint-disable-line + e.preventDefault() + return + } + + dispatch('updatePreferences', 'autoAddTorrents', isChecked) + + if (isChecked) { + dispatch('startFolderWatcher', null) + return + } + + dispatch('stopFolderWatcher', null) + } + + torrentsFolderPathSelector () { + const torrentsFolderPath = this.props.state.unsaved.prefs.torrentsFolderPath + + return ( + + + + ) + } + + handletorrentsFolderPathChange (filePath) { + dispatch('updatePreferences', 'torrentsFolderPath', filePath) + } + setDefaultAppButton () { const isFileHandler = this.props.state.unsaved.prefs.isFileHandler if (isFileHandler) { @@ -163,8 +216,10 @@ class PreferencesPage extends React.Component { } return (
- + {this.downloadPathSelector()} + {this.autoAddTorrentsCheckbox()} + {this.torrentsFolderPathSelector()} {this.openExternalPlayerCheckbox()}