diff --git a/main.js b/main.js index 4cbdf92..acd4297 100755 --- a/main.js +++ b/main.js @@ -1,31 +1,10 @@ -// Inspired by https://github.com/pbarbiero/basic-electron-react-boilerplate -// TODO: Look into https://github.com/electron-userland/electron-builder 'use strict'; -// Import parts of electron to use -const { app, BrowserWindow, Menu, Tray, clipboard } = require('electron'); - -var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { - server.passArgs(commandLine) -}) - -if (shouldQuit) { - app.quit() - return -} - const path = require('path'); const url = require('url'); const process = require('process'); -const MenuBuilder = require('./menu'); const getPort = require('get-port') -const AutoLaunch = require('auto-launch'); - -const autoLauncher = new AutoLaunch({ - name: 'Powder Web' -}) - const server = require('./server') const streams = require('./server/streams') const acestream = require('./server/acestream') @@ -37,26 +16,11 @@ const events = require('./server/utils/events') const qrCode = require('./server/utils/qrcode') -const opn = require('opn') - -if (app && app.commandLine && app.commandLine.appendSwitch) - app.commandLine.appendSwitch("ignore-certificate-errors") - -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. -let mainWindow; +const opn = require('open') -if (app.dock) - app.dock.hide() - -// Keep a reference for dev mode -let dev = false; -if (process.env.NODE_ENV === 'development') { - dev = true; - require('dotenv').config({ silent: true }); -} +const haveElectron = require('./server/utils/haveElectron') -function createServer() { +function createServer(cb) { let frontPort let backPort @@ -90,266 +54,308 @@ function createServer() { server.init(frontPort, backPort) - setTimeout(createWindow) + if (cb) + setTimeout(cb) }) }) } -const quit = () => { +if (!haveElectron()) { + // headless mode + createServer() +} else { + // run electron -// if (mainWindow) -// mainWindow.destroy() + const AutoLaunch = require('auto-launch'); - if (mainWindow.isVisible()) - mainWindow.hide() + const autoLauncher = new AutoLaunch({ + name: 'Powder Web' + }) - tray.destroy() + const MenuBuilder = require('./menu'); + const { app, BrowserWindow, Menu, Tray, clipboard } = require('electron'); - var ticks = 3 + var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { + server.passArgs(commandLine) + }) - const tick = () => { - ticks-- - if (!ticks) { - app.quit() - } + if (shouldQuit) { + app.quit() + return } - sop.unhackSopPlayer(() => { - sop.kill(tick, tick) - }) + if (app && app.commandLine && app.commandLine.appendSwitch) + app.commandLine.appendSwitch("ignore-certificate-errors") - streams.closeAll(tick) + // Keep a global reference of the window object, if you don't, the window will + // be closed automatically when the JavaScript object is garbage collected. + let mainWindow; - acestream.binary.kill(tick, tick) + if (app.dock) + app.dock.hide() -} + // Keep a reference for dev mode + let dev = false; + if (process.env.NODE_ENV === 'development') { + dev = true; + require('dotenv').config({ silent: true }); + } -function createWindow() { - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 1268, - height: 768, - show: false, - webPreferences: { - nodeIntegration: false, - allowpopups: true, - webSecurity: false, - nativeWindowOpen: true, - }, - resizable: true, - title: 'Powder Web', - center: true, - frame: false - }); + const quit = () => { - // Disable top menu bar on Windows/Linux - mainWindow.setMenu(null); + // if (mainWindow) + // mainWindow.destroy() - // and load the index.html of the app. - let indexPath; + if (mainWindow.isVisible()) + mainWindow.hide() - mainWindow.on('close', (e) => { - console.log('window-close') + tray.destroy() -// if (process.platform == 'linux') { -// quit() -// return -// } + var ticks = 3 - e.preventDefault() - mainWindow.hide() - if (app.dock) - app.dock.hide() - }); + const tick = () => { + ticks-- + if (!ticks) { + app.quit() + } + } - server.setMainWindow(mainWindow) + sop.unhackSopPlayer(() => { + sop.kill(tick, tick) + }) - // Build app menu - const menuBuilder = new MenuBuilder(mainWindow); - menuBuilder.buildMenu(); -} + streams.closeAll(tick) + + acestream.binary.kill(tick, tick) -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -let tray = false -app.on('ready', () => { - // Allow electron to serve static files - if (!dev) { - require('electron').protocol.interceptFileProtocol('file', (request, callback) => { - const url = request.url.substr(7) /* all urls start with 'file://' */ - callback({ path: path.normalize(`${__dirname}/dist/${url}`)}) - }, (err) => { - if (err) console.error('Failed to register protocol') - }) } - // Create the Browser window - if (dev) { - const { - default: installExtension, - REACT_DEVELOPER_TOOLS, - REDUX_DEVTOOLS - } = require('electron-devtools-installer'); - installExtension(REACT_DEVELOPER_TOOLS) - .then(() => installExtension(REDUX_DEVTOOLS)) - .then(() => createWindow()); - } else { - createServer(); + function createWindow() { + // Create the browser window. + mainWindow = new BrowserWindow({ + width: 1268, + height: 768, + show: false, + webPreferences: { + nodeIntegration: false, + allowpopups: true, + webSecurity: false, + nativeWindowOpen: true, + }, + resizable: true, + title: 'Powder Web', + center: true, + frame: false + }); + + // Disable top menu bar on Windows/Linux + mainWindow.setMenu(null); + + // and load the index.html of the app. + let indexPath; + + mainWindow.on('close', (e) => { + console.log('window-close') + + // if (process.platform == 'linux') { + // quit() + // return + // } + + e.preventDefault() + mainWindow.hide() + if (app.dock) + app.dock.hide() + }); + + server.setMainWindow(mainWindow) + + // Build app menu + const menuBuilder = new MenuBuilder(mainWindow); + menuBuilder.buildMenu(); } -if (process.platform == 'darwin' || process.platform == 'win32') { - tray = new Tray(path.join(__dirname, 'packaging', 'osx_tray.png')) -} else { - tray = new Tray(path.join(__dirname, 'packaging', 'icons', 'powder-square-border.png')) -} - const showApp = () => { - if (!mainWindow.isVisible()) { - mainWindow.loadURL( 'http' + (server.isSSL ? 's': '') + '://127.0.0.1:' + server.port() + '/auth?token=' + server.masterKey ); - mainWindow.show() - mainWindow.focus() - if (app.dock && !app.dock.isVisible()) - app.dock.show() - if (dev) { - mainWindow.webContents.openDevTools() - } + // This method will be called when Electron has finished + // initialization and is ready to create browser windows. + // Some APIs can only be used after this event occurs. + let tray = false + app.on('ready', () => { + // Allow electron to serve static files + if (!dev) { + require('electron').protocol.interceptFileProtocol('file', (request, callback) => { + const url = request.url.substr(7) /* all urls start with 'file://' */ + callback({ path: path.normalize(`${__dirname}/dist/${url}`)}) + }, (err) => { + if (err) console.error('Failed to register protocol') + }) + } + + // Create the Browser window + if (dev) { + const { + default: installExtension, + REACT_DEVELOPER_TOOLS, + REDUX_DEVTOOLS + } = require('electron-devtools-installer'); + installExtension(REACT_DEVELOPER_TOOLS) + .then(() => installExtension(REDUX_DEVTOOLS)) + .then(() => createWindow()); } else { - mainWindow.focus() + createServer(createWindow); } + + if (process.platform == 'darwin' || process.platform == 'win32') { + tray = new Tray(path.join(__dirname, 'packaging', 'osx_tray.png')) + } else { + tray = new Tray(path.join(__dirname, 'packaging', 'icons', 'powder-square-border.png')) } - const copyEmbedKey = () => { - const servUrl = 'http' + (server.isSSL ? 's': '') + '://127.0.0.1:' + server.port() + '/' - const embedKey = server.embedKey - clipboard.writeText(embedKey + '-' + btoa(servUrl)); - } - const copyLink = (qrType) => { + const showApp = () => { + if (!mainWindow.isVisible()) { + mainWindow.loadURL( 'http' + (server.isSSL ? 's': '') + '://127.0.0.1:' + server.port() + '/auth?token=' + server.masterKey ); + mainWindow.show() + mainWindow.focus() + if (app.dock && !app.dock.isVisible()) + app.dock.show() + if (dev) { + mainWindow.webContents.openDevTools() + } + } else { + mainWindow.focus() + } + } + const copyEmbedKey = () => { + const servUrl = 'http' + (server.isSSL ? 's': '') + '://127.0.0.1:' + server.port() + '/' + const embedKey = server.embedKey + clipboard.writeText(embedKey + '-' + btoa(servUrl)); + } + const copyLink = (qrType) => { - qrCode(qrType, server.argsKey, server.port(), (resp) => { - if (resp && resp.url) - clipboard.writeText(resp.url); - }, (err) => { + qrCode(qrType, server.argsKey, server.port(), (resp) => { + if (resp && resp.url) + clipboard.writeText(resp.url); + }, (err) => { - }) - } - const copyLanLink = () => { copyLink('local') } - const copyInternetLink = () => { copyLink('internet') } - const showBrowser = () => { - opn('http' + (server.isSSL ? 's': '') + '://127.0.0.1:' + server.port() + '/auth?token=' + server.masterKey) - } + }) + } + const copyLanLink = () => { copyLink('local') } + const copyInternetLink = () => { copyLink('internet') } + const showBrowser = () => { + opn('http' + (server.isSSL ? 's': '') + '://127.0.0.1:' + server.port() + '/auth?token=' + server.masterKey) + } - const toggleStartUp = () => { + const toggleStartUp = () => { - autoLauncher.isEnabled() - .then(function(isEnabled){ - if(isEnabled){ - autoLauncher.disable() - } else { - autoLauncher.enable() - } - }) - .catch(function(err){ }) + autoLauncher.isEnabled() + .then(function(isEnabled){ + if(isEnabled){ + autoLauncher.disable() + } else { + autoLauncher.enable() + } + }) + .catch(function(err){ }) - } + } - const relaunch = () => { -// mainWindow.destroy() -// streams.closeAll(() => { - app.relaunch() - quit() -// }) - } + const relaunch = () => { + // mainWindow.destroy() + // streams.closeAll(() => { + app.relaunch() + quit() + // }) + } - events.on('appQuit', quit) - events.on('appRelaunch', relaunch) - events.on('appShow', showApp) - events.on('appShowBrowser', showBrowser) - - const buildContextMenu = (startUp) => { - const contextMenu = Menu.buildFromTemplate([ - { - label: 'Show App', - type: 'normal', - click: showApp - }, - { - label: 'Show in Browser', - type: 'normal', - click: showBrowser - }, - { type: 'separator' }, - { - label: 'Copy LAN Link', - type: 'normal', - click: copyLanLink - }, - { - label: 'Copy Internet Link', - type: 'normal', - click: copyInternetLink - }, - { type: 'separator' }, - { - label: 'Copy Embed Key', - type: 'normal', - click: copyEmbedKey - }, - { type: 'separator' }, - { - label: 'Run on Start-Up', - type: 'checkbox', - checked: startUp, - click: toggleStartUp - }, - { type: 'separator' }, - { - label: 'Restart', - type: 'normal', - click: relaunch - }, - { - label: 'Quit', - type: 'normal', - click: quit - } - ]) - tray.setContextMenu(contextMenu) - } + events.on('appQuit', quit) + events.on('appRelaunch', relaunch) + events.on('appShow', showApp) + events.on('appShowBrowser', showBrowser) + + const buildContextMenu = (startUp) => { + const contextMenu = Menu.buildFromTemplate([ + { + label: 'Show App', + type: 'normal', + click: showApp + }, + { + label: 'Show in Browser', + type: 'normal', + click: showBrowser + }, + { type: 'separator' }, + { + label: 'Copy LAN Link', + type: 'normal', + click: copyLanLink + }, + { + label: 'Copy Internet Link', + type: 'normal', + click: copyInternetLink + }, + { type: 'separator' }, + { + label: 'Copy Embed Key', + type: 'normal', + click: copyEmbedKey + }, + { type: 'separator' }, + { + label: 'Run on Start-Up', + type: 'checkbox', + checked: startUp, + click: toggleStartUp + }, + { type: 'separator' }, + { + label: 'Restart', + type: 'normal', + click: relaunch + }, + { + label: 'Quit', + type: 'normal', + click: quit + } + ]) + tray.setContextMenu(contextMenu) + } - tray.on('click', showApp) + tray.on('click', showApp) - tray.setToolTip('Powder Web') + tray.setToolTip('Powder Web') - autoLauncher.isEnabled() - .then(function(isEnabled){ - buildContextMenu(isEnabled) - }).catch(function(err){ - buildContextMenu(false) - }) -}); - -//Quit when all windows are closed. -// app.on('window-all-closed', () => { -// // On macOS it is common for applications and their menu bar -// // to stay active until the user quits explicitly with Cmd + Q -// if (process.platform !== 'darwin') { -// app.quit(); -// } -// }); - -app.on('window-all-closed', app.quit); - -app.on('activate', () => { - // On macOS it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow(); - } -}); + autoLauncher.isEnabled() + .then(function(isEnabled){ + buildContextMenu(isEnabled) + }).catch(function(err){ + buildContextMenu(false) + }) + }); -app.on('before-quit', () => { - if (!mainWindow) return - mainWindow.removeAllListeners('close'); - mainWindow.destroy(); -}); + //Quit when all windows are closed. + // app.on('window-all-closed', () => { + // // On macOS it is common for applications and their menu bar + // // to stay active until the user quits explicitly with Cmd + Q + // if (process.platform !== 'darwin') { + // app.quit(); + // } + // }); + + app.on('window-all-closed', app.quit); + + app.on('activate', () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow(); + } + }); + app.on('before-quit', () => { + if (!mainWindow) return + mainWindow.removeAllListeners('close'); + mainWindow.destroy(); + }); +} diff --git a/package.json b/package.json index 778f42a..c907508 100755 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "clean:packages:": "rimraf ./packages", "lint": "eslint ./src ./tools ./webpackConfig \"./*.js\"", "start-back": "cross-env NODE_ENV=development electron .", + "start-headless": "node main.js", "electron-production": "cross-env NODE_ENV=production electron .", "prepackage": "run-s clean:packages", "build-back": "electron-packager ./ --out=./packages --icon=./packaging/icons/powder --ignore=\"tools|docs|webpackConfig|lock|public/\"", @@ -33,7 +34,6 @@ "decompress-zip": "https://github.com/jaruba/decompress-zip/tarball/master", "duti-prebuilt": "https://github.com/jaruba/duti-prebuilt/tarball/master", "easy-ffmpeg": "https://github.com/jaruba/easy-ffmpeg/tarball/master", - "electron-settings": "https://github.com/jaruba/electron-settings/tarball/master", "formidable": "^1.2.1", "frisbee": "^1.6.0", "get-port": "^3.2.0", @@ -49,7 +49,7 @@ "node-notifier": "^5.2.1", "npm-run-all": "^4.1.3", "opensubtitles-api": "https://github.com/jaruba/opensubtitles-api/tarball/master", - "opn": "^5.3.0", + "open": "^7.0.0", "parse-torrent": "^6.0.0", "prop-types": "^15.6.0", "pump": "^3.0.0", @@ -96,9 +96,6 @@ "babel-preset-env": "^1.7.0", "cross-env": "^5.0.0", "dotenv": "^4.0.0", - "electron": "^1.6.7", - "electron-devtools-installer": "^2.2.0", - "electron-packager": "^12.1.0", "eslint-config-react-tools": "^1.0.6", "eslint-plugin-class-property": "^1.0.6", "eslint-plugin-import": "^2.7.0", @@ -107,9 +104,6 @@ "npm-run-all": "^4.1.3", "nwb": "^0.19.1" }, - "optionalDependencies": { - "electron-installer-debian": "^0.8.1" - }, "repository": { "type": "git", "url": "https://github.com/jaruba/PowderWeb.git" diff --git a/server/acestream.js b/server/acestream.js index fba692a..ea3fc00 100755 --- a/server/acestream.js +++ b/server/acestream.js @@ -367,16 +367,18 @@ const connect = async (torrentHash, serverPort, peerflixProxy, reqToken, playlis let aceVersion -const { app } = require('electron') -const os = require('os') -const TMP = os.tmpDir() +const app = require('./utils/electronShim') + +const TMP = app.getPath('temp') const child = require('child_process') const exec = child.exec const spawn = child.spawn -const downloadLoc = path.join(app.getPath('appData'), 'PowderWeb') +const rootDir = app.getPath('appData') + +const downloadLoc = app.getPath('userData') const ace = { rename: (pid, name) => { @@ -401,7 +403,7 @@ const ace = { let cacheLoc if (process.platform == 'darwin') { - cacheLoc = path.join(app.getPath("appData"), "PowderWeb", "acestream", "Contents/Resources/wineprefix/drive_c/_acestream_cache_") + cacheLoc = path.join(downloadLoc, "acestream", "Contents/Resources/wineprefix/drive_c/_acestream_cache_") } else if (process.platform = 'win32') { cacheLoc = path.join((downloadLoc.split('\\')[0] || 'C:'), '_acestream_cache_') } @@ -462,7 +464,7 @@ const ace = { let cacheLoc if (process.platform == 'darwin') { - cacheLoc = path.join(app.getPath("appData"), "PowderWeb", "acestream", "Contents/Resources/wineprefix/drive_c/_acestream_cache_") + cacheLoc = path.join(downloadLoc, "acestream", "Contents/Resources/wineprefix/drive_c/_acestream_cache_") } else if (process.platform = 'win32') { cacheLoc = path.join((downloadLoc.split('\\')[0] || 'C:'), '_acestream_cache_') } @@ -522,9 +524,9 @@ const ace = { const isDirectory = source => fs.lstatSync(source).isDirectory() const getDirectories = source => fs.readdirSync(source) - getDirectories(app.getPath('appData')).forEach((dirNm) => { + getDirectories(rootDir).forEach((dirNm) => { if (dirNm.startsWith('com.aceengine.powder')) - portLocs.push(path.join(app.getPath('appData'), dirNm, locOnDrive)) + portLocs.push(path.join(rootDir, dirNm, locOnDrive)) }) } else if (process.platform == 'win32') { portLocs = [path.join(downloadLoc, 'acestream\\engine\\acestream.port')] @@ -566,9 +568,9 @@ const ace = { const isDirectory = source => fs.lstatSync(source).isDirectory() const getDirectories = source => fs.readdirSync(source) - getDirectories(app.getPath('appData')).forEach((dirNm) => { + getDirectories(rootDir).forEach((dirNm) => { if (dirNm.startsWith('com.aceengine.powder')) - portLocs.push(path.join(app.getPath('appData'), dirNm, locOnDrive)) + portLocs.push(path.join(rootDir, dirNm, locOnDrive)) }) } else if (process.platform == 'win32') { portLocs = [path.join(downloadLoc, 'acestream\\engine\\acestream.port')] diff --git a/server/index.js b/server/index.js index e97003b..1fbf5b7 100755 --- a/server/index.js +++ b/server/index.js @@ -1,9 +1,11 @@ -const { app, shell, dialog } = require('electron'); const fs = require('fs'); const path = require('path'); const ffmpeg = require('easy-ffmpeg') -var dir = path.join(app.getPath('appData'), 'PowderWeb'); + +const app = require('./utils/electronShim') + +var dir = app.getPath('userData'); const openerDir = path.join(dir, 'openers') @@ -58,12 +60,12 @@ const https = require('https') const url = require('url') const streams = require('./streams') const childProcess = require('child_process') -const settings = require('electron-settings') +const settings = app.settings() const config = require('./utils/config') const getPort = require('get-port') const _ = require('lodash') const os = require('os') -const TMP = os.tmpDir() +const TMP = app.getPath('temp') const platform = os.platform() const addresses = require('./utils/addressbook') const uniqueString = require('unique-string') @@ -85,7 +87,7 @@ const hlsLink = require('./utils/live-trans') const srt2vtt = require('srt-to-vtt') -const opn = require('opn') +const opn = require('open') const helpers = require('./utils/misc') @@ -118,6 +120,8 @@ let tokens = { [argsKey]: true } +const haveElectron = require('./utils/haveElectron') + const passArgs = function(e, args) { clArgs.process(Array.isArray(args) ? args : [args], argsKey); } @@ -125,12 +129,17 @@ const passArgs = function(e, args) { if (process.platform !== 'darwin') { passArgs(null, process.argv) } else { - // these events are OSX only: - app.on('open-file', passArgs); - app.on('open-url', passArgs); + if (haveElectron()) { + // these events are OSX only: + const appUtil = require('electron').app + appUtil.on('open-file', passArgs); + appUtil.on('open-url', passArgs); + } else { + // should think of alternative for headless + } } -if (process.env.NODE_ENV === 'development') { +if (process.env.NODE_ENV === 'development' || !haveElectron()) { console.log('master key: '+ masterKey) } @@ -409,12 +418,12 @@ const mainServer = http.createServer(function(req, resp) { // open with default player streams.createPlaylist(torrentId, organizedFiles, reqToken, false, playlist => { - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(dir, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, function(err) { if (err) { return console.log(err); } - shell.openItem(filePath) + app.openItem(filePath) }) }, reqUrl) } @@ -451,12 +460,12 @@ const mainServer = http.createServer(function(req, resp) { const tryConnect = () => { sop.connect(urlParsed.query.pid, peerflixProxy, reqToken, (playlist) => { // playlist cb - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(dir, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, (err) => { if (err) { return console.log(err); } - shell.openItem(filePath) + app.openItem(filePath) }) }, reqUrl) } @@ -499,7 +508,7 @@ const mainServer = http.createServer(function(req, resp) { } } - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(dir, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, newM3U, (err) => { if (err) { @@ -508,7 +517,7 @@ const mainServer = http.createServer(function(req, resp) { if (config.get('extPlayer')) { helpers.openApp(config.get('extPlayer'), config.get('playerCmdArgs'), filePath) } else { - shell.openItem(filePath) + app.openItem(filePath) } }) } @@ -529,7 +538,7 @@ const mainServer = http.createServer(function(req, resp) { newM3U += os.EOL+"#EXTINF:0,"+ytdl.name+os.EOL+uri } - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(dir, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, newM3U, (err) => { if (err) { @@ -538,7 +547,7 @@ const mainServer = http.createServer(function(req, resp) { if (config.get('extPlayer')) { helpers.openApp(config.get('extPlayer'), config.get('playerCmdArgs'), filePath) } else { - shell.openItem(filePath) + app.openItem(filePath) } }) } @@ -573,12 +582,12 @@ const mainServer = http.createServer(function(req, resp) { } else { acestream.connect(pid, servPort, peerflixProxy, reqToken, (playlist) => { // playlist cb - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(dir, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, function(err) { if (err) { return console.log(err); } - shell.openItem(filePath) + app.openItem(filePath) }) }, reqUrl) } @@ -938,7 +947,7 @@ const mainServer = http.createServer(function(req, resp) { notifier.on('click', (notifierObject, options) => { streams.getPath(engine.infoHash, (folderPath) => { if (folderPath) { - shell.openItem(folderPath) + app.openItem(folderPath) } }) }) @@ -1264,12 +1273,12 @@ const mainServer = http.createServer(function(req, resp) { streams.createPlaylist(torrentId, organizedFiles, reqToken, urlParsed.query.fileID || false, playlist => { if (isMaster && urlParsed.query.openNow) { - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(dir, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, function(err) { if (err) { return console.log(err); } - shell.openItem(filePath) + app.openItem(filePath) }) if (doneResp) return respond({}) @@ -1596,19 +1605,19 @@ const mainServer = http.createServer(function(req, resp) { } if (method == 'jackettLink') { - shell.openExternal('https://github.com/jaruba/PowderWeb/wiki/Enable-Jackett') + app.openExternal('https://github.com/jaruba/PowderWeb/wiki/Enable-Jackett') respond({}) return } if (method == 'donateLink') { - shell.openExternal('https://powder.media/donate') + app.openExternal('https://powder.media/donate') respond({}) return } if (method == 'sopGuideLink') { - shell.openExternal('https://github.com/jaruba/PowderWeb/wiki/Enable-Sopcast') + app.openExternal('https://github.com/jaruba/PowderWeb/wiki/Enable-Sopcast') respond({}) return } @@ -1633,7 +1642,7 @@ const mainServer = http.createServer(function(req, resp) { } if (method == 'addLocal') { - const loc = dialog.showOpenDialog({filters: { name: 'media', extensions: supported.ext.allMedia.map(el => { return el.replace('.','') })}, properties: ['openFile', 'openDirectory', 'createDirectory']}) + const loc = app.showOpenDialog({filters: { name: 'media', extensions: supported.ext.allMedia.map(el => { return el.replace('.','') })}, properties: ['openFile', 'openDirectory', 'createDirectory']}) if (!loc || !loc.length) { respond({}) } else { @@ -1659,19 +1668,19 @@ const mainServer = http.createServer(function(req, resp) { // this is for subtitles, because we can't download files in electron // so we download the subtitle programmatically and open the temp download folder helpers.downloadFile(atob(urlParsed.query.file), (filePath, dirPath) => { - shell.showItemInFolder(filePath) + app.showItemInFolder(filePath) respond({}) }) return } if (method == 'selectFile') { - respond({ value: dialog.showOpenDialog({properties: ['openFile']}) }) + respond({ value: app.showOpenDialog({properties: ['openFile']}) }) return } if (method == 'selectFolder') { - respond({ value: dialog.showOpenDialog({properties: ['openDirectory', 'createDirectory']}) }) + respond({ value: app.showOpenDialog({properties: ['openDirectory', 'createDirectory']}) }) return } @@ -1704,7 +1713,7 @@ const mainServer = http.createServer(function(req, resp) { if (!filePath) { page500('Path to file could not be found') } else { - shell.openItem(filePath) + app.openItem(filePath) respond({}) } }) @@ -1716,7 +1725,7 @@ const mainServer = http.createServer(function(req, resp) { if (!filePath) { page500('Path to file could not be found') } else { - shell.showItemInFolder(filePath) + app.showItemInFolder(filePath) respond({}) } }) @@ -1727,11 +1736,11 @@ const mainServer = http.createServer(function(req, resp) { const loc = local.get(urlParsed.query.pid) if (loc) { if (loc.location) { - shell.showItemInFolder(loc.location) + app.showItemInFolder(loc.location) } else if (loc.files && loc.files.length) { const fl = loc.files[urlParsed.query.flId || 0] if (fl && fl.location) { - shell.showItemInFolder(fl.location) + app.showItemInFolder(fl.location) } else { page500('Unknown Error Occurred') } @@ -1747,7 +1756,7 @@ const mainServer = http.createServer(function(req, resp) { if (method == 'localDirLoc' && urlParsed.query.pid) { const loc = local.get(urlParsed.query.pid) if (loc && loc.location) { - shell.openItem(loc.location) + app.openItem(loc.location) } return } @@ -1757,7 +1766,7 @@ const mainServer = http.createServer(function(req, resp) { if (!folderPath) { page500('Path to folder could not be found') } else { - shell.openItem(folderPath) + app.openItem(folderPath) respond({}) } }) @@ -1766,9 +1775,9 @@ const mainServer = http.createServer(function(req, resp) { if (method == 'openDefaultFolder') { if (config.get('downloadFolder')) - shell.openItem(config.get('downloadFolder')) + app.openItem(config.get('downloadFolder')) else - shell.openItem(path.join(app.getPath('temp'), 'PowderWeb')) + app.openItem(path.join(TMP, 'PowderWeb')) respond({}) return } @@ -1886,7 +1895,13 @@ const mainServer = http.createServer(function(req, resp) { return page404() -}).listen(port, () => { }) +}).listen(port, () => { + if (!haveElectron()) { + // headless mode, open browser + const isSSL = config.get('webServerSSL') || false + app.openExternal('http' + (isSSL ? 's': '') + '://localhost:' + serverPort + '/auth?token=' + masterKey) + } +}) mainServer.on('connection', function (socket) { socket.setTimeout(Number.MAX_SAFE_INTEGER) @@ -2466,7 +2481,7 @@ var srv = http.createServer(function (req, res) { srv.on('listening',function() { }) - if (process.env.NODE_ENV !== 'development') { + if (process.env.NODE_ENV !== 'development' || !haveElectron()) { // create web server var webProxy = require('http-proxy').createProxyServer({ diff --git a/server/presets/defaults.js b/server/presets/defaults.js index 4c3354f..98429a6 100755 --- a/server/presets/defaults.js +++ b/server/presets/defaults.js @@ -1,4 +1,5 @@ -const { app } = require('electron') +const app = require('../utils/electronShim') +const userData = app.getPath('userData') const _ = require('lodash') const mkdirp = require('mkdirp') const path = require('path') @@ -11,10 +12,10 @@ const userDataFolders = [ const fs = require('fs') userDataFolders.forEach(folder => { - mkdirp(path.join(app.getPath('userData'), folder), () => {}) + mkdirp(path.join(userData, folder), () => {}) }) -const settings = require('electron-settings') +const settings = app.settings() // defaults const map = { diff --git a/server/sopcast.js b/server/sopcast.js index 3e49840..b3e9f28 100644 --- a/server/sopcast.js +++ b/server/sopcast.js @@ -1,9 +1,9 @@ const fs = require('fs') const path = require('path') -const { app } = require('electron') -const os = require('os') -const TMP = os.tmpDir() +const app = require('./utils/electronShim') + +const TMP = app.getPath('temp') const child = require('child_process') @@ -14,7 +14,7 @@ const getPort = require('get-port') const downloader = require('./utils/downloadPackage') -const downloadLoc = path.join(app.getPath('appData'), 'PowderWeb') +const downloadLoc = app.getPath('userData') const net = require('net') diff --git a/server/streams.js b/server/streams.js index 37caf31..62a707b 100755 --- a/server/streams.js +++ b/server/streams.js @@ -1,5 +1,5 @@ -const { app } = require('electron') +const app = require('./utils/electronShim') const createTorrent = require('./utils/torrent') const config = require('./utils/config') const parser = require('./utils/parser') @@ -22,9 +22,11 @@ const isTorrentString = require('./utils/isTorrentString') const rimraf = require('rimraf') const checksum = require('checksum') -const openerDir = path.join(app.getPath('appData'), 'PowderWeb', 'openers') -const tempDir = path.join(os.tmpDir(), 'PowderWeb', 'torrent-stream') -const fastResumeDir = path.join(app.getPath('appData'), 'PowderWeb', 'fastresume') +const userData = app.getPath('userData') + +const openerDir = path.join(userData, 'openers') +const tempDir = path.join(app.getPath('temp'), 'torrent-stream') +const fastResumeDir = path.join(userData, 'fastresume') let loading = {} diff --git a/server/utils/acebook.js b/server/utils/acebook.js index 7b5ed1f..51e1201 100644 --- a/server/utils/acebook.js +++ b/server/utils/acebook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('acebook') diff --git a/server/utils/acenamebook.js b/server/utils/acenamebook.js index a9ede03..9bcf26e 100644 --- a/server/utils/acenamebook.js +++ b/server/utils/acenamebook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('acenamebook') diff --git a/server/utils/addressbook.js b/server/utils/addressbook.js index 01a1e82..907ccb1 100755 --- a/server/utils/addressbook.js +++ b/server/utils/addressbook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('addressbook') diff --git a/server/utils/backup.js b/server/utils/backup.js index 1779d88..7633c31 100644 --- a/server/utils/backup.js +++ b/server/utils/backup.js @@ -1,9 +1,9 @@ +const app = require('./electronShim') + const fs = require('fs'), path = require('path'), - { app } = require('electron') - -const appData = path.join(app.getPath('appData'), 'PowderWeb') + appData = app.getPath('userData') const paths = { settings: path.join(appData, 'Settings'), diff --git a/server/utils/clArgs.js b/server/utils/clArgs.js index a048cbe..ac828c1 100644 --- a/server/utils/clArgs.js +++ b/server/utils/clArgs.js @@ -5,10 +5,11 @@ const streams = require('../streams') const acestream = require('../acestream') const youtube = require('../ytdl') const sop = require('../sopcast') -const { app, shell } = require('electron') -const helpers = require('../utils/misc') -const events = require('../utils/events') -const isTorrentString = require('../utils/isTorrentString') +const app = require('./electronShim') +const userData = app.getPath('userData') +const helpers = require('./misc') +const events = require('./events') +const isTorrentString = require('./isTorrentString') const fs = require('fs') const runPlaylist = (torrentId, organizedFiles, infoHash, reqToken, opts) => { @@ -24,7 +25,7 @@ const runPlaylist = (torrentId, organizedFiles, infoHash, reqToken, opts) => { if (config.get('useWebPlayerAssoc') || (opts && opts.runWebPlayer)) { const webPlayerUrl = serverUrl + '/embed?opener=' + infoHash + '&token=' + reqToken - shell.openExternal(webPlayerUrl) + app.openExternal(webPlayerUrl) } else { if (config.get('extPlayer')) { @@ -40,13 +41,13 @@ const runPlaylist = (torrentId, organizedFiles, infoHash, reqToken, opts) => { // open with default player streams.createPlaylist(torrentId, organizedFiles, reqToken, false, playlist => { - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(userData, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, function(err) { if (err) { return console.log(err); } - shell.openItem(filePath) + app.openItem(filePath) }) }, serverUrl) } @@ -87,7 +88,7 @@ const runAcePlaylist = (pid, reqToken) => { } else { acestream.connect(pid, servPort, peerflixProxy, reqToken, (playlist) => { // playlist cb - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(userData, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, function(err) { if (err) { return console.log(err); @@ -160,7 +161,7 @@ const runSopPlaylist = (pid, reqToken) => { const tryConnect = () => { sop.connect(urlParsed.query.pid, peerflixProxy, reqToken, (playlist) => { // playlist cb - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(userData, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, playlist, (err) => { if (err) { return console.log(err); @@ -280,7 +281,7 @@ const runTorrent = (torrentQuery, reqToken, noAction, opts) => { newM3U += os.EOL+"#EXTINF:0,"+ytdl.name+os.EOL+uri } - const filePath = path.join(app.getPath('appData'), 'PowderWeb', 'playlist'+(Date.now())+'.m3u') + const filePath = path.join(userData, 'playlist'+(Date.now())+'.m3u') fs.writeFile(filePath, newM3U, (err) => { if (err) { diff --git a/server/utils/config.js b/server/utils/config.js index 20ac25f..6175f2b 100644 --- a/server/utils/config.js +++ b/server/utils/config.js @@ -3,9 +3,13 @@ const jsonfile = require('jsonfile') const uniqueString = require('unique-string') const path = require('path') -const { app } = require('electron') +const app = require('./electronShim') -const configPath = path.join(app.getPath('appData'), 'PowderWeb', 'config.json') +const userData = app.getPath('userData') + +const configPath = path.join(userData, 'config.json') + +const haveElectron = require('./haveElectron') let map = { // torrentContent: false, @@ -25,7 +29,7 @@ let map = { forceDownload: false, peerID: 'PW0700', maxConcurrency: 2, - maxUsers: 0, + maxUsers: haveElectron() ? 0 : 1, // start from 1 user in headless mode webServerPort: 3000, webServerSSL: false, downloadFolder: '', diff --git a/server/utils/downloadPackage.js b/server/utils/downloadPackage.js index 3a498ee..5046cf3 100644 --- a/server/utils/downloadPackage.js +++ b/server/utils/downloadPackage.js @@ -4,9 +4,8 @@ const simpleGet = require('simple-get') const decopressZip = require('decompress-zip') const fs = require('fs') const path = require('path') -const { app } = require('electron') - -const downloadLoc = path.join(app.getPath('appData'), 'PowderWeb') +const app = require('./electronShim') +const downloadLoc = app.getPath('userData') const downloader = { diff --git a/server/utils/electronShim.js b/server/utils/electronShim.js new file mode 100644 index 0000000..477e439 --- /dev/null +++ b/server/utils/electronShim.js @@ -0,0 +1,100 @@ +// this project also supports a headless mode +// so this file will try to reproduce electron +// features with just nodejs + +const fs = require('fs') +const path = require('path') +const os = require('os') +const opn = require('open') +const haveElectron = require('./haveElectron.js')() + +const rootDir = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + '/.local/share') + +let configDir + +const electronShim = { + getPath: data => { + if (haveElectron) { + const { app } = require('electron') + return app.getPath(data) + } else { + if (data == 'userData') { + if (configDir) + return configDir + + configDir = path.join(rootDir, 'PowderWeb') + + if (!fs.existsSync(configDir)) + fs.mkdirSync(configDir) + + return configDir + } else if (data == 'appData') + return rootDir + else if (data == 'temp') + return os.tmpdir() + return false + } + }, + openItem: data => { + if (haveElectron) { + const { shell } = require('electron') + shell.openItem(data) + } else + opn(data) + }, + openExternal: data => { + if (haveElectron) { + const { shell } = require('electron') + shell.openExternal(data) + } else + opn(data) + }, + showItemInFolder: data => { + if (haveElectron) { + const { shell } = require('electron') + shell.showItemInFolder(data) + } else { + + // there is no substitute for this that i know of + // using open folder instead + + opn(path.dirname(data)) + + } + + return false + }, + showOpenDialog: data => { + if (haveElectron) { + const { dialog } = require('electron') + dialog.showOpenDialog(data) + } + + // there is no substitute for this that i know of + + return false + }, + setAsDefaultProtocolClient: data => { + if (haveElectron) { + const { app } = require('electron') + app.setAsDefaultProtocolClient(data); + } else { + + // only magnet link association will work + // in the headless version for now + + if (data == 'magnet') { + const dataPath = electronShim.getPath('userData') + fs.writeFile(dataPath+'\\register-link.reg', 'REGEDIT4\r\n[HKEY_CLASSES_ROOT\\Magnet]\r\n@="URL:magnet Protocol"\r\n"Content Type"="application/x-magnet"\r\n"URL Protocol"=""\r\n\[HKEY_CLASSES_ROOT\\Magnet\\DefaultIcon]\r\n@="\\"'+process.execPath.split("\\").join("\\\\")+'\\"\r\n[HKEY_CLASSES_ROOT\\Magnet\\shell]\r\n[HKEY_CLASSES_ROOT\\Magnet\\shell\\open]\r\n[HKEY_CLASSES_ROOT\\Magnet\\shell\\open\\command]\r\n@="\\"'+process.execPath.split("\\").join("\\\\")+'\\" \\"%1\\""\r\n[HKEY_CURRENT_USER\\Software\\Classes\\Magnet]\r\n@="URL:magnet Protocol"\r\n"Content Type"="application/x-magnet"\r\n"URL Protocol"=""\r\n[HKEY_CURRENT_USER\\Software\\Classes\\Magnet\\DefaultIcon]\r\n@="\\"'+process.execPath.split("\\").join("\\\\")+'\\"\r\n[HKEY_CURRENT_USER\\Software\\Classes\\Magnet\\shell]\r\n[HKEY_CURRENT_USER\\Software\\Classes\\Magnet\\shell\\open]\r\n[HKEY_CURRENT_USER\\Software\\Classes\\Magnet\\shell\\open\\command]\r\n@="\\"'+process.execPath.split("\\").join("\\\\")+'\\" \\"%1\\""', function (err) { + if (err) throw err; + opn(dataPath+'\\register-link.reg'); + }); + } + } + }, + settings: () => { + return haveElectron ? require('electron-settings') : require('./settingsShim') + } +} + +module.exports = electronShim diff --git a/server/utils/fastresumebook.js b/server/utils/fastresumebook.js index 5b35bde..c0c1edd 100644 --- a/server/utils/fastresumebook.js +++ b/server/utils/fastresumebook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('fastresumebook') diff --git a/server/utils/file_organizer.js b/server/utils/file_organizer.js index 489ab62..146ea94 100755 --- a/server/utils/file_organizer.js +++ b/server/utils/file_organizer.js @@ -3,9 +3,11 @@ const config = require('./config') const parser = require('./parser') const sorter = require('./sort') const supported = require('./isSupported') -const { app } = require('electron') const path = require('path') -const temp = path.join(app.getPath('temp'), 'Powder-Player') + +const app = require('./electronShim') + +const temp = path.join(app.getPath('temp'), 'PowderWeb') module.exports = (engine) => { return new Promise((resolve) => { diff --git a/server/utils/haveElectron.js b/server/utils/haveElectron.js new file mode 100644 index 0000000..8202d6e --- /dev/null +++ b/server/utils/haveElectron.js @@ -0,0 +1,14 @@ + +function moduleAvailable(name) { + try { + require.resolve(name) + return true + } catch(e){} + return false +} + +const haveElectron = moduleAvailable('electron') + +module.exports = () => { + return haveElectron +} \ No newline at end of file diff --git a/server/utils/live-trans.js b/server/utils/live-trans.js index 7d2ad0b..4b9a2b3 100644 --- a/server/utils/live-trans.js +++ b/server/utils/live-trans.js @@ -4,8 +4,8 @@ const path = require('path') const pump = require('pump') const getPort = require('get-port') const rangeParser = require('range-parser') -const os = require('os') -const TMP = os.tmpDir() +const app = require('./electronShim') +const TMP = app.getPath('temp') const pUrl = require('url') const ffmpeg = require('easy-ffmpeg') const http = require('http') diff --git a/server/utils/locbook.js b/server/utils/locbook.js index e91cdc3..9f7b8eb 100644 --- a/server/utils/locbook.js +++ b/server/utils/locbook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('locbook') diff --git a/server/utils/misc.js b/server/utils/misc.js index 487fefc..67fdb1d 100644 --- a/server/utils/misc.js +++ b/server/utils/misc.js @@ -1,5 +1,6 @@ +const app = require('./electronShim') +const TMP = app.getPath('temp') const os = require('os') -const TMP = os.tmpDir() const platform = os.platform() const childProcess = require('child_process') diff --git a/server/utils/register.js b/server/utils/register.js index b86dd7f..0c1fdb4 100644 --- a/server/utils/register.js +++ b/server/utils/register.js @@ -1,12 +1,9 @@ const child = require('child_process'); const fs = require('fs'); -const { - shell, - app -} -= require('electron'); -const dataPath = app.getPath('userData'); +const haveElectron = require('./haveElectron'); const regFileW32 = require('./regFileWin'); +const app = require('./electronShim'); +const dataPath = app.getPath('userData') const path = require('path'); const duti = require('duti-prebuilt'); diff --git a/server/utils/settingsShim.js b/server/utils/settingsShim.js new file mode 100644 index 0000000..985bbb8 --- /dev/null +++ b/server/utils/settingsShim.js @@ -0,0 +1,41 @@ +// this is a shim for electron-settings that +// is used when running in headless mode + + +const jsonfile = require('jsonfile') +const uniqueString = require('unique-string') +const path = require('path') + +const app = require('./electronShim') + +const userData = app.getPath('userData') + +const configPath = path.join(userData, 'settingsShim.json') + +let map = {} + +jsonfile.readFile(configPath, (err, obj) => { + if (err) + jsonfile.atomicWriteFileSync(configPath, map) + else + map = obj +}) + +const config = { + getAll: () => { + return map + }, + get: str => { + return map[str] + }, + set: (str, value) => { + map[str] = value + jsonfile.atomicWriteFileSync(configPath, map) + }, + has: key => { + return map.hasOwnProperty(key) + } +} + +module.exports = config + diff --git a/server/utils/sopbook.js b/server/utils/sopbook.js index 731709c..48512b9 100644 --- a/server/utils/sopbook.js +++ b/server/utils/sopbook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('sopbook') diff --git a/server/utils/torrent.js b/server/utils/torrent.js index aa5e529..00baa43 100755 --- a/server/utils/torrent.js +++ b/server/utils/torrent.js @@ -1,13 +1,14 @@ -const { app } = require('electron') const path = require('path') +const app = require('./electronShim') +const configDir = app.getPath('userData') const temp = path.join(app.getPath('temp'), 'PowderWeb') const torrentWorker = require('torrent-worker') const config = require('./config') const hat = require('hat') const getPort = require('get-port') const readTorrent = require('read-torrent') -const fastResumeDir = path.join(app.getPath('appData'), 'PowderWeb', 'fastresume') +const fastResumeDir = path.join(configDir, 'fastresume') module.exports = (torrent) => { diff --git a/server/utils/updater.js b/server/utils/updater.js index cb937a8..64dfc1e 100644 --- a/server/utils/updater.js +++ b/server/utils/updater.js @@ -1,6 +1,6 @@ const notifier = require('node-notifier') const needle = require('needle') -const { app, shell, dialog } = require('electron') +const app = require('./electronShim') const config = require('./config') let updateCheck = config.get('updateCheck') @@ -30,8 +30,9 @@ module.exports = { }, (err, response) => { if (!err) { config.set('updateCheck', Math.floor(Date.now() / 1000)) - if (response == 'activate') - shell.openExternal(vers[1]) + if (response == 'activate') { + app.openExternal(ver[1]) + } } }) diff --git a/server/utils/uploadedbook.js b/server/utils/uploadedbook.js index f140a2a..fbcdc8f 100644 --- a/server/utils/uploadedbook.js +++ b/server/utils/uploadedbook.js @@ -1,4 +1,4 @@ -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('uploaded') diff --git a/server/utils/ytdlbook.js b/server/utils/ytdlbook.js index 8adaae3..b29916a 100644 --- a/server/utils/ytdlbook.js +++ b/server/utils/ytdlbook.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const settings = require('electron-settings') +const settings = require('./electronShim').settings() let addresses = settings.get('ytdlbook') diff --git a/start.js b/start.js index 18da4fa..9d8eb37 100644 --- a/start.js +++ b/start.js @@ -6,7 +6,7 @@ var getPort = require('get-port') var child = require('child_process') -var opn = require('opn') +var opn = require('open') var masterKey var serverLink @@ -16,6 +16,8 @@ var checkOpen = function() { opn(serverLink + 'auth?token=' + masterKey) } +var haveElectron = require('./server/utils/haveElectron') + var gotPorts = function() { var isWin = process.platform === 'win32' @@ -50,7 +52,7 @@ var gotPorts = function() { console.log('web server exit') }) - var backProc = child.spawn('npm' + (isWin ? '.cmd' : ''), ['run', 'start-back'], + var backProc = child.spawn('npm' + (isWin ? '.cmd' : ''), ['run', 'start-back' + (!haveElectron() ? '-headless' : '')], { cwd: process.cwd(), env: newEnv