@@ -32,7 +32,9 @@ module.exports = { | |||
], | |||
root: true, | |||
rules: { | |||
"no-param-reassign": "off", | |||
"class-methods-use-this": "off", | |||
"no-trailing-spaces": "warn", | |||
"comma-dangle": "warn", | |||
"global-require": "off", | |||
"import/default": "warn", |
@@ -1,5 +0,0 @@ | |||
// tippy.js | |||
@import 'tippy.js/index.css'; | |||
@import 'tippy.js/themes/light.css'; | |||
@import '~cropperjs/src/css/cropper'; |
@@ -1,6 +1,6 @@ | |||
@tailwind base; | |||
@import './base/reset'; | |||
// @import './base/reset'; | |||
@tailwind components; | |||
@import './components/all'; | |||
//@import './components/all'; | |||
@tailwind utilities; | |||
@import './utilities/all'; | |||
//@import './utilities/all'; |
@@ -55,7 +55,7 @@ export default { | |||
methods: { | |||
createError() { | |||
throw new Error('UI test error.') | |||
throw new Error('User Interface test error.') | |||
}, | |||
}, | |||
} |
@@ -30,6 +30,8 @@ | |||
</template> | |||
<script> | |||
import { requirements } from '~/modules/system' | |||
const { settings } = $provider | |||
export default { |
@@ -1,40 +1,8 @@ | |||
/* eslint-disable no-template-curly-in-string */ | |||
const pkg = require('./package.json') | |||
module.exports = { | |||
appId: 'com.dreamnet.dreamtime', | |||
productName: process.env.npm_package_displayName, | |||
copyright: 'Copyright (C) DreamNet. All rights reserved.', | |||
directories: { | |||
output: '../dist', | |||
}, | |||
files: [ | |||
'!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}', | |||
'!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}', | |||
'!**/node_modules/*.d.ts', | |||
'!**/node_modules/.bin', | |||
'!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj,vscode,env.example,eslintrc.json,prettierrc,tgz}', | |||
'!.editorconfig', | |||
'!**/._*', | |||
'!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}', | |||
'!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}', | |||
'!**/{appveyor.yml,.travis.yml,circle.yml}', | |||
'!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}', | |||
'!**/{jsconfig.json,electron-builder.js,.eslintrc.js,.env-cmdrc.js,.codeclimate.yml,.babelrc,tailwind.config.js,nucleus.json}', | |||
'!{components,cli,layouts,middleware,mixins,pages,patches,plugins,scripts,store,third,coverage,.nuxt,test,workers}', | |||
'!{static,assets}', | |||
'!**/electron/src', | |||
], | |||
extraFiles: [ | |||
{ | |||
from: '.env', | |||
to: '.env', | |||
}, | |||
{ | |||
from: 'package.copy.json', | |||
to: 'package.json', | |||
}, | |||
], | |||
const windows = { | |||
win: { | |||
target: 'nsis', | |||
extraResources: [ | |||
@@ -48,6 +16,19 @@ module.exports = { | |||
}, | |||
], | |||
}, | |||
nsis: { | |||
oneClick: false, | |||
perMachine: false, | |||
allowToChangeInstallationDirectory: true, | |||
uninstallDisplayName: '${productName}', | |||
deleteAppDataOnUninstall: true, | |||
displayLanguageSelector: true, | |||
menuCategory: true, | |||
artifactName: '${productName}-v${version}-windows.${ext}', | |||
}, | |||
} | |||
const linux = { | |||
linux: { | |||
target: 'snap', | |||
executableName: process.env.npm_package_name, | |||
@@ -60,6 +41,12 @@ module.exports = { | |||
}, | |||
], | |||
}, | |||
snap: { | |||
artifactName: '${productName}-v${version}-ubuntu.${ext}', | |||
}, | |||
} | |||
const macos = { | |||
mac: { | |||
target: 'dmg', | |||
darkModeSupport: true, | |||
@@ -78,25 +65,48 @@ module.exports = { | |||
}, | |||
], | |||
}, | |||
nsis: { | |||
oneClick: false, | |||
perMachine: false, | |||
allowToChangeInstallationDirectory: true, | |||
uninstallDisplayName: '${productName}', | |||
deleteAppDataOnUninstall: true, | |||
displayLanguageSelector: true, | |||
menuCategory: true, | |||
artifactName: '${productName}-v${version}-windows.${ext}', | |||
}, | |||
snap: { | |||
plugs: ['default', { | |||
'personal-files': { read: ['$HOME'], write: ['$HOME'] }, | |||
}], | |||
artifactName: '${productName}-v${version}-ubuntu.${ext}', | |||
}, | |||
dmg: { | |||
title: '${productName}', | |||
artifactName: '${productName}-v${version}-macos.${ext}', | |||
backgroundColor: '#000', | |||
}, | |||
} | |||
module.exports = { | |||
appId: 'com.dreamnet.dreamtime', | |||
productName: process.env.npm_package_displayName, | |||
copyright: 'Copyright (C) DreamNet. All rights reserved.', | |||
directories: { | |||
output: '../dist', | |||
}, | |||
files: [ | |||
'!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}', | |||
'!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}', | |||
'!**/node_modules/*.d.ts', | |||
'!**/node_modules/.bin', | |||
'!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj,vscode,env.example,eslintrc.json,prettierrc,tgz}', | |||
'!.editorconfig', | |||
'!**/._*', | |||
'!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}', | |||
'!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}', | |||
'!**/{appveyor.yml,.travis.yml,circle.yml}', | |||
'!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}', | |||
'!**/{jsconfig.json,electron-builder.js,.eslintrc.js,.env-cmdrc.js,.codeclimate.yml,.babelrc,tailwind.config.js,nucleus.json}', | |||
'!{components,cli,layouts,middleware,mixins,pages,patches,plugins,scripts,store,third,coverage,.nuxt,test,workers}', | |||
'!{static,assets}', | |||
'!**/electron/src', | |||
], | |||
extraFiles: [ | |||
{ | |||
from: '.env', | |||
to: '.env', | |||
}, | |||
{ | |||
from: 'package.min.json', | |||
to: 'package.json', | |||
}, | |||
], | |||
...windows, | |||
...linux, | |||
...macos, | |||
} |
@@ -9,17 +9,13 @@ | |||
import { startsWith } from 'lodash' | |||
import { app, BrowserWindow, shell } from 'electron' | |||
import http from 'http' | |||
import { dirname, join } from 'path' | |||
import { URL } from 'url' | |||
import contextMenu from 'electron-context-menu' | |||
import { dirname, resolve } from 'path' | |||
import Logger from 'logplease' | |||
import { enforceMacOSAppLocation } from 'electron-util' | |||
import fs from 'fs-extra' | |||
import { AppError } from './modules/app-error' | |||
import { system } from './modules/tools/system' | |||
import { existsSync, mkdirSync } from './modules/tools/fs' | |||
import { getPath } from './modules/tools/paths' | |||
import { settings } from './modules/settings' | |||
import { settings, ngrok } from './modules' | |||
import config from '~/nuxt.config' | |||
const logger = Logger.create('electron') | |||
@@ -27,7 +23,8 @@ const logger = Logger.create('electron') | |||
// NuxtJS root directory | |||
config.rootDir = dirname(dirname(__dirname)) | |||
if (process.env.NODE_ENV === 'production') { | |||
if (process.env.name === 'production') { | |||
// make sure that the working directory is where the executable is | |||
process.chdir(getPath('exe', '..')) | |||
} | |||
@@ -37,20 +34,21 @@ class DreamApp { | |||
*/ | |||
window | |||
/** | |||
* | |||
*/ | |||
static async boot() { | |||
// logger setup | |||
Logger.setLogLevel(process.env.LOG || 'info') | |||
Logger.setLogfile(getPath('userData', 'dreamtime.log')) | |||
Logger.setOptions({ | |||
filename: getPath('userData', 'dreamtime.main.log'), | |||
logLevel: process.env.LOG || 'debug', | |||
}) | |||
logger.info('Booting...') | |||
logger.debug({ | |||
env: process.env.name, | |||
paths: { | |||
appPath: app.getAppPath(), | |||
exePath: app.getPath('exe'), | |||
}, | |||
}) | |||
logger.debug(`Enviroment: ${process.env.name}`) | |||
logger.debug(`App Path: ${app.getAppPath()}`) | |||
logger.debug(`Exe Path: ${app.getPath('exe')}`) | |||
// catch errors | |||
process.on('uncaughtException', (err) => { | |||
@@ -74,9 +72,10 @@ class DreamApp { | |||
app.commandLine.appendSwitch('disable-renderer-backgrounding') | |||
// user settings. | |||
await settings.initialSetup() | |||
await settings.boot() | |||
if (settings.app ?.disableHardwareAcceleration) { | |||
// this may increase performance on some systems. | |||
if (settings.app?.disableHardwareAcceleration) { | |||
app.disableHardwareAcceleration() | |||
} | |||
} | |||
@@ -96,8 +95,12 @@ class DreamApp { | |||
* Prepare the application. | |||
*/ | |||
static async setup() { | |||
// https://github.com/sindresorhus/electron-util#enforcemacosapplocation-macos | |||
enforceMacOSAppLocation() | |||
if (process.platform === 'darwin') { | |||
const { enforceMacOSAppLocation } = require('electron-util') | |||
// https://github.com/sindresorhus/electron-util#enforcemacosapplocation-macos | |||
enforceMacOSAppLocation() | |||
} | |||
// application exit. | |||
app.on('will-quit', async (event) => { | |||
@@ -110,13 +113,15 @@ class DreamApp { | |||
app.exit() | |||
}) | |||
// windows closed, no more to do. | |||
// windows closed, exit. | |||
app.on('window-all-closed', () => { | |||
app.quit() | |||
}) | |||
app.on('web-contents-created', (e, contents) => { | |||
contents.on('will-navigate', (event, navigationUrl) => { | |||
const { URL } = require('url') | |||
const url = new URL(navigationUrl) | |||
const host = process.env.SERVER_HOST | |||
@@ -149,6 +154,8 @@ class DreamApp { | |||
}) | |||
}) | |||
const contextMenu = require('electron-context-menu') | |||
// allow save image option | |||
contextMenu({ | |||
showSaveImageAs: true, | |||
@@ -158,18 +165,25 @@ class DreamApp { | |||
await system.setup() | |||
// user settings. | |||
await settings.initialSetup() | |||
await settings.setup() | |||
// | |||
this.createDirs() | |||
if (process.env.name === 'development') { | |||
const address = await ngrok.connect() | |||
logger.debug(`Proxy for debugging: ${address}`) | |||
} | |||
} | |||
/** | |||
* | |||
*/ | |||
// eslint-disable-next-line no-empty-function | |||
static async shutdown() { | |||
if (process.env.name === 'development') { | |||
await ngrok.disconnect() | |||
} | |||
} | |||
/** | |||
@@ -185,11 +199,11 @@ class DreamApp { | |||
minWidth: 1200, | |||
minHeight: 700, | |||
frame: false, | |||
icon: join(config.rootDir, 'dist', 'icon.ico'), | |||
icon: resolve(config.rootDir, 'dist', 'icon.ico'), | |||
webPreferences: { | |||
nodeIntegration: true, | |||
nodeIntegrationInWorker: true, | |||
preload: join(app.getAppPath(), 'electron', 'dist', 'provider.js'), | |||
preload: resolve(app.getAppPath(), 'electron', 'dist', 'provider.js'), | |||
}, | |||
}) | |||
@@ -221,6 +235,8 @@ class DreamApp { | |||
static pollUi() { | |||
logger.debug(`Requesting status from the server: ${this.uiUrl}`) | |||
const http = require('http') | |||
http | |||
.get(this.uiUrl, (response) => { | |||
if (response.statusCode === 200) { | |||
@@ -244,7 +260,7 @@ class DreamApp { | |||
*/ | |||
static getUiUrl() { | |||
if (!config.dev) { | |||
return join(config.rootDir, 'dist', 'index.html') | |||
return resolve(config.rootDir, 'dist', 'index.html') | |||
} | |||
return `http://localhost:${config.server.port}` | |||
@@ -254,14 +270,18 @@ class DreamApp { | |||
* Create required directories. | |||
*/ | |||
static createDirs() { | |||
const modelsPath = join(settings.folders.models, 'Uncategorized') | |||
if (!existsSync(modelsPath)) { | |||
mkdirSync(modelsPath, { recursive: true }, | |||
(error) => { | |||
throw new AppError(`Models directory creation fail.`, { error }) | |||
}) | |||
} | |||
const dirs = [ | |||
resolve(settings.folders.models, 'Uncategorized'), | |||
settings.folders.masks, | |||
] | |||
dirs.forEach((dir) => { | |||
try { | |||
fs.ensureDirSync(dir) | |||
} catch (error) { | |||
throw new AppError(`Could not create the directory:\n${dir}`, { error }) | |||
} | |||
}) | |||
} | |||
} | |||
@@ -269,7 +289,7 @@ app.on('ready', async () => { | |||
try { | |||
await DreamApp.start() | |||
} catch (error) { | |||
throw new AppError(error, { title: `Failed to start correctly.`, fatal: true }) | |||
throw new AppError(error, { title: `Failed to start correctly.`, level: 'error' }) | |||
} | |||
}) | |||
@@ -8,11 +8,11 @@ | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { | |||
isError, isString, isObject, isArray, | |||
isError, isString, isObject, isArray, attempt, | |||
} from 'lodash' | |||
import { app, dialog } from 'electron' | |||
const logger = require('logplease').create('app-error:main') | |||
const logger = require('logplease').create('error:main') | |||
/** | |||
* @typedef {Object} ErrorOptions | |||
@@ -32,9 +32,8 @@ export class AppError extends Error { | |||
*/ | |||
options = { | |||
title: null, | |||
level: 'error', | |||
level: 'warn', | |||
error: null, | |||
fatal: false, | |||
quiet: false, | |||
} | |||
@@ -76,25 +75,24 @@ export class AppError extends Error { | |||
show() { | |||
dialog.showErrorBox( | |||
this.options.title || 'A problem has occurred.', | |||
this.message, | |||
`${this.message}\n\n<code>${this.options.error?.message}</code>`, | |||
) | |||
} | |||
handle() { | |||
const { | |||
level, quiet, fatal, error, | |||
level, quiet, error, | |||
} = this.options | |||
// logger | |||
logger[level](this.message, { | |||
error, | |||
}) | |||
attempt(() => { | |||
logger[level](this.message, { error }) | |||
if (!quiet) { | |||
this.show() | |||
} | |||
if (!quiet) { | |||
this.show() | |||
} | |||
}) | |||
if (fatal) { | |||
if (level === 'error') { | |||
app.quit() | |||
} | |||
} | |||
@@ -103,21 +101,21 @@ export class AppError extends Error { | |||
let appError = error | |||
if (!(error instanceof AppError)) { | |||
let reportError | |||
let exception | |||
if (isError(error)) { | |||
reportError = error | |||
exception = error | |||
} else if (isObject(error) || isArray(error)) { | |||
reportError = new Error(JSON.stringify(error)) | |||
exception = attempt(() => new Error(JSON.stringify(error))) | |||
} else { | |||
reportError = new Error(error) | |||
exception = new Error(error) | |||
} | |||
appError = new AppError(`The application has encountered an unexpected error:\n<code>${reportError?.message}</code>`, | |||
{ | |||
error: reportError, | |||
title: 'Unexpected error!', | |||
}) | |||
appError = new AppError(`The application has encountered an unexpected error.`, { | |||
error: exception, | |||
title: 'Unexpected error!', | |||
level: 'error', | |||
}) | |||
} | |||
appError.handle() |
@@ -0,0 +1,13 @@ | |||
// DreamTime. | |||
// Copyright (C) DreamNet. All rights reserved. | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU General Public License 3.0 as published by | |||
// the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html> | |||
// | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import * as ngrok from './ngrok' | |||
export { settings } from './settings' | |||
export { ngrok } |
@@ -0,0 +1,41 @@ | |||
// DreamTime. | |||
// Copyright (C) DreamNet. All rights reserved. | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU General Public License 3.0 as published by | |||
// the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html> | |||
// | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { isNil } from 'lodash' | |||
let address | |||
export async function connect() { | |||
if (process.env.name !== 'development') { | |||
return null | |||
} | |||
if (!isNil(address)) { | |||
return address | |||
} | |||
const ngrok = require('ngrok') | |||
if (process.env.NGROK_ACCESS_TOKEN) { | |||
await ngrok.authtoken(process.env.NGROK_ACCESS_TOKEN) | |||
} | |||
address = await ngrok.connect(process.env.SERVER_PORT) | |||
return address | |||
} | |||
export function disconnect() { | |||
const ngrok = require('ngrok') | |||
return ngrok.disconnect() | |||
} | |||
export function getAddress() { | |||
return address | |||
} |
@@ -92,7 +92,7 @@ export class BaseService { | |||
static make(obj) { | |||
if (!obj) { | |||
// eslint-disable-next-line no-param-reassign | |||
obj = new this() | |||
obj = new this | |||
} | |||
return makeServiceProxy(obj) |
@@ -11,7 +11,7 @@ import fs from 'fs-extra' | |||
import { | |||
round, cloneDeep, isNil, isEmpty, isPlainObject, get, set, | |||
} from 'lodash' | |||
import uuid from 'uuid' | |||
import { AppError } from './app-error' | |||
import { paths, system } from './tools' | |||
const logger = require('logplease').create('electron:scripts:services:settings') | |||
@@ -50,12 +50,12 @@ class Settings { | |||
return | |||
} | |||
if (!fs.existsSync(this.path)) { | |||
return | |||
try { | |||
this.payload = fs.readJsonSync(this.path) | |||
logger.debug('Settings:', this.payload) | |||
} catch (error) { | |||
console.error(error) | |||
} | |||
this.payload = fs.readJsonSync(this.path) | |||
logger.debug(this.payload) | |||
} | |||
/** | |||
@@ -63,7 +63,7 @@ class Settings { | |||
* This function is called automatically if you set a first level variable. | |||
*/ | |||
async save() { | |||
fs.writeJsonSync(this.path, this.payload) | |||
fs.writeJsonSync(this.path, this.payload, { spaces: 2 }) | |||
} | |||
/** | |||
@@ -102,23 +102,53 @@ class Settings { | |||
/** | |||
* | |||
*/ | |||
async initialSetup() { | |||
this._loadInitital() | |||
async boot() { | |||
this._loadDefault() | |||
await this.load() | |||
} | |||
_loadInitital() { | |||
/** | |||
* Load the default configuration (and the current version) | |||
*/ | |||
_loadDefault() { | |||
const hasGPU = system.graphics.length > 0 | |||
const cores = round(system.cores / 2) || 4 | |||
const cores = round(system.cores / 2) || 1 | |||
const uuid = require('uuid') | |||
this.payload = { | |||
version: 5, | |||
welcome: true, | |||
version: 6, | |||
user: uuid(), | |||
wizard: { | |||
welcome: false, | |||
tos: false, | |||
user: false, | |||
telemetry: false, | |||
}, | |||
app: { | |||
disableHardwareAcceleration: true, | |||
uploadMode: 'add-queue', | |||
uploadMode: 'none', | |||
}, | |||
notifications: { | |||
run: false, | |||
allRuns: true, | |||
update: true, | |||
}, | |||
folders: { | |||
cropped: paths.getPath('temp'), | |||
models: paths.getPath('pictures', 'DreamTime'), | |||
masks: paths.getPath('temp'), | |||
cli: paths.getPath('userData', 'dreampower'), | |||
}, | |||
telemetry: { | |||
bugs: true, | |||
dom: true, | |||
domPrivate: false, | |||
}, | |||
processing: { | |||
@@ -166,36 +196,19 @@ class Settings { | |||
}, | |||
advanced: { | |||
scaleMode: 'auto-rescale', | |||
scaleMode: 'auto-resize', | |||
transformMode: 'normal', | |||
useColorTransfer: false, | |||
useWaifu: false, | |||
}, | |||
}, | |||
notifications: { | |||
run: false, | |||
allRuns: true, | |||
update: true, | |||
}, | |||
folders: { | |||
cropped: paths.getPath('temp'), | |||
models: paths.getPath('userData', 'models'), | |||
masks: paths.getPath('temp'), | |||
cli: paths.getPath('userData', 'dreampower'), | |||
}, | |||
telemetry: { | |||
enabled: true, | |||
}, | |||
} | |||
this._default = cloneDeep(this.payload) | |||
} | |||
/** | |||
* Create the settings file if it does not exist | |||
* Create the settings file if it does not exist. | |||
*/ | |||
async _create() { | |||
if (fs.existsSync(this.path)) { | |||
@@ -205,13 +218,12 @@ class Settings { | |||
try { | |||
fs.outputFileSync(this.path, JSON.stringify(this._default, null, 2)) | |||
} catch (error) { | |||
throw new Error(`Settings creation fail. Please make sure the program has the necessary permissions to write to:\n${this.path}\n\n${error}`) | |||
throw new AppError(`Could not create settings file. Please make sure the program has the necessary permissions to write to:\n${this.path}`, { fatal: true, error }) | |||
} | |||
} | |||
/** | |||
* Check if it is necessary to update the settings file. | |||
* legacy code :WutFaceW: | |||
* Upgrade the settings file. | |||
*/ | |||
async _upgrade() { | |||
if (this.payload?.version === this._default.version) { | |||
@@ -222,7 +234,7 @@ class Settings { | |||
const currentSettings = cloneDeep(this.payload) | |||
// Upgrade 1 -> 2 | |||
// 1 -> 2 | |||
if (this.payload?.version === 1 && this._default.version >= 2) { | |||
this.payload.version = 2 | |||
this.payload.preferences = this._default.preferences | |||
@@ -243,7 +255,7 @@ class Settings { | |||
this.payload.preferences.pubicHair.size = pubicHairSize | |||
} | |||
// Upgrade 2 -> 3 | |||
// 2 -> 3 | |||
if (this.payload?.version === 2 && this._default.version >= 3) { | |||
const { processing, preferences } = currentSettings | |||
@@ -280,7 +292,7 @@ class Settings { | |||
} | |||
} | |||
// Upgrade 3 -> 4 | |||
// 3 -> 4 | |||
if (this.payload?.version === 3 && this._default.version >= 4) { | |||
this.payload.version = 4 | |||
this.payload.app = { | |||
@@ -289,6 +301,32 @@ class Settings { | |||
} | |||
} | |||
// 4 -> 5 | |||
if (this.payload?.version === 4 && this._default.version === 5) { | |||
this.payload.version = 5 | |||
this.payload.preferences.advanced.transformMode = 'normal' | |||
} | |||
// 5 -> 6 | |||
if (this.payload?.version === 5 && this._default.version === 6) { | |||
this.payload.version = 6 | |||
delete this.payload.welcome | |||
this.payload.wizard = { | |||
welcome: false, | |||
tos: false, | |||
user: false, | |||
telemetry: false, | |||
} | |||
this.payload.telemetry = { | |||
bugs: this.payload.enabled, | |||
dom: true, | |||
domPrivate: false, | |||
} | |||
} | |||
this.save() | |||
} | |||
} | |||
@@ -312,7 +350,6 @@ export function make(obj) { | |||
return undefined | |||
}, | |||
/* eslint-disable no-param-reassign */ | |||
set: (obj, prop, value) => { | |||
if (!isNil(obj.payload)) { | |||
if (prop in obj.payload) { | |||
@@ -326,7 +363,6 @@ export function make(obj) { | |||
obj[prop] = value | |||
return true | |||
}, | |||
/* eslint-enable no-param-reassign */ | |||
}) | |||
} | |||
@@ -5,13 +5,8 @@ import { | |||
createWriteStream, createReadStream, | |||
} from 'fs-extra' | |||
import { app, dialog } from 'electron' | |||
import { is, platform } from 'electron-util' | |||
import EventBus from 'js-event-bus' | |||
import axios from 'axios' | |||
import unzipper from 'unzipper' | |||
import deferred from 'deferred' | |||
import sevenBin from '7zip-bin' | |||
import { extractFull } from 'node-7z' | |||
import { getAppResourcesPath } from './paths' | |||
import { AppError } from '../app-error' | |||
@@ -59,6 +54,8 @@ export function writeDataURL(path, dataURL) { | |||
* @param {string} destinationPath | |||
*/ | |||
export function extractZip(path, destinationPath) { | |||
const unzipper = require('unzipper') | |||
const def = deferred() | |||
const stream = createReadStream(path).pipe(unzipper.Extract({ path: destinationPath })) | |||
@@ -80,11 +77,15 @@ export function extractZip(path, destinationPath) { | |||
* @param {string} destinationPath | |||
*/ | |||
export function extractSeven(path, destinationPath) { | |||
const { is, platform } = require('electron-util') | |||
const { extractFull } = require('node-7z') | |||
const def = deferred() | |||
let pathTo7zip | |||
if (is.development) { | |||
const sevenBin = require('7zip-bin') | |||
pathTo7zip = sevenBin.path7za | |||
} else { | |||
const binName = platform({ | |||
@@ -118,7 +119,8 @@ export function extractSeven(path, destinationPath) { | |||
* @param {Object} [options] | |||
*/ | |||
export function download(url, options = {}) { | |||
const bus = new EventBus() | |||
const EventBus = require('js-event-bus') | |||
const bus = new EventBus | |||
// eslint-disable-next-line no-param-reassign | |||
options = { |
@@ -4,12 +4,14 @@ const { make } = require('./modules/settings') | |||
const util = remote.require('electron-util') | |||
const { settingsRaw } = remote.require('./modules/settings') | |||
const tools = remote.require('./modules/tools') | |||
const ngrok = remote.require('./modules/ngrok') | |||
// tools provider | |||
window.$provider = { | |||
...tools, | |||
settings: make(settingsRaw), | |||
ngrok, | |||
api: util.api, | |||
util, |
@@ -16,11 +16,11 @@ | |||
<script> | |||
export default { | |||
middleware: ['checks'], | |||
middleware: ['wizard'], | |||
} | |||
</script> | |||
<style lang="scss"> | |||
<style lang="scss" scoped> | |||
.layout { | |||
@apply h-full; | |||
@@ -0,0 +1,51 @@ | |||
<template> | |||
<div class="layout"> | |||
<layout-topbar /> | |||
<div id="layout-content" class="layout__content"> | |||
<nuxt /> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.layout { | |||
@apply h-full; | |||
display: grid; | |||
grid-template-columns: 100%; | |||
grid-template-rows: 30px 1fr; | |||
grid-template-areas: "topbar" "content"; | |||
.layout__topbar { | |||
grid-area: topbar; | |||
} | |||
.layout__content { | |||
@apply relative overflow-hidden overflow-y-auto; | |||
@apply p-6; | |||
grid-area: content; | |||
height: calc(100vh - 30px); | |||
} | |||
} | |||
</style> | |||
<style lang="scss"> | |||
.layout__header { | |||
@apply flex justify-center items-center; | |||
@apply text-3xl font-semibold mb-6; | |||
height: 60px; | |||
h1 { | |||
@apply text-xl text-white; | |||
} | |||
} | |||
</style> |
@@ -9,23 +9,14 @@ | |||
import { requirements } from '~/modules/system' | |||
const { system, settings } = $provider | |||
/** | |||
* Detects if the user has what it takes to run the program, | |||
* otherwise redirects him to the appropriate page. | |||
*/ | |||
export default function ({ route, redirect }) { | |||
/* | |||
window.$redirect = redirect | |||
if (settings.welcome) { | |||
// First time execution! | |||
if (route.path !== '/welcome') { | |||
redirect('/welcome') | |||
} | |||
return | |||
} | |||
if (!requirements.power.installed || !requirements.power.compatible) { | |||
// DreamPower is missing | |||
@@ -45,4 +36,5 @@ export default function ({ route, redirect }) { | |||
redirect('/about#checkpoints') | |||
} | |||
} | |||
*/ | |||
} |
@@ -0,0 +1,70 @@ | |||
// DreamTime. | |||
// Copyright (C) DreamNet. All rights reserved. | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU General Public License 3.0 as published by | |||
// the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html> | |||
// | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { requirements } from '~/modules/system' | |||
const { wizard } = $provider.settings | |||
export default function ({ route, redirect }) { | |||
window.$redirect = redirect | |||
if (!wizard.welcome) { | |||
if (route.path !== '/wizard/welcome') { | |||
redirect('/wizard/welcome') | |||
} | |||
return | |||
} | |||
if (!wizard.tos) { | |||
if (route.path !== '/wizard/tos') { | |||
redirect('/wizard/tos') | |||
} | |||
return | |||
} | |||
if (!requirements.power.installed) { | |||
if (route.path !== '/wizard/power') { | |||
redirect('/wizard/power') | |||
} | |||
return | |||
} | |||
if (!requirements.power.checkpoints) { | |||
if (route.path !== '/wizard/checkpoints') { | |||
redirect('/wizard/checkpoints') | |||
} | |||
return | |||
} | |||
if (!wizard.telemetry) { | |||
if (route.path !== '/wizard/telemetry') { | |||
redirect('/wizard/telemetry') | |||
} | |||
return | |||
} | |||
if (!wizard.user) { | |||
if (route.path !== '/wizard/user') { | |||
redirect('/wizard/user') | |||
} | |||
return | |||
} | |||
if (!wizard.telemetry) { | |||
if (route.path !== '/wizard/telemetry') { | |||
redirect('/wizard/telemetry') | |||
} | |||
} | |||
} |
@@ -8,12 +8,13 @@ | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { | |||
isError, isString, isObject, isArray, pick, | |||
isError, isString, isObject, isArray, attempt, | |||
} from 'lodash' | |||
import { mapStackTrace } from 'sourcemapped-stacktrace' | |||
import Swal from 'sweetalert2' | |||
import { logrocket } from '~/modules/services' | |||
import { logrocket, rollbar } from '~/modules/services' | |||
const logger = require('logplease').create('app-error:renderer') | |||
const logger = require('logplease').create('error:renderer') | |||
const { app } = $provider.api | |||
@@ -32,6 +33,7 @@ export class AppError extends Error { | |||
*/ | |||
options = { | |||
title: null, | |||
message: null, | |||
level: 'error', | |||
error: null, | |||
fatal: false, | |||
@@ -48,22 +50,25 @@ export class AppError extends Error { | |||
* @param {string} message | |||
* @param {ErrorOptions} options | |||
*/ | |||
constructor(input, options = {}) { | |||
if (isString(input)) { | |||
super(input) | |||
} else if (isError(input)) { | |||
super(input.message) | |||
constructor(message, options = {}) { | |||
if (isError(message)) { | |||
// that's better. | |||
options.error = message | |||
message = message.message | |||
} | |||
this.stack = input.stack | |||
const { error } = options | |||
this.options.error = input | |||
if (isError(error)) { | |||
// we want this error to be the closest to the original | |||
super(error.message) | |||
if (input.options) { | |||
this.options = { | |||
...this.options, | |||
...input.options, | |||
} | |||
if (error.options) { | |||
// inherit error options. | |||
this.options = error.options | |||
} | |||
} else if (isString(message)) { | |||
super(message) | |||
} else { | |||
super() | |||
} | |||
@@ -71,42 +76,81 @@ export class AppError extends Error { | |||
this.options = { | |||
...this.options, | |||
...options, | |||
message, | |||
} | |||
if (this.options.level === 'warning') { | |||
// warning does not exist in logger. | |||
this.options.level = 'warn' | |||
} | |||
} | |||
report() { | |||
/* | |||
if (process.env.NODE_ENV === 'development') { | |||
this.reportUrl = `https://rollbar.com/occurrence/uuid/?uuid={EXAMPLE}` | |||
/** | |||
* Copy the original error information. | |||
*/ | |||
async copyError() { | |||
const { error } = this.options | |||
if (!isError(error)) { | |||
return | |||
} | |||
*/ | |||
const { level } = this.options | |||
// transform the original stack to the source-map stack. | |||
const getStack = () => new Promise((resolve) => { | |||
mapStackTrace(error.stack, (stack) => { | |||
resolve(`${error.message}\n${stack.join('\n')}`) | |||
}, { cacheGlobally: true }) | |||
}) | |||
if (!logrocket.enabled || level !== 'error') { | |||
return | |||
} | |||
// copy pasta | |||
this.name = error.name | |||
this.stack = await getStack() | |||
} | |||
try { | |||
const error = this.options.error || this | |||
/** | |||
* Report the error to the logger, bug and session tracking services. | |||
*/ | |||
report() { | |||
const { level, error } = this.options | |||
let rollbarResponse | |||
console.log(logrocket) | |||
// logger. | |||
logger[level](this) | |||
logrocket.captureException(error, { | |||
extra: this.options, | |||
}) | |||
// bug tracking. | |||
if (rollbar.enabled && level === 'error') { | |||
try { | |||
rollbarResponse = rollbar[level](this, { | |||
...this.options, | |||
sessionURL: logrocket.sessionURL, | |||
}) | |||
this.reported = true | |||
} catch (err) { | |||
logger.warn('Rollbar report fail!', err) | |||
} | |||
} | |||
// session tracking. | |||
if (logrocket.enabled && level === 'error') { | |||
try { | |||
logrocket.captureException(error || this, { | |||
extra: { | |||
...this.options, | |||
rollbarURL: `https://rollbar.com/occurrence/uuid/?uuid=${rollbarResponse?.uuid}`, | |||
}, | |||
}) | |||
this.reported = true | |||
} catch (err) { | |||
logger.warn('LogRocket report fail!', err) | |||
this.reported = true | |||
} catch (err) { | |||
logger.warn('LogRocket report fail!', err) | |||
} | |||
} | |||
} | |||
/** | |||
* Show the error to the user. | |||
*/ | |||
show() { | |||
let icon = 'error' | |||
@@ -120,52 +164,54 @@ export class AppError extends Error { | |||
Swal.fire({ | |||
title: this.options.title, | |||
html: this.message, | |||
html: `${this.options.message}<br><br><pre>${this.message}</pre>`, | |||
icon, | |||
footer: this.reported ? `<code>This problem has been reported to the developers.</code>` : null, | |||
footer: this.reported ? `<code>🐞 This problem has been reported to DreamNet.<br>It will be fixed as soon as possible.</code>` : null, | |||
}) | |||
} | |||
handle() { | |||
const { | |||
level, quiet, fatal, error, | |||
} = this.options | |||
/** | |||
* | |||
*/ | |||
async handle() { | |||
const { quiet, fatal, error } = this.options | |||
// logger | |||
logger[level](this.message, { | |||
error, | |||
}) | |||
await this.copyError(error) | |||
this.report() | |||
attempt(() => { | |||
this.report() | |||
if (!quiet) { | |||
this.show() | |||
} | |||
if (!quiet) { | |||
this.show() | |||
} | |||
}) | |||
if (fatal) { | |||
app.quit() | |||
} | |||
} | |||
/** | |||
* | |||
*/ | |||
static handle(error) { | |||
let appError = error | |||
if (!(error instanceof AppError)) { | |||
let reportError | |||
let exception | |||
if (isError(error)) { | |||
reportError = error | |||
exception = error | |||
} else if (isObject(error) || isArray(error)) { | |||
reportError = new Error(JSON.stringify(error)) | |||
exception = new Error(JSON.stringify(error)) | |||
} else { | |||
reportError = new Error(error) | |||
exception = new Error(error) | |||
} | |||
appError = new AppError(`The application has encountered an unexpected error:\n<pre>${reportError?.message}</pre>`, | |||
{ | |||
error: reportError, | |||
title: 'Unexpected error!', | |||
}) | |||
appError = new AppError(`Woah! An error has occurred and we do not know why.<br>Please try again.`, { | |||
error: exception, | |||
title: 'Unexpected error!', | |||
}) | |||
} | |||
appError.handle() |
@@ -9,4 +9,4 @@ | |||
import EventBus from 'js-event-bus' | |||
export const events = new EventBus() | |||
export const events = new EventBus |
@@ -36,7 +36,7 @@ export class File { | |||
* @param {*} filepath | |||
*/ | |||
static fromPath(filepath) { | |||
const file = new this() | |||
const file = new this | |||
return file.open(filepath) | |||
} | |||
@@ -48,7 +48,7 @@ export class File { | |||
directory: getPath('temp'), | |||
}) | |||
const file = new this() | |||
const file = new this | |||
await file.open(filepath) | |||
return file | |||
@@ -58,7 +58,7 @@ export class File { | |||
* | |||
*/ | |||
static fromMetadata(metadata) { | |||
const file = new this() | |||
const file = new this | |||
return file.setMetadata(metadata) | |||
} | |||
@@ -83,7 +83,7 @@ export class Nudify { | |||
afterProcessDelay: 500, | |||
batchSize: 1, | |||
concurrent: 1, | |||
store: new MemoryStore(), | |||
store: new MemoryStore, | |||
}) | |||
this.queue.on('task_queued', (photoId, photo) => { |
@@ -67,7 +67,7 @@ export class PhotoRun { | |||
/** | |||
* @type {Timer} | |||
*/ | |||
timer = new Timer() | |||
timer = new Timer | |||
/** | |||
* @type {Object} | |||
@@ -130,7 +130,7 @@ export class PhotoRun { | |||
this.status = 'pending' | |||
this.failed = false | |||
this.timer = new Timer() | |||
this.timer = new Timer | |||
} | |||
toObject() { |
@@ -47,7 +47,7 @@ export class Photo { | |||
/** | |||
* @type {EventBus} | |||
*/ | |||
events = new EventBus() | |||
events = new EventBus | |||
/** | |||
* @type {string} | |||
@@ -86,7 +86,7 @@ export class Photo { | |||
/** | |||
* @type {Timer} | |||
*/ | |||
timer = new Timer() | |||
timer = new Timer | |||
/** | |||
* @type {require('cropperjs').default} | |||
@@ -309,7 +309,7 @@ export class Photo { | |||
afterProcessDelay: 500, | |||
batchSize: 1, | |||
concurrent: 1, | |||
store: new MemoryStore(), | |||
store: new MemoryStore, | |||
}) | |||
this.queue.on('drain', () => { | |||
@@ -356,7 +356,7 @@ export class Photo { | |||
reset() { | |||
this.status = 'pending' | |||
this.timer = new Timer() | |||
this.timer = new Timer | |||
this.runs = [] | |||
} |
@@ -36,7 +36,7 @@ export class BaseService { | |||
* @return {BaseService} | |||
*/ | |||
static make() { | |||
return new Proxy(new this(), { | |||
return new Proxy(new this, { | |||
get: (obj, prop) => { | |||
if (prop in obj) { | |||
return obj[prop] |
@@ -9,3 +9,4 @@ | |||
export { nucleus } from './nucleus' | |||
export { logrocket } from './logrocket' | |||
export { rollbar } from './rollbar' |
@@ -7,15 +7,22 @@ | |||
// | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { isString, get } from 'lodash' | |||
import { isString, endsWith } from 'lodash' | |||
import LogRocket from 'logrocket' | |||
import { BaseService } from './base' | |||
import { nucleus } from './nucleus' | |||
const { settings, system } = $provider | |||
const { telemetry } = settings | |||
const logger = require('logplease').create('services:logrocket') | |||
const privateExtensions = ['.jpg', '.jpeg', '.png', '.gif'] | |||
/** | |||
* https://logrocket.com/ | |||
* Session tracking. | |||
*/ | |||
class LogRocketService extends BaseService { | |||
/** | |||
* @type {string} | |||
@@ -31,6 +38,9 @@ class LogRocketService extends BaseService { | |||
return isString(this.accessToken) | |||
} | |||
/** | |||
* @type {string} | |||
*/ | |||
get release() { | |||
return process.env.GITHUB_SHA || process.env.npm_package_version | |||
} | |||
@@ -42,9 +52,26 @@ class LogRocketService extends BaseService { | |||
return { | |||
release: this.release, | |||
shouldCaptureIP: false, | |||
/*dom: { | |||
baseHref: nucleus.urls?.internal?.cdn || '', | |||
}, */ | |||
network: { | |||
requestSanitizer(request) { | |||
if (!telemetry.domPrivate) { | |||
// the user does not want to send private dom. | |||
privateExtensions.forEach((extension) => { | |||
if (endsWith(request.url.toLowerCase(), extension)) { | |||
// scrub web address photo. | |||
request.url = '[private-photo]' | |||
} | |||
}) | |||
} | |||
}, | |||
responseSanitizer(request) { | |||
console.log(request) | |||
}, | |||
}, | |||
dom: { | |||
isEnabled: telemetry.dom, | |||
baseHref: $provider.ngrok.getAddress() || nucleus.urls?.internal?.cdn || null, | |||
}, | |||
} | |||
} | |||
@@ -54,10 +81,9 @@ class LogRocketService extends BaseService { | |||
} | |||
try { | |||
LogRocket.init(this.accessToken) | |||
LogRocket.init(this.accessToken, this.config) | |||
LogRocket.identify(settings.user || 'unknown', { | |||
settings: settings.payload, | |||
}) | |||
this.service = LogRocket |
@@ -8,27 +8,28 @@ | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { | |||
isNil, isString, get, | |||
isNil, isString, | |||
} from 'lodash' | |||
import { execSync } from 'child_process' | |||
import Rollbar from 'rollbar' | |||
import { remote } from 'electron' | |||
import { BaseService } from './base' | |||
import { settings } from './settings' | |||
import { nucleus } from './nucleus' | |||
import { system } from '../tools/system' | |||
const { settings, system } = $provider | |||
const { execSync } = remote.require('child_process') | |||
const logger = require('logplease').create('services:rollbar') | |||
/** | |||
* https://rollbar.com | |||
* Bug tracking service. | |||
* Bug tracking. | |||
*/ | |||
class RollbarService extends BaseService { | |||
/** | |||
* @type {string} | |||
*/ | |||
get accessToken() { | |||
return process.env.ROLLBAR_ACCESS_TOKEN || get(nucleus, 'keys.rollbar') | |||
return process.env.ROLLBAR_ACCESS_TOKEN || nucleus.keys?.rollbar | |||
} | |||
/** | |||
@@ -41,7 +42,7 @@ class RollbarService extends BaseService { | |||
/** | |||
* @type {string} | |||
*/ | |||
get codeVersion() { | |||
get release() { | |||
try { | |||
return process.env.GITHUB_SHA || execSync('git rev-parse HEAD').toString().trim() | |||
} catch (err) { | |||
@@ -58,20 +59,24 @@ class RollbarService extends BaseService { | |||
captureUncaught: false, | |||
captureUnhandledRejections: false, | |||
captureIp: 'anonymize', | |||
enabled: settings.telemetry.enabled, | |||
verbose: process.env.NODE_ENV === 'development', | |||
enabled: settings.telemetry.bugs, | |||
verbose: process.env.name === 'development', | |||
logLevel: 'info', | |||
nodeSourceMaps: true, | |||
reportLevel: 'error', | |||
reportLevel: 'warning', | |||
payload: { | |||
environment: process.env.NODE_ENV, | |||
environment: process.env.name, | |||
person: { | |||
id: settings.user, | |||
}, | |||
server: { | |||
root: 'webpack:///', | |||
}, | |||
client: { | |||
javascript: { | |||
source_map_enabled: true, | |||
code_version: this.codeVersion, | |||
guess_uncaught_frames: true, | |||
code_version: this.release, | |||
}, | |||
}, | |||
settings: settings.payload, | |||
@@ -93,10 +98,10 @@ class RollbarService extends BaseService { | |||
} | |||
try { | |||
this._service = new Rollbar(this.config) | |||
this.service = new Rollbar(this.config) | |||
this.enabled = true | |||
logger.info('Rollbar enabled!') | |||
logger.info('Rollbar started!') | |||
logger.debug(this.accessToken) | |||
} catch (err) { | |||
logger.warn('Rollbar setup failed!', err) |
@@ -7,16 +7,16 @@ | |||
// | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { isNil, isString, toInteger } from 'lodash' | |||
import { isNil, startsWith } from 'lodash' | |||
import { remote } from 'electron' | |||
import { nucleus } from '../services' | |||
const logger = require('logplease').create('app:system:requirements') | |||
const { system, fs } = $provider | |||
const { is } = $provider.util | |||
const { remote } = $provider.api | |||
const { getVersion, isInstalled } = $provider.power | |||
const { getAppResourcesPath, getPowerPath, getCheckpointsPath } = $provider.paths | |||
const { getAppResourcesPath, getCheckpointsPath } = $provider.paths | |||
export const requirements = { | |||
power: { | |||
@@ -74,9 +74,10 @@ export const requirements = { | |||
} | |||
const compareVersions = require('compare-versions') | |||
let version | |||
try { | |||
const version = await getVersion() | |||
version = await getVersion() | |||
const currentVersion = process.env.npm_package_version | |||
const minimum = nucleus.v1?.projects?.dreamtime?.releases[`v${currentVersion}`]?.dreampower?.minimum || 'v0.0.1' | |||
@@ -92,7 +93,7 @@ export const requirements = { | |||
return true | |||
} catch (err) { | |||
logger.warn('An error occurred while verifying the version of DreamPower.', err) | |||
logger.warn(`DreamPower version verification failed. (${version}).`, err) | |||
return false | |||
} | |||
}, | |||
@@ -140,8 +141,8 @@ export const requirements = { | |||
const version = system.os.release | |||
if (toInteger(version) < 10) { | |||
// no windows 10 | |||
if (!startsWith(version, '10')) { | |||
// no windows 10. | |||
return true | |||
} | |||
@@ -68,4 +68,4 @@ class DreamTimeUpdater extends BaseUpdater { | |||
} | |||
} | |||
export const dreamtime = new DreamTimeUpdater() | |||
export const dreamtime = new DreamTimeUpdater |
@@ -32,9 +32,70 @@ module.exports = { | |||
meta: [ | |||
{ charset: 'utf-8' }, | |||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }, | |||
// { 'http-equiv': 'Content-Security-Policy', content: 'default-src \'self\'; script-src \'self\' \'unsafe-inline\' https://cdn.logrocket.io https://cdn.lr-ingest.io; worker-src \'self\' \'unsafe-inline\' data: blob:; object-src \'none\'; style-src \'self\' \'unsafe-inline\' https://fonts.googleapis.com; img-src \'self\' data:; media-src \'self\' data:; frame-src \'self\' https://*.dreamnet.tech; font-src *; connect-src \'self\' http://localhost:* https://*.dreamnet.tech wss://app.nucleus.sh https://nucleus.sh https://*.logrocket.io https://r.lr-ingest.io https://*.github.com' }, | |||
], | |||
}, | |||
/** | |||
* | |||
*/ | |||
render: { | |||
csp: { | |||
hashAlgorithm: 'sha256', | |||
policies: { | |||
'default-src': [ | |||
'self', | |||
], | |||
'script-src': [ | |||
'self', | |||
'unsafe-inline', | |||
'https://cdn.logrocket.io', | |||
'https://cdn.lr-ingest.io', | |||
], | |||
'worker-src': [ | |||
'self', | |||
'unsafe-inline', | |||
'data:', | |||
'blob:', | |||
], | |||
'object-src': [ | |||
'none', | |||
], | |||
'style-src': [ | |||
'self', | |||
'unsafe-inline', | |||
'https://fonts.googleapis.com', | |||
], | |||
'img-src': [ | |||
'self', | |||
'data:', | |||
], | |||
'media-src': [ | |||
'self', | |||
'data:', | |||
], | |||
'frame-src': [ | |||
'self', | |||
'https://*.dreamnet.tech', | |||
], | |||
'font-src': [ | |||
'*', | |||
], | |||
'connect-src': [ | |||
'self', | |||
'http://localhost:*', | |||
'https://*.dreamnet.tech', | |||
'wss://app.nucleus.sh', | |||
'https://nucleus.sh', | |||
'https://*.logrocket.io', | |||
'https://r.lr-ingest.io', | |||
'https://*.github.com', | |||
], | |||
}, | |||
addMeta: true, | |||
}, | |||
}, | |||
/* | |||
** Customize the progress-bar color | |||
*/ | |||
@@ -48,14 +109,23 @@ module.exports = { | |||
'cropperjs/dist/cropper.css', | |||
'tui-image-editor/dist/tui-image-editor.css', | |||
'tui-color-picker/dist/tui-color-picker.css', | |||
'~/assets/css/tailwind.scss', | |||
'~/assets/css/reset.scss', | |||
'~/assets/css/components/_all.scss', | |||
'~/assets/css/utilities/_all.scss', | |||
'~/assets/css/fonts.scss', | |||
], | |||
/* | |||
** Plugins to load before mounting the App | |||
*/ | |||
plugins: ['~/plugins/boot.js', '~/plugins/setup.js', '~/plugins/fontawesome.js', '~/components'], | |||
plugins: [ | |||
'~/plugins/boot.js', | |||
'~/plugins/setup.js', | |||
'~/plugins/fontawesome.js', | |||
'~/components', | |||
], | |||
/* | |||
** Nuxt.js dev-modules | |||
@@ -63,6 +133,8 @@ module.exports = { | |||
buildModules: [ | |||
// Doc: https://github.com/nuxt-community/eslint-module | |||
'@nuxtjs/eslint-module', | |||
// Doc: https://github.com/Developmint/nuxt-purgecss | |||
'nuxt-purgecss', | |||
// Doc: https://github.com/nuxt-community/nuxt-tailwindcss | |||
'@nuxtjs/tailwindcss', | |||
], | |||
@@ -83,7 +155,8 @@ module.exports = { | |||
* | |||
*/ | |||
purgeCSS: { | |||
whitelistPatterns: [/tippy/, /cropper/, /tui/, /color-picker/], | |||
enabled: !dev, | |||
whitelistPatterns: [/tippy/, /cropper/, /tui/, /color-picker/, /swal2/, /text-/, /nuxt/, /pre/, /svg/], | |||
}, | |||
/** | |||
@@ -104,11 +177,11 @@ module.exports = { | |||
build: { | |||
parallel: true, | |||
hardSource: dev, | |||
hardSource: false, | |||
cache: dev, | |||
cache: false, | |||
extractCSS: !dev, | |||
extractCSS: true, | |||
/** | |||
* | |||
@@ -154,11 +227,14 @@ module.exports = { | |||
*/ | |||
optimization: { | |||
splitChunks: { | |||
// minSize: 30000, | |||
// maxSize: 3000000, | |||
cacheGroups: { | |||
commons: { | |||
vendors: { | |||
test: /[\\/]node_modules[\\/]/, | |||
name: 'vendors', | |||
chunks: 'all', | |||
reuseExistingChunk: true, | |||
}, | |||
}, | |||
}, | |||
@@ -168,6 +244,8 @@ module.exports = { | |||
** You can extend webpack config here | |||
*/ | |||
extend(config, { isDev }) { | |||
const webpack = require('webpack') | |||
config.target = 'electron-renderer' | |||
config.module.rules.push({ | |||
@@ -176,15 +254,13 @@ module.exports = { | |||
exclude: /(node_modules)/, | |||
}) | |||
// eslint-disable-next-line no-useless-escape | |||
config.plugins.push(new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/)) | |||
if (isDev) { | |||
config.devtool = 'source-map' | |||
config.devtool = 'inline-source-map' | |||
} else { | |||
config.output.publicPath = './_nuxt/' | |||
const webpack = require('webpack') | |||
// eslint-disable-next-line no-useless-escape | |||
config.plugins.push(new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/)) | |||
} | |||
}, | |||
}, |
@@ -1,155 +0,0 @@ | |||
{ | |||
"name": "dreamtime", | |||
"displayName": "DreamTime", | |||
"description": "DreamTime allows you to nudify photos of people.", | |||
"author": "DreamNet", | |||
"homepage": "https://time.dreamnet.tech", | |||
"version": "1.2.0", | |||
"main": "electron/dist/index.js", | |||
"license": "GPL-3.0-only", | |||
"private": true, | |||
"repository": { | |||
"type": "git", | |||
"url": "git+https://github.com/dreamnettech/dreamtime.git" | |||
}, | |||
"bugs": { | |||
"url": "https://github.com/dreamnettech/dreamtime/issues" | |||
}, | |||
"scripts": { | |||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .", | |||
"development": "env-cmd -e default,development --no-override", | |||
"production": "env-cmd -e default,production --no-override", | |||
"start:nuxt": "yarn development nuxt", | |||
"start:babel": "yarn development babel electron/src --out-dir electron/dist --source-maps --watch --verbose", | |||
"start:electron": "yarn development electron .", | |||
"build:nuxt": "yarn production nuxt build", | |||
"build:babel": "yarn production babel electron/src --out-dir electron/dist --minified", | |||
"build:electron": "yarn production electron-builder --publish=never --x64", | |||
"build": "yarn build:nuxt && yarn build:babel && yarn build:electron", | |||
"preview:electron": "env-cmd -e default,production,preview --no-override electron .", | |||
"preview": "yarn build:nuxt && yarn build:babel && yarn preview:electron" | |||
}, | |||
"lint-staged": { | |||
"*.{js,vue}": "eslint" | |||
}, | |||
"husky": { | |||
"hooks": { | |||
"pre-commit": "lint-staged" | |||
} | |||
}, | |||
"engines": { | |||
"node": ">=10.0.0" | |||
}, | |||
"os": [ | |||
"win32", | |||
"darwin", | |||
"linux" | |||
], | |||
"cpu": [ | |||
"x64" | |||
], | |||
"dependencies": { | |||
"7zip-bin": "^5.0.3", | |||
"@fortawesome/fontawesome-svg-core": "^1.2.25", | |||
"@fortawesome/free-brands-svg-icons": "^5.11.2", | |||
"@fortawesome/free-regular-svg-icons": "^5.11.2", | |||
"@fortawesome/free-solid-svg-icons": "^5.11.2", | |||
"@fortawesome/vue-fontawesome": "^0.1.8", | |||
"@nuxtjs/dotenv": "^1.4.1", | |||
"@nuxtjs/pwa": "^2.6.0", | |||
"axios": "^0.19.0", | |||
"better-queue": "^3.8.10", | |||
"better-queue-memory": "^1.0.4", | |||
"clipboard": "^2.0.4", | |||
"compare-versions": "^3.5.1", | |||
"cropperjs": "^1.5.6", | |||
"cryptr": "^6.0.1", | |||
"debug": "^4.1.1", | |||
"deferred": "^0.7.11", | |||
"delay": "^4.3.0", | |||
"electron-context-menu": "^0.15.1", | |||
"electron-util": "^0.13.0", | |||
"filesize": "^6.0.1", | |||
"form-data": "^3.0.0", | |||
"fs-extra": "^8.1.0", | |||
"gpu-info": "^0.0.1", | |||
"gsap": "^3.0.1", | |||
"image-js": "^0.21.8", | |||
"instagram-save": "^1.3.2", | |||
"is-online": "^8.2.0", | |||
"izitoast": "^1.4.0", | |||
"js-event-bus": "^1.0.0", | |||
"lodash": "^4.17.15", | |||
"logplease": "^1.2.15", | |||
"markdown": "^0.5.0", | |||
"md5": "^2.2.1", | |||
"md5-file": "^4.0.0", | |||
"mime-types": "^2.1.25", | |||
"moment": "^2.24.0", | |||
"node-7z": "^2.0.3", | |||
"node-graceful-shutdown": "^1.0.3", | |||
"nucleus-nodejs": "^3.0.1", | |||
"nuxt": "^2.10.2", | |||
"p-queue": "^6.2.1", | |||
"patch-package": "^6.2.0", | |||
"popmotion": "^8.7.1", | |||
"postinstall-postinstall": "^2.0.0", | |||
"randomcolor": "^0.5.4", | |||
"randomstring": "^1.1.5", | |||
"raw-loader": "^3.1.0", | |||
"regedit": "^3.0.3", | |||
"rollbar": "^2.14.4", | |||
"semver-regex": "^3.1.0", | |||
"supports-color": "^7.1.0", | |||
"sweetalert2": "^9.4.0", | |||
"systeminformation": "^4.15.3", | |||
"tippy.js": "^5.1.1", | |||
"unzipper": "^0.10.5", | |||
"uuid": "^3.3.3", | |||
"webpack-node-externals": "^1.7.2" | |||
}, | |||
"devDependencies": { | |||
"electron": "^7.1.1", | |||
"@babel/cli": "^7.7.0", | |||
"@babel/core": "^7.7.2", | |||
"@babel/plugin-proposal-class-properties": "^7.7.0", | |||
"@babel/plugin-proposal-export-default-from": "^7.5.2", | |||
"@babel/plugin-proposal-optional-chaining": "^7.6.0", | |||
"@nuxtjs/eslint-config": "^1.1.2", | |||
"@nuxtjs/eslint-module": "^1.1.0", | |||
"@nuxtjs/tailwindcss": "^1.2.0", | |||
"@octokit/rest": "^16.35.0", | |||
"babel-eslint": "^10.0.3", | |||
"babel-plugin-module-resolver": "^3.2.0", | |||
"babel-plugin-transform-inline-environment-variables": "^0.4.3", | |||
"babel-watch": "^7.0.0", | |||
"cross-env": "^6.0.3", | |||
"delay-cli": "^1.1.0", | |||
"electron-builder": "^22.1.0", | |||
"electron-devtools-installer": "^2.2.4", | |||
"electron-rebuild": "^1.8.6", | |||
"env-cmd": "^10.0.1", | |||
"eslint": "^6.6.0", | |||
"eslint-config-airbnb-base": "^14.0.0", | |||
"eslint-config-standard": ">=14.1.0", | |||
"eslint-import-resolver-nuxt": "^0.1.5", | |||
"eslint-plugin-import": ">=2.18.2", | |||
"eslint-plugin-jest": ">=23.0.4", | |||
"eslint-plugin-lodash": "^6.0.0", | |||
"eslint-plugin-node": ">=10.0.0", | |||
"eslint-plugin-nuxt": ">=0.5.0", | |||
"eslint-plugin-promise": ">=4.2.1", | |||
"eslint-plugin-standard": ">=4.0.1", | |||
"eslint-plugin-vue": "^6.0.1", | |||
"husky": "^3.0.9", | |||
"lint-staged": "^9.4.3", | |||
"node-sass": "^4.13.0", | |||
"nodemon": "^1.19.4", | |||
"nuxtjs-electron": "^0.1.10", | |||
"rollbar-sourcemap-webpack-plugin": "^2.5.1", | |||
"sass-loader": "^8.0.0", | |||
"tailwindcss": "^1.1.3", | |||
"tailwindcss-alpha": "hacknug/tailwindcss-alpha#feature/tests", | |||
"webpack-cli": "^3.3.10" | |||
} | |||
} |
@@ -4,7 +4,7 @@ | |||
"description": "DreamTime allows you to nudify photos of people.", | |||
"author": "DreamNet", | |||
"homepage": "https://time.dreamnet.tech", | |||
"version": "1.3.0", | |||
"version": "1.3.1", | |||
"main": "electron/dist/index.js", | |||
"license": "GPL-3.0-only", | |||
"private": true, | |||
@@ -93,6 +93,7 @@ | |||
"regedit": "^3.0.3", | |||
"rollbar": "^2.14.4", | |||
"semver-regex": "^3.1.0", | |||
"sourcemapped-stacktrace": "^1.1.11", | |||
"sweetalert2": "^9.4.0", | |||
"systeminformation": "^4.15.3", | |||
"tippy.js": "^5.1.1", | |||
@@ -141,6 +142,7 @@ | |||
"lint-staged": "^9.4.3", | |||
"mocha": "^6.2.2", | |||
"modclean": "^3.0.0-beta.1", | |||
"ngrok": "^3.2.7", | |||
"nodemon": "^1.19.4", | |||
"nyc": "^14.1.1", | |||
"rollbar-sourcemap-webpack-plugin": "^2.5.1", |
@@ -0,0 +1,11 @@ | |||
{ | |||
"name": "dreamtime", | |||
"displayName": "DreamTime", | |||
"description": "DreamTime allows you to nudify photos of people.", | |||
"author": "DreamNet", | |||
"homepage": "https://time.dreamnet.tech", | |||
"version": "1.3.1", | |||
"main": "electron/dist/index.js", | |||
"license": "GPL-3.0-only", | |||
"private": true | |||
} |
@@ -21,7 +21,7 @@ | |||
<box-item | |||
label="DreamPower" | |||
description="DreamPower is not installed or the installed version is not compatible."> | |||
:description="`DreamPower is not installed or the installed version is not compatible. ${$settings.processing.usePython ? '<b class=\'text-warning\'>Python enabled!</b>' : ''}`"> | |||
<template slot="icon"> | |||
<span v-if="requirements.power.installed && requirements.power.compatible" class="item__icon">✔</span> | |||
<span v-else class="item__icon">❌</span> |
@@ -0,0 +1,105 @@ | |||
<template> | |||
<div class="power"> | |||
<div class="layout__header"> | |||
<h1>Setup Wizard - {{ power.title }}.</h1> | |||
</div> | |||
<div class="power__content"> | |||
<div class="power__overview"> | |||
<figure> | |||
<img src="~/assets/images/apps/dreampower.png"> | |||
</figure> | |||
<h1>{{ power.title }}</h1> | |||
<h2>{{ power.description }}</h2> | |||
<div class="power__navigation"> | |||
<a v-for="(item, index) in power.navigation" :key="index" :href="item.href" target="_blank" class="button">{{ item.label }}</a> | |||
</div> | |||
</div> | |||
<div class="power__description"> | |||
<p>To make your dreams come true, it is necessary for {{ $dream.name }} to download and install {{ power.title }}, the algorithm/AI that will handle the entire nudification process.</p> | |||
<p>Keep in mind that the download of {{ power.title }} can be up to <strong>1 GB</strong>! (Depending on your system)</p> | |||
<p>In case the download cannot be done automatically, please click on the "Mirrors" button to see a list of links where you can download it manually.</p> | |||
</div> | |||
</div> | |||
<div class="power__installation" /> | |||
</div> | |||
</template> | |||
<script> | |||
import { nucleus } from '~/modules/services' | |||
export default { | |||
layout: 'wizard', | |||
computed: { | |||
power() { | |||
return nucleus.v1?.projects?.dreampower.about || { | |||
title: 'DreamPower', | |||
description: 'Deep Learning algorithm for nudify photos.', | |||
navigation: [ | |||
{ | |||
href: 'https://power.dreamnet.tech', | |||
label: 'Website', | |||
}, | |||
{ | |||
href: 'https://github.com/dreamnettech/dreampower', | |||
label: 'GitHub', | |||
}, | |||
{ | |||
href: 'https://www.patreon.com/dreampower', | |||
label: 'Patreon', | |||
}, | |||
], | |||
} | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.power__content { | |||
@apply flex; | |||
.power__overview { | |||
@apply flex-1 flex flex-col justify-center items-center; | |||
figure { | |||
@apply mb-6; | |||