Browse Source

Much better telemetry code, some design improvements and bugfixes.

tags/v1.4.4
Ivan Bravo Bravo 10 months ago
parent
commit
85e8ae87e2
55 changed files with 1838 additions and 705 deletions
  1. 8
    2
      src/.eslintrc.js
  2. 1
    1
      src/assets/css/components/_box.scss
  3. 1
    1
      src/assets/css/components/_button.scss
  4. 6
    2
      src/assets/css/components/_form.scss
  5. 1
    1
      src/assets/css/fonts.scss
  6. 27
    4
      src/assets/css/reset.scss
  7. 0
    3
      src/assets/css/tailwind.scss
  8. 3
    2
      src/components/Layout/Navbar.vue
  9. 3
    14
      src/components/Nudity/PhotoRun.vue
  10. 22
    17
      src/components/Nudity/Upload.vue
  11. 91
    0
      src/components/Settings/Preference.vue
  12. 24
    255
      src/components/Settings/SettingsPreferences.vue
  13. 2
    0
      src/components/Settings/index.js
  14. 15
    65
      src/components/UI/AppUpdate.vue
  15. 9
    8
      src/components/UI/BoxItem.vue
  16. 157
    0
      src/components/UI/ProjectUpdate.vue
  17. 2
    0
      src/components/UI/index.js
  18. 15
    11
      src/electron/src/index.js
  19. 118
    26
      src/electron/src/modules/settings.js
  20. 18
    15
      src/electron/src/modules/tools/fs.js
  21. 1
    1
      src/electron/src/modules/tools/power.js
  22. 51
    6
      src/electron/src/modules/tools/system.js
  23. 9
    7
      src/layouts/wizard.vue
  24. 2
    8
      src/middleware/wizard.js
  25. 0
    1
      src/modules/index.js
  26. 6
    6
      src/modules/nudify/nudify.js
  27. 26
    17
      src/modules/nudify/photo-run.js
  28. 14
    6
      src/modules/nudify/photo.js
  29. 1
    1
      src/modules/services/logrocket.js
  30. 0
    2
      src/modules/services/nucleus.js
  31. 1
    1
      src/modules/services/rollbar.js
  32. 175
    0
      src/modules/system/consola.js
  33. 147
    0
      src/modules/system/errors.js
  34. 4
    0
      src/modules/system/index.js
  35. 216
    0
      src/modules/system/log.js
  36. 2
    2
      src/modules/system/requirements.js
  37. 28
    23
      src/modules/updater/base.js
  38. 11
    4
      src/modules/updater/checkpoints.js
  39. 6
    3
      src/modules/updater/dreampower.js
  40. 8
    7
      src/modules/updater/dreamtime.js
  41. 2
    0
      src/nuxt.config.js
  42. 3
    0
      src/package.json
  43. 22
    62
      src/pages/about.vue
  44. 5
    5
      src/pages/settings/app.vue
  45. 25
    21
      src/pages/settings/processing.vue
  46. 16
    3
      src/pages/settings/telemetry.vue
  47. 96
    0
      src/pages/wizard/checkpoints.vue
  48. 146
    37
      src/pages/wizard/power.vue
  49. 205
    0
      src/pages/wizard/telemetry.vue
  50. 11
    7
      src/pages/wizard/tos.vue
  51. 5
    7
      src/pages/wizard/welcome.vue
  52. 32
    13
      src/plugins/boot.js
  53. 6
    22
      src/plugins/setup.js
  54. 13
    0
      src/plugins/vue-slider.js
  55. 20
    6
      src/tailwind.config.js

+ 8
- 2
src/.eslintrc.js View File

@@ -17,7 +17,12 @@ module.exports = {
],
globals: {
$provider: false,
AppError: false
AppError: false,
LogError: false,
Warning: false,
Exception: false,
consola: false,
Consola: false,
},
parserOptions: {
parser: "babel-eslint",
@@ -47,7 +52,7 @@ module.exports = {
"promise/no-callback-in-promise": "off",
"promise/catch-or-return": "off",
"linebreak-style": "warn",
"new-parens": ['error', 'never'],
"new-parens": "off",
"lodash/import-scope": [
"off",
"member"
@@ -88,6 +93,7 @@ module.exports = {
"error",
"never"
],
"prefer-spread": "off",
"quote-props": [
"error",
"as-needed"

+ 1
- 1
src/assets/css/components/_box.scss View File

@@ -10,7 +10,7 @@
*/

.box {
@apply bg-dark-500 rounded-sm shadow mb-6;
@apply bg-dark-600 shadow mb-6 border-t border-l border-r border-dark-100;

.box__photo {
@apply relative;

+ 1
- 1
src/assets/css/components/_button.scss View File

@@ -1,7 +1,7 @@
.button {
@apply inline-flex items-center justify-center;
@apply border border-primary-500-30;
@apply px-4 rounded-sm;
@apply px-4 rounded;
@apply text-primary-400 font-semibold uppercase;
@apply outline-none #{!important};
height: 40px;

+ 6
- 2
src/assets/css/components/_form.scss View File

@@ -11,18 +11,22 @@
}

.input {
@apply border border-dark-300 bg-dark-600;
@apply border border-dark-300 bg-dark-700;
@apply rounded py-2 px-4 w-full text-generic-300 shadow-inner;
outline: none !important;
transition: all .2s ease-in-out;

&:hover, &:focus {
@apply text-generic-100;
@apply text-generic-100 shadow-inner-md;
}

&::placeholder {
@apply text-generic-700;
}

&[disabled] {
@apply opacity-75 cursor-not-allowed;
}
}

select.input {

+ 1
- 1
src/assets/css/fonts.scss View File

@@ -1 +1 @@
@import url('https://fonts.googleapis.com/css?family=Catamaran:300,400,500,600,700&display=swap');
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700|Roboto+Slab:300,400,500,600,700');

+ 27
- 4
src/assets/css/reset.scss View File

@@ -6,10 +6,9 @@
}

html {
@apply bg-black text-generic-500;
font-family: theme('fontFamily.sans');
@apply bg-black text-generic-500 font-sans;
background-image: url('https://www.toptal.com/designers/subtlepatterns/patterns/papyrus-dark.png'); /* Background pattern from Toptal Subtle Patterns */
font-size: 16px;
word-spacing: 1px;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-moz-osx-font-smoothing: grayscale;
@@ -38,12 +37,28 @@ dialog {
@apply p-4 bg-dark-500 rounded;
@apply flex flex-col justify-center;
}

.dialog__buttons {
@apply flex mt-4;

.button {
@apply flex-1;

&:not(:last-child) {
@apply mr-2;
}
}
}
}

dialog::backdrop {
background: rgba(25, 25, 26, 0.75);
}

.title {
@apply font-serif;
}

.swal-content {
font-size: 16px;

@@ -71,7 +86,7 @@ dialog::backdrop {

*::-webkit-scrollbar-thumb
{
@apply bg-dark-100 rounded-sm;
@apply bg-dark-100;
transition: all .1s ease-in-out;

&:hover {
@@ -89,4 +104,12 @@ dialog::backdrop {
code {
@apply text-sm text-center;
}
}

.vue-slider {
@apply w-full #{!important};
}

.vue-slider-process {
@apply bg-primary-500 #{!important};
}

+ 0
- 3
src/assets/css/tailwind.scss View File

@@ -1,6 +1,3 @@
@tailwind base;
// @import './base/reset';
@tailwind components;
//@import './components/all';
@tailwind utilities;
//@import './utilities/all';

+ 3
- 2
src/components/Layout/Navbar.vue View File

@@ -9,7 +9,7 @@
About
</nuxt-link>

<nuxt-link v-if="canNudify" class="navbar__item" to="/dreamnet">
<nuxt-link class="navbar__item" to="/dreamnet">
DreamNet
</nuxt-link>

@@ -55,7 +55,8 @@ export default {

methods: {
createError() {
throw new Error('User Interface test error.')
// throw new Error('User Interface test error.')
throw new Warning('Warning Test')
},
},
}

+ 3
- 14
src/components/Nudity/PhotoRun.vue View File

@@ -277,7 +277,7 @@ export default {
}
</script>

<style lang="scss">
<style lang="scss" scoped>
.c-photo-run {
@apply bg-cover bg-center border border-dark-500;
@apply relative;
@@ -313,9 +313,10 @@ export default {
}

.run__content {
@apply opacity-0 bg-dark-500-90 w-full;
@apply opacity-0 bg-dark-500-80 w-full;
@apply absolute bottom-0;
@apply flex;
backdrop-filter: blur(5px);
transition: all .1s linear;
height: 100px;

@@ -358,18 +359,6 @@ export default {
}
}

.dialog__buttons {
@apply flex;

.button {
@apply flex-1;

&:not(:last-child) {
@apply mr-2;
}
}
}

.section__preferences {
p {
@apply text-sm;

+ 22
- 17
src/components/Nudity/Upload.vue View File

@@ -30,7 +30,7 @@
@drop="openDrop">
<p class="dropzone-hint">
<font-awesome-icon icon="camera" />
Drop the photo(s)/folder here!
Drop the photos here!
</p>
</div>

@@ -76,7 +76,7 @@

<div class="box__content">
<button class="button" @click.prevent="openFolder">
<span>import folder</span>
<span>Open folder</span>
</button>
</div>
</div>
@@ -97,7 +97,7 @@
<input v-model="webAddress" type="url" class="input mb-2" placeholder="https://">

<button class="button" @click="openUrl">
Go!
Submit
</button>
</div>
</div>
@@ -118,7 +118,7 @@
<input v-model="instagramPhoto" type="url" class="input mb-2" placeholder="https://www.instagram.com/p/dU4fHDw-Ho/">

<button class="button" @click="openInstagramPhoto">
Go!
Submit
</button>
</div>
</div>
@@ -132,9 +132,12 @@ import {
isNil, isEmpty, startsWith,
map, isArray,
} from 'lodash'
import Swal from 'sweetalert2'
import { nucleus } from '~/modules/services'
import { Nudify } from '~/modules/nudify'

const consola = Consola.create('upload')

const { instagram } = $provider
const { dialog } = $provider.api

@@ -152,9 +155,6 @@ export default {
isDragging: false,
}),

created() {

},

methods: {
/**
@@ -168,6 +168,9 @@ export default {
Nudify.addFile(file.path)
},

/**
*
*/
async addFiles(files) {
if (!isArray(files)) {
return
@@ -188,7 +191,7 @@ export default {

const paths = map(files, 'path')

nucleus.track('UPLOAD_FILE')
consola.track('FILE')

this.addFiles(paths)

@@ -211,13 +214,13 @@ export default {
*/
openUrl() {
if (isEmpty(this.webAddress) || (!startsWith(this.webAddress, 'http://') && !startsWith(this.webAddress, 'https://'))) {
throw new AppError('Please enter a valid web address.', { title: 'Upload failed.', level: 'warning' })
throw new Warning('Upload failed.', 'Please enter a valid web address.')
}

nucleus.track('UPLOAD_URL')

Nudify.addUrl(this.webAddress)

consola.track('URL')

this.webAddress = ''
},

@@ -226,7 +229,7 @@ export default {
*/
async openInstagramPhoto() {
if (isEmpty(this.instagramPhoto)) {
throw new AppError('Please enter a valid Instagram photo.', { title: 'Upload failed.', level: 'warning' })
throw new Warning('Upload failed.', 'Please enter a valid Instagram photo.')
}

let post
@@ -234,15 +237,17 @@ export default {
try {
post = await instagram.getPost(this.instagramPhoto)
} catch (error) {
throw new AppError('Unable to download the photo, please verify that the address is correct and that you are connected to the Internet.', { title: 'Upload failed.', error, level: 'warning' })
throw new Warning('Upload failed.', 'Unable to download the photo, please verify that the address is correct and that you are connected to the Internet.', error)
}

if (post.isVideo) {
throw new AppError('The videos are not supported yet.', { title: 'Upload failed.', level: 'warning' })
throw new Warning('Upload failed.', 'Videos are not supported yet.')
}

Nudify.addUrl(post.downloadUrl)

consola.track('INSTAGRAM')

this.instagramPhoto = ''
},

@@ -284,12 +289,12 @@ export default {
const url = event.dataTransfer.getData('url')

if (url.length > 0) {
nucleus.track('UPLOAD_DROP_URL')
Nudify.addUrl(url)
consola.track('DROP_URL')
} else if (files.length > 0) {
const paths = map(files, 'path')
this.addFiles(paths)
nucleus.track('UPLOAD_DROP_FILE')
consola.track('DROP_FILE')
}
},
},
@@ -332,7 +337,7 @@ export default {
.uploader__dropzone {
@apply flex items-center justify-center;
@apply bg-dark-500 mb-6;
@apply rounded border-2 border-dashed border-dark-100;
@apply border-2 border-dashed border-dark-100;
height: 200px;
transition: all 0.1s linear;


+ 91
- 0
src/components/Settings/Preference.vue View File

@@ -0,0 +1,91 @@
<template>
<section class="box box--items">
<div class="box__content">
<box-item :description="`Value: ${currentValue.size}`" :label="`${label} size`">
<VueSlider v-model="currentValue.size" :min="0.3" :max="2" :interval="0.05" />
</box-item>

<box-item
v-show="!body.randomize && body.progressive.enabled"
label="Progressive."
description="Increase the value progressively in each run">
<select v-model="currentValue.progressive" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<div v-show="body.randomize">
<box-item
label="Randomize."
description="Randomize the value in each run.">
<select v-model="currentValue.randomize.enabled" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
label="Range."
:description="`Min: ${currentValue.randomize.min} - Max: ${currentValue.randomize.max}`">
<VueSlider
v-model="randomizeRange"
:min-range="minRange"
:max-range="maxRange"
:min="minRange"
:max="maxRange"
:interval="0.05" />
</box-item>
</div>
</div>
</section>
</template>

<script>
import { VModel } from '~/mixins'

export default {

mixins: [VModel],
props: {
label: {
type: String,
required: true,
},
minRange: {
type: Number,
default: 0.3,
},
maxRange: {
type: Number,
default: 2,
},
},

computed: {
randomizeRange: {
get() {
return [this.currentValue.randomize.min, this.currentValue.randomize.max]
},
set(value) {
const [min, max] = value

this.currentValue.randomize.min = min
this.currentValue.randomize.max = max
},
},

body() {
return this.$parent.currentValue?.body
},
},
}
</script>

+ 24
- 255
src/components/Settings/SettingsPreferences.vue View File

@@ -3,22 +3,22 @@
<section v-show="currentValue.advanced.transformMode !== 'import-maskfin'" class="box box--items">
<div class="box__header">
<h2 class="title">
Runs
Per run.
</h2>
<h3 class="subtitle">
Customize what will happen in each processing.
Customize what will happen in each transformation.
</h3>
</div>

<div class="box__content">
<box-item
label="Number of runs"
description="How many times will the photo be processed?">
label="Runs."
description="Number of times the photo will be transformed.">
<input v-model="currentValue.body.executions" type="number" min="1" class="input">
</box-item>

<box-item
label="Randomize"
label="Randomize."
description="Random body preferences will be set at each run.">
<select v-model="currentValue.body.randomize" class="input">
<option :value="true">
@@ -32,7 +32,7 @@

<box-item
v-show="!currentValue.body.randomize"
label="Progressive"
label="Progressive."
:description="`Body preferences will increase their value ${currentValue.body.progressive.rate} at each run.`">
<select v-model="currentValue.body.progressive.enabled" class="input">
<option :value="true">
@@ -46,264 +46,33 @@

<box-item
v-show="!currentValue.body.randomize"
label="Progressive rate"
:description="`Current value: ${currentValue.body.progressive.rate}`">
<div class="slider-container">
<input
v-model="currentValue.body.progressive.rate"
type="range"
class="slider"
min="0.1"
max="0.9"
step="0.1">
<span class="min">0.1</span>
<span class="max">0.9</span>
</div>
label="Progressive Rate."
:description="`Value: ${currentValue.body.progressive.rate}`">
<VueSlider v-model="currentValue.body.progressive.rate" :min="0.1" :max="0.9" :interval="0.05" />
</box-item>
</div>
</section>

<section v-show="currentValue.advanced.transformMode !== 'import-maskfin'" class="box box--items">
<div class="box__header">
<h2 class="title">
Body
</h2>
<h3 class="subtitle">
Customize the body of your dream.
</h3>
</div>

<div class="box__content">
<!-- Boobs -->
<box-item :description="`Current value: ${currentValue.body.boobs.size}`" label="Boobs size">
<div class="slider-container">
<input
v-model="currentValue.body.boobs.size"
type="range"
class="slider"
in="0.3"
max="2"
step="0.1">
<span class="min">0.3</span>
<span class="max">2.0</span>
</div>
</box-item>

<box-item
v-show="currentValue.body.randomize"
label="Randomize"
description="Randomize the value in each run."
class="box__item--sub">
<select v-model="currentValue.body.boobs.randomize" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
v-show="!currentValue.body.randomize && currentValue.body.progressive.enabled"
label="Progressive"
description="Increase the value progressively in each run"
class="box__item--sub">
<select v-model="currentValue.body.boobs.progressive" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<!-- Areola -->
<box-item :description="`Current value: ${currentValue.body.areola.size}`" label="Areola size">
<div class="slider-container">
<input
v-model="currentValue.body.areola.size"
type="range"
class="slider"
in="0.3"
max="2"
step="0.1">
<span class="min">0.3</span>
<span class="max">2.0</span>
</div>
</box-item>

<box-item
v-show="currentValue.body.randomize"
label="Randomize"
description="Randomize the value in each run."
class="box__item--sub">
<select v-model="currentValue.body.areola.randomize" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
v-show="!currentValue.body.randomize && currentValue.body.progressive.enabled"
label="Progressive"
description="Increase the value progressively in each run"
class="box__item--sub">
<select v-model="currentValue.body.areola.progressive" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<!-- Nipple -->
<box-item :description="`Current value: ${currentValue.body.nipple.size}`" label="Nipple Size">
<div class="slider-container">
<input
v-model="currentValue.body.nipple.size"
type="range"
class="slider"
in="0.3"
max="2"
step="0.1">
<span class="min">0.3</span>
<span class="max">2.0</span>
</div>
</box-item>

<box-item
v-show="currentValue.body.randomize"
label="Randomize"
description="Randomize the value in each run."
class="box__item--sub">
<select v-model="currentValue.body.nipple.randomize" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>
<!-- Boobs -->
<Preference v-model="currentValue.body.boobs" label="Boobs" />

<box-item
v-show="!currentValue.body.randomize && currentValue.body.progressive.enabled"
label="Progressive"
description="Increase the value progressively in each run"
class="box__item--sub">
<select v-model="currentValue.body.nipple.progressive" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<!-- Vagina -->
<box-item :description="`Current value: ${currentValue.body.vagina.size}`" label="Vagina Size">
<div class="slider-container">
<input
v-model="currentValue.body.vagina.size"
type="range"
class="slider"
in="0.3"
max="1.5"
step="0.1"></input>
<span class="min">0.3</span>
<span class="max">1.5</span>
</div>
</box-item>

<box-item
v-show="currentValue.body.randomize"
label="Randomize"
description="Randomize the value in each run."
class="box__item--sub">
<select v-model="currentValue.body.vagina.randomize" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
v-show="!currentValue.body.randomize && currentValue.body.progressive.enabled"
label="Progressive"
description="Increase the value progressively in each run"
class="box__item--sub">
<select v-model="currentValue.body.vagina.progressive" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>
<!-- Areola -->
<Preference v-model="currentValue.body.areola" label="Areola" />

<box-item :description="`Current value: ${currentValue.body.pubicHair.size}`" label="Pubic Hair">
<div class="slider-container">
<input
v-model="currentValue.body.pubicHair.size"
type="range"
class="slider"
in="0"
max="2"
step="0.1"></input>
<span class="min">Disabled</span>
<span class="max">2.0</span>
</div>
</box-item>
<!-- Nipple -->
<Preference v-model="currentValue.body.nipple" label="Nipple" />

<box-item
v-show="currentValue.body.randomize"
label="Randomize"
description="Randomize the value in each run."
class="box__item--sub">
<select v-model="currentValue.body.pubicHair.randomize" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>
<!-- Vagina -->
<Preference v-model="currentValue.body.vagina" label="Vagina" :max-range="1.5" />

<box-item
v-show="!currentValue.body.randomize && currentValue.body.progressive.enabled"
label="Progressive"
description="Increase the value progressively in each run"
class="box__item--sub">
<select v-model="currentValue.body.pubicHair.progressive" class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>
</div>
</section>
<!-- Pubic Hair -->
<Preference v-model="currentValue.body.pubicHair" label="Pubic Hair" :min-range="0" />

<!-- Advanced -->
<section class="box box--items">
<div class="box__header">
<h2 class="title">
Advanced
Advanced.
</h2>
<h3 class="subtitle">
Additional processing settings.
@@ -312,7 +81,7 @@

<div class="box__content">
<box-item
label="Scale method"
label="Scale method."
description="Method to scale the photo to 512x512">
<select v-model="currentValue.advanced.scaleMode" class="input">
<option value="none">
@@ -337,7 +106,7 @@
</box-item>

<box-item
label="Transform method"
label="Transform method."
description="Transformation method, only recommended for advanced users.">
<select v-model="currentValue.advanced.transformMode" class="input">
<option value="normal">
@@ -353,7 +122,7 @@
</box-item>

<box-item
label="Color transfer"
label="Color transfer."
description="Use a experimental color transfer algorithm to try to recover the original colors of the photo.">
<select v-model="currentValue.advanced.useColorTransfer" class="input">
<option :value="true">

+ 2
- 0
src/components/Settings/index.js View File

@@ -11,5 +11,7 @@

import Vue from 'vue'
import SettingsPreferences from './SettingsPreferences'
import Preference from './Preference'

Vue.component('settings-preferences', SettingsPreferences)
Vue.component('Preference', Preference)

+ 15
- 65
src/components/UI/AppUpdate.vue View File

@@ -17,69 +17,19 @@
v-else-if="!updater.update.active"
:label="`${projectTitle} ${updater.latest.tag_name} available.`"
icon="fire-alt"
class="update-item">
<button v-tooltip="'Download and install the update automatically.'" type="button" class="button is-sm" @click.prevent="updater.start()">
Update
</button>

<a v-tooltip="'Download the update manually.'" :href="downloadURL" target="_blank" class="button is-sm">
Manual
</a>
</box-item>

<!-- update... -->
<!-- eslint-disable-next-line vue/valid-template-root --->
<box-item
v-else
:label="updater.update.status"
icon="globe">
<template slot="description">
<p v-if="updater.update.status === 'Downloading...'" class="item__description">
<strong>{{ updater.update.progress | progress }}</strong> - {{ updater.update.written | size }}/{{ updater.update.total | size }} MB.
</p>

<p v-else class="item__description">
Wait a few minutes, please do not close the program.
</p>
</template>

<button type="button" class="button is-danger is-sm" @click.prevent="updater.cancel()">
Cancel
</button>
</box-item>
class="update-item"
:is-link="true"
@click="next" />
</template>

<script>
import { isString, toNumber } from 'lodash'

/* eslint import/namespace: ['error', { allowComputed: true }] */
import * as updateProviders from '~/modules/updater'
import * as providers from '~/modules/updater'

const { shell } = $provider.api
const { getPath } = $provider.paths

export default {
filters: {
progress(value) {
if (isString(value)) {
// eslint-disable-next-line no-param-reassign
value = toNumber(value)
}

const progress = (value * 100).toFixed(2)
return `${progress}%`
},

size(value) {
if (isString(value)) {
// eslint-disable-next-line no-param-reassign
value = toNumber(value)
}

return value.toFixed(2)
},
},

props: {
project: {
type: String,
@@ -90,31 +40,31 @@ export default {
type: String,
default: 'Project',
},

href: {
type: String,
required: true,
},
},

data: () => ({
currentVersion: 'v0.0.0',
updater: {},
}),

computed: {
downloadURL() {
return this.updater.downloadUrls[0]
currentVersion() {
return this.updater?.currentVersion || 'v0.0.0'
},
},

created() {
this.currentVersion = this.updater.currentVersion
this.updater = updateProviders[this.project]
},

beforeDestroy() {
this.updater.cancel()
this.updater = providers[this.project]
},

methods: {
openDownload() {
shell.openItem(getPath('downloads'))
next() {
console.log(this.href)
this.$router.push(this.href)
},
},
}

+ 9
- 8
src/components/UI/BoxItem.vue View File

@@ -36,22 +36,27 @@ export default {
type: [String, Array],
default: undefined,
},

label: {
type: String,
required: true,
},

description: {
type: String,
default: undefined,
},

version: {
type: String,
default: undefined,
},

href: {
type: String,
default: undefined,
},

isLink: {
type: Boolean,
default: false,
@@ -69,7 +74,7 @@ export default {

cssClass() {
return {
'is-link': !isNil(this.href) || this.isLink,
'box__item--link': !isNil(this.href) || this.isLink,
}
},
},
@@ -125,16 +130,12 @@ export default {
@apply pl-8;
}

&:hover {
@apply bg-dark-400 text-white;
}

&.is-link {
&.box__item--link {
@apply cursor-pointer;
transition: all .1s ease-in-out;

&:hover {
@apply bg-dark-600;
@apply bg-dark-600 text-white;
}
}

@@ -163,7 +164,7 @@ export default {
}

.item__action {
@apply w-1/3 ml-4 flex flex-col justify-center;
@apply w-1/3 ml-4 flex items-center justify-center;
}
}
}

+ 157
- 0
src/components/UI/ProjectUpdate.vue View File

@@ -0,0 +1,157 @@
<template>
<div class="project-update">
<!-- Update available -->
<div v-if="!updater.update.active" class="update__status">
{{ updater.latest.tag_name }} available:
</div>

<!-- Downloading -->
<div v-else-if="isDownloading" class="update__status">
Downloading ~ <strong>{{ updater.update.progress | progress }}</strong> ~ {{ updater.update.written | size }}/{{ updater.update.total | size }} MB.
</div>

<!-- Installing -->
<div v-else-if="isInstalling" class="update__status">
Installing...
</div>

<!-- Download Progress -->
<div v-show="isDownloading" class="update__progressbar">
<progress min="0" max="100" :value="updater.update.progress" />
</div>

<!-- Actions -->
<div class="update__actions">
<button v-show="!updater.update.active" class="button button--success" @click.prevent="updater.start()">
Download
</button>

<button v-show="updater.update.active" class="button button--danger" @click.prevent="updater.cancel()">
Cancel
</button>

<button class="button button--info" @click.prevent="$refs.mirrorsDialog.show()">
Mirrors
</button>
</div>

<!-- Mirrors Dialog -->
<dialog ref="mirrorsDialog">
<div class="dialog__content">
<ul class="mirrors">
<li v-for="(item, index) in updater.downloadUrls" :key="index">
<a :href="item" target="_blank">{{ item | domain }}</a>
</li>
</ul>

<div class="dialog__buttons">
<button class="button button--danger" @click.prevent="$refs.mirrorsDialog.close()">
Close
</button>
</div>
</div>
</dialog>
</div>
</template>

<script>
import { isString, toNumber } from 'lodash'
import * as providers from '~/modules/updater'

export default {
filters: {
progress(value) {
if (isString(value)) {
value = toNumber(value)
}

return `${value}%`
},

size(value) {
if (isString(value)) {
value = toNumber(value)
}

return value.toFixed(2)
},

domain(value) {
return (new URL(value)).hostname
},
},

props: {
project: {
type: String,
required: true,
},
},

data: () => ({
updater: null,
}),

computed: {
currentVersion() {
return this.updater?.currentVersion || 'v0.0.0'
},

isDownloading() {
return this.updater?.update?.status === 'downloading'
},

isInstalling() {
return this.updater?.update?.status === 'installing'
},
},

created() {
// eslint-disable-next-line import/namespace
this.updater = providers[this.project]
},

beforeDestroy() {
this.updater.cancel()
},
}
</script>

<style lang="scss" scoped>
.project-update {
@apply flex flex-col items-center justify-center;
}

.update__status {
@apply mb-6 text-2xl text-white;
}

.update__progressbar {
@apply mb-6;
width: 80%;

progress {
@apply w-full border-0 bg-dark-600;
height: 18px;
border-radius: 9px;

&::-webkit-progress-bar {
@apply bg-dark-800;
border-radius: 9px;
}

&::-webkit-progress-value {
@apply bg-primary-500;
border-radius: 9px;
}
}
}

.mirrors {
@apply list-disc ml-6;

a:hover {
@apply underline;
}
}
</style>

+ 2
- 0
src/components/UI/index.js View File

@@ -13,9 +13,11 @@ import Update from './AppUpdate'
import BoxItem from './BoxItem'
import AppPhoto from './AppPhoto'
import AppNews from './AppNews'
import ProjectUpdate from './ProjectUpdate'

Vue.component('app-title', Title)
Vue.component('app-update', Update)
Vue.component('app-photo', AppPhoto)
Vue.component('app-news', AppNews)
Vue.component('box-item', BoxItem)
Vue.component('ProjectUpdate', ProjectUpdate)

+ 15
- 11
src/electron/src/index.js View File

@@ -18,6 +18,12 @@ import { getPath } from './modules/tools/paths'
import { settings, ngrok } from './modules'
import config from '~/nuxt.config'

// logger setup
Logger.setOptions({
filename: getPath('userData', 'dreamtime.main.log'),
logLevel: process.env.LOG || 'debug',
})

const logger = Logger.create('electron')

// NuxtJS root directory
@@ -38,12 +44,6 @@ class DreamApp {
*
*/
static async boot() {
// logger setup
Logger.setOptions({
filename: getPath('userData', 'dreamtime.main.log'),
logLevel: process.env.LOG || 'debug',
})

logger.info('Booting...')

logger.debug(`Enviroment: ${process.env.name}`)
@@ -76,6 +76,7 @@ class DreamApp {

// this may increase performance on some systems.
if (settings.app?.disableHardwareAcceleration) {
logger.debug('Hardware Acceleration disabled.')
app.disableHardwareAcceleration()
}
}
@@ -104,12 +105,13 @@ class DreamApp {

// application exit.
app.on('will-quit', async (event) => {
logger.debug('Exiting...')
logger.debug('Received exit event.')

event.preventDefault()

await this.shutdown()

logger.debug('Bye!')
app.exit()
})

@@ -134,7 +136,7 @@ class DreamApp {

event.preventDefault()

logger.warn('Blocked attempt to load an external page.', {
logger.warn('Illegal page load blocked!', {
event,
url,
})
@@ -181,6 +183,8 @@ class DreamApp {
*/
// eslint-disable-next-line no-empty-function
static async shutdown() {
logger.debug('Shutting down services...')

if (process.env.name === 'development') {
await ngrok.disconnect()
}
@@ -233,7 +237,7 @@ class DreamApp {
* Wait until the NuxtJS server is ready.
*/
static pollUi() {
logger.debug(`Requesting status from the server: ${this.uiUrl}`)
logger.debug(`Requesting server (${this.uiUrl})...`)

const http = require('http')

@@ -243,12 +247,12 @@ class DreamApp {
logger.debug('Server ready, dream time!')
this.window.loadURL(this.uiUrl)
} else {
logger.warn(`The server reported: ${response.statusCode}`)
logger.warn(`Server reported: ${response.statusCode}`)
setTimeout(this.pollUi.bind(this), 300)
}
})
.on('error', (error) => {
logger.warn('Poll error', error)
logger.warn('Server error', error)
setTimeout(this.pollUi.bind(this), 300)
})
}

+ 118
- 26
src/electron/src/modules/settings.js View File

@@ -14,7 +14,7 @@ import {
import { AppError } from './app-error'
import { paths, system } from './tools'

const logger = require('logplease').create('electron:scripts:services:settings')
const logger = require('logplease').create('settings')

/**
* User settings.
@@ -64,6 +64,7 @@ class Settings {
*/
async save() {
fs.writeJsonSync(this.path, this.payload, { spaces: 2 })
logger.debug('Settings saved!')
}

/**
@@ -91,14 +92,6 @@ class Settings {
this.save()
}

/**
* Setup service
*/
async setup() {
await this._create()
await this._upgrade()
}

/**
*
*/
@@ -107,14 +100,21 @@ class Settings {
await this.load()
}

/**
* Setup service
*/
async setup() {
await this._create()
await this._upgrade()
}

/**
* Load the default configuration (and the current version)
*/
_loadDefault() {
const hasGPU = system.graphics.length > 0
const cores = round(system.cores / 2) || 1

const uuid = require('uuid')
const hasGPU = system.graphics.length > 0
const cores = round(system.cpu?.cores / 2) || 1

this.payload = {
version: 6,
@@ -148,7 +148,6 @@ class Settings {
telemetry: {
bugs: true,
dom: true,
domPrivate: false,
},

processing: {
@@ -169,28 +168,48 @@ class Settings {
},

boobs: {
size: '1',
randomize: true,
size: 1,
randomize: {
enabled: true,
min: 0.3,
max: 2,
},
progressive: true,
},
areola: {
size: '1',
randomize: false,
size: 1,
randomize: {
enabled: true,
min: 0.3,
max: 2,
},
progressive: true,
},
nipple: {
size: '1',
randomize: false,
size: 1,
randomize: {
enabled: true,
min: 0.3,
max: 2,
},
progressive: true,
},
vagina: {
size: '0.75',
randomize: true,
size: 0.75,
randomize: {
enabled: true,
min: 0.3,
max: 1.5,
},
progressive: true,
},
pubicHair: {
size: '1',
randomize: true,
size: 1,
randomize: {
enabled: true,
min: 0,
max: 2,
},
progressive: true,
},
},
@@ -215,6 +234,9 @@ class Settings {
return
}

// default settings now with the system information.
this._loadDefault()

try {
fs.outputFileSync(this.path, JSON.stringify(this._default, null, 2))
} catch (error) {
@@ -323,7 +345,38 @@ class Settings {
this.payload.telemetry = {
bugs: this.payload.enabled,
dom: true,
domPrivate: false,
}

const { body } = this.payload.preferences

body.boobs.randomize = {
enabled: true,
min: 0.3,
max: 2,
}

body.areola.randomize = {
enabled: true,
min: 0.3,
max: 2,
}

body.nipple.randomize = {
enabled: true,
min: 0.3,
max: 2,
}

body.vagina.randomize = {
enabled: true,
min: 0.3,
max: 1.5,
}

body.pubicHair.randomize = {
enabled: true,
min: 0,
max: 2,
}
}

@@ -331,12 +384,47 @@ class Settings {
}
}

export const settingsRaw = new Settings

const saveHandler = {
get(target, property, receiver) {
try {
return new Proxy(target[property], saveHandler)
} catch (err) {
return Reflect.get(target, property, receiver)
}
},
defineProperty(target, property, descriptor) {
settingsRaw.save()
return Reflect.defineProperty(target, property, descriptor)
},
}

const settingsHandler = {
get(target, property, receiver) {
try {
if (property in target) {
return target[property]
}

if (property in target.payload) {
return new Proxy(target.payload[property], saveHandler)
}
// eslint-disable-next-line no-empty
} catch (err) { }

return Reflect.get(target, property, receiver)
},
}

/**
* Create a new instance with a Proxy.
*
* @return {Proxy}
*/
export function make(obj) {
return new Proxy(obj, settingsHandler)
/*
return new Proxy(obj, {
get: (obj, prop) => {
if (prop in obj) {
@@ -351,6 +439,11 @@ export function make(obj) {
},

set: (obj, prop, value) => {
console.log({
prop,
value,
})

if (!isNil(obj.payload)) {
if (prop in obj.payload) {
obj.payload[prop] = value
@@ -364,8 +457,7 @@ export function make(obj) {
return true
},
})
*/
}

export const settingsRaw = new Settings

export const settings = make(settingsRaw)

+ 18
- 15
src/electron/src/modules/tools/fs.js View File

@@ -1,9 +1,6 @@
import { attempt } from 'lodash'
import { basename, join } from 'path'
import {
readFileSync, writeFileSync,
existsSync,
createWriteStream, createReadStream,
} from 'fs-extra'
import fs from 'fs-extra'
import { app, dialog } from 'electron'
import axios from 'axios'
import deferred from 'deferred'
@@ -35,7 +32,7 @@ export function getBase64Data(dataURL) {
* @param {string} encoding
*/
export function read(path, encoding = 'utf-8') {
return readFileSync(path, { encoding })
return fs.readFileSync(path, { encoding })
}

/**
@@ -45,7 +42,7 @@ export function read(path, encoding = 'utf-8') {
*/
export function writeDataURL(path, dataURL) {
const data = this.getBase64Data(dataURL)
return writeFileSync(path, data, 'base64')
return fs.writeFileSync(path, data, 'base64')
}

/**
@@ -58,7 +55,7 @@ export function extractZip(path, destinationPath) {

const def = deferred()

const stream = createReadStream(path).pipe(unzipper.Extract({ path: destinationPath }))
const stream = fs.createReadStream(path).pipe(unzipper.Extract({ path: destinationPath }))

stream.on('close', () => {
def.resolve()
@@ -140,7 +137,7 @@ export function download(url, options = {}) {
})
}

const writeStream = createWriteStream(filepath)
const writeStream = fs.createWriteStream(filepath)

axios.request({
url,
@@ -173,7 +170,7 @@ export function download(url, options = {}) {
return
}

if (!existsSync(filepath)) {
if (!fs.existsSync(filepath)) {
throw new AppError('The file was not saved correctly.', { title: 'Download failed.' })
}

@@ -185,18 +182,24 @@ export function download(url, options = {}) {
bus.on('cancel', () => {
cancelled = true

writeStream.destroy()
data.destroy()
attempt(() => {
writeStream.destroy()
data.destroy()
fs.unlinkSync(filepath)
})

logger.info('Download canceled by user.')
logger.info('Download cancelled by user.')
bus.emit('cancelled')
})

return true
}).catch((err) => {
writeStream.destroy(err)
attempt(() => {
writeStream.destroy(err)
fs.unlinkSync(filepath)
})

logger.warn('Download canceled due to an error.', err)
logger.warn('Download cancelled due to an error.', err)
bus.emit('error', null, err)
})


+ 1
- 1
src/electron/src/modules/tools/power.js View File

@@ -16,7 +16,7 @@ import * as fs from 'fs-extra'
import { getPowerPath } from './paths'
import { settings } from '../settings'

const logger = require('logplease').create('electron:power')
const logger = require('logplease').create('power')

export function exec(args, options = {}) {
args.push('--debug')

+ 51
- 6
src/electron/src/modules/tools/system.js View File

@@ -36,6 +36,19 @@ class System {
*/
memory

/**
* @type {Object}
*/
snapshot = {
load: null,
cpu: {
speed: null,
temperature: null,
},
memory: null,
online: false,
}

/**
* @type {boolean}
*/
@@ -45,11 +58,13 @@ class System {
*
*/
async setup() {
logger.debug('Collecting system information...')

const [
graphics,
os,
cpu,
mem,
memory,
online,
] = await Promise.all([
si.graphics(),
@@ -62,13 +77,43 @@ class System {
this._graphics = graphics
this.os = os
this.cpu = cpu
this.memory = mem
this.memory = memory
this.online = online

logger.info(`GPU devices: ${this.graphics.length}`)
logger.info(`RAM: ${this.memory.total} bytes.`)
logger.info(`Internet connection: ${this.online}`)
logger.debug(this)
logger.info(`GPU:`, this.graphics)
logger.info(`RAM: ${memory.total} bytes.`)
logger.info(`Online: ${online}`)
}

/**
*
*/
async takeSnapshot() {
logger.info('Taking snapshot...')

const [load, cpuSpeed, cpuTemperature, memory, online] = await Promise.all([
si.currentLoad(),
si.cpuCurrentspeed(),
si.cpuTemperature(),
si.mem(),
isOnline(),
])

this.snapshot = {
load,
cpu: {
speed: cpuSpeed,
temperature: cpuTemperature,
},
memory,
online,
}

logger.info(`Current load:`, load)
logger.info(`CPU Speed:`, cpuSpeed)
logger.info(`CPU Temperature:`, cpuTemperature)
logger.info(`Memory:`, memory)
logger.info(`Online: ${online}`)
}

/**

+ 9
- 7
src/layouts/wizard.vue View File

@@ -9,8 +9,6 @@
</template>

<script>


export default {

}
@@ -31,7 +29,7 @@ export default {

.layout__content {
@apply relative overflow-hidden overflow-y-auto;
@apply p-6;
@apply p-6 border-t border-dark-500;
grid-area: content;
height: calc(100vh - 30px);
}
@@ -40,12 +38,16 @@ export default {

<style lang="scss">
.layout__header {
@apply flex justify-center items-center;
@apply text-3xl font-semibold mb-6;
height: 60px;
@apply flex flex-col justify-center items-center;
@apply text-3xl font-semibold mb-8;
height: 80px;

h1 {
.title {
@apply text-xl text-white;
}

.subtitle {
@apply text-lg;
}
}
</style>

+ 2
- 8
src/middleware/wizard.js View File

@@ -50,10 +50,9 @@ export default function ({ route, redirect }) {
if (route.path !== '/wizard/telemetry') {
redirect('/wizard/telemetry')
}

return
}

/*
if (!wizard.user) {
if (route.path !== '/wizard/user') {
redirect('/wizard/user')
@@ -61,10 +60,5 @@ export default function ({ route, redirect }) {

return
}

if (!wizard.telemetry) {
if (route.path !== '/wizard/telemetry') {
redirect('/wizard/telemetry')
}
}
*/
}

+ 0
- 1
src/modules/index.js View File

@@ -1,4 +1,3 @@
export { AppError } from './app-error'
export { events } from './events'
export { File } from './file'
export { Timer } from './timer'

+ 6
- 6
src/modules/nudify/nudify.js View File

@@ -21,7 +21,7 @@ import { Photo } from './photo'
import { File } from '../file'
import { getFilesMetadata } from '~/workers/fs'

const logger = require('logplease').create('nudify')
const consola = Consola.create('nudify')

const { settings } = $provider

@@ -139,7 +139,7 @@ export class Nudify {

this.photos.unshift(photo)

logger.debug('Photo added!', photo.file.fullname)
consola.debug(`Photo ${photo.file.fullname} added!`)

this.emitUpdate()

@@ -176,7 +176,7 @@ export class Nudify {
this.add(file)
} catch (err) {
if (multiple) {
logger.warn('Error adding a photo, skipped.', err)
consola.warn('Error adding a photo.', err)
} else {
throw err
}
@@ -216,7 +216,7 @@ export class Nudify {
*/
static async addUrl(url) {
if (!startsWith(url, 'http://') && !startsWith(url, 'https://')) {
throw new AppError('Please enter a valid web address.', { title: 'Upload failed.', level: 'warning' })
throw new Warning('Upload failed.', 'Please enter a valid web address.')
}

Swal.fire({
@@ -234,7 +234,7 @@ export class Nudify {

this.add(file)
} catch (error) {
throw new AppError('There was a problem trying to download the file. Make sure you have an Internet connection.', { title: 'Upload failed.', level: 'warning', error })
throw new Warning('Upload failed.', 'Unable to download the photo, please verify that the address is correct and that you are connected to the Internet.', error)
}
}

@@ -317,7 +317,7 @@ export class Nudify {
return
}

logger.debug(`Forgetting ${photo.file.fullname}...`)
consola.debug(`Forgetting ${photo.file.fullname}...`)

this.forget(photo)
})

+ 26
- 17
src/modules/nudify/photo-run.js View File

@@ -152,9 +152,15 @@ export class PhotoRun {

start() {
const def = deferred()
const { consola } = this.photo

const onSpawnError = (error) => {
def.reject(new AppError('There was a problem trying to start DreamPower, make sure you have everything set up correctly.', { title: 'DreamPower failed!', error, level: 'warn' }))
consola
.withError(error)
.warn('There was a problem trying to start DreamPower, make sure you have everything set up correctly.')
.show('DreamPower failed!')

def.reject()
}

this.beforeStart()
@@ -199,14 +205,14 @@ export class PhotoRun {
this.maskfinFile.open(),
])

nucleus.track('DREAM_COMPLETED')
window.consola.track('DREAM_COMPLETED')

def.resolve()
})

this.process.on('fail', (fileError) => {
if (fileError) {
def.reject(new AppError('DreamPower has transformed the photo but could not save it.', { title: `Run ${this.id} failed!`, level: 'warn' }))
def.reject(new Warning(`Run ${this.id} failed!`, 'DreamPower has transformed the photo but could not save it.', fileError))
} else {
def.reject(this.getPowerError())
}
@@ -227,14 +233,16 @@ export class PhotoRun {
const preferences = this.preferences.body

if (preferences.randomize) {
// randomize
// randomize.
forIn(preferencesConfig, (payload, key) => {
if (preferences[key].randomize) {
preferences[key].size = rand(payload.min, payload.max)
const { enabled, min, max } = preferences[key].randomize

if (enabled) {
preferences[key].size = rand(min, max)
}
})
} else if (preferences.progressive.enabled) {
// progressive
// progressive.
const add = preferences.progressive.rate * (this.id - 1)

forIn(preferencesConfig, (payload, key) => {
@@ -281,21 +289,22 @@ export class PhotoRun {
return null
}

const { consola } = this.photo

const title = `Run ${this.id} has failed.`

const options = {
error: new Error(message),
terminal: this.cli.lines,
}

for (const payload of cliErrors) {
if (message.includes(payload.error)) {
return new AppError(payload.message, {
title: `Run ${this.id} has failed.`,
level: payload.level,
error: new Error(message),
})
return new LogError(consola, title, payload.message, payload.level, options)
}
}

return new AppError(`DreamPower has been interrupted by an unknown error, this may be caused by a corrupt installation, please check the console for more information.\n<pre>${message}</pre>`, {
title: `Run ${this.id} has failed.`,
error: new Error(message),
terminal: this.cli.lines,
})
return new Exception(consola, title, 'DreamPower has been interrupted by an unknown error.', options)
}

_sendNotification() {

+ 14
- 6
src/modules/nudify/photo.js View File

@@ -14,6 +14,7 @@ import Queue from 'better-queue'
import MemoryStore from 'better-queue-memory'
import Logger from 'logplease'
import EventBus from 'js-event-bus'
import { Consola } from '../system'
import { Nudify } from './nudify'
import { PhotoRun } from './photo-run'
import { File } from '../file'
@@ -113,6 +114,11 @@ export class Photo {
*/
_logger

/**
* @type {Consola}
*/
consola

get folderName() {
// todo: implement models
return 'Uncategorized'
@@ -202,7 +208,9 @@ export class Photo {

this.fileCrop = new File(getCropPath(`${this.id}-crop${file.extension}`), 'crop')

this._logger = Logger.create(`nudify:photo:${file.fullname}`)
this._logger = Logger.create(file.fullname)

this.consola = Consola.create(file.fullname)

this._setupPreferences(isMaskfin)

@@ -287,16 +295,16 @@ export class Photo {
const { exists, mimetype, path } = this.file

if (!exists) {
throw new AppError(`The file "${path}" does not exists.`, { title: 'Upload failed.', level: 'warn' })
throw new Warning('Upload failed.', `The file "${path}" does not exists.`)
}

if (mimetype !== 'image/jpeg' && mimetype !== 'image/png' && mimetype !== 'image/gif') {
throw new AppError(`The file "${path}" is not a valid photo. Only jpeg, png or gif.`, { title: 'Upload failed.', level: 'warn' })
throw new Warning('Upload failed.', `The file "${path}" is not a valid photo. Only jpeg, png or gif.`)
}
}

_setupQueue() {
let maxTimeout = settings.processing.device === 'GPU' ? (3 * 60 * 1000) : (10 * 60 * 1000)
let maxTimeout = settings.processing.device === 'GPU' ? (3 * 60 * 1000) : (20 * 60 * 1000)

if (this.file.mimetype === 'image/gif') {
maxTimeout += (30 * 60 * 1000)
@@ -304,8 +312,6 @@ export class Photo {

this.queue = new Queue(this._run, {
maxTimeout,
// maxRetries: 2,
// retryDelay: 1000,
afterProcessDelay: 500,
batchSize: 1,
concurrent: 1,
@@ -335,9 +341,11 @@ export class Photo {
this._logger.warn(`Run #${runId} failed!`, error)
run.onFail()

/*
if (error !== 'cancelled') {
AppError.handle(error)
}
*/
})
}


+ 1
- 1
src/modules/services/logrocket.js View File

@@ -35,7 +35,7 @@ class LogRocketService extends BaseService {
* @type {boolean}
*/
get can() {
return isString(this.accessToken)
return isString(this.accessToken) && process.env.name === 'production'
}

/**

+ 0
- 2
src/modules/services/nucleus.js View File

@@ -15,8 +15,6 @@ const { system, settings } = $provider

const logger = require('logplease').create('services:nucleus')

console.log(settings)

/**
* https://nucleus.sh
* Analytics and bug tracking for Javascript desktop apps.

+ 1
- 1
src/modules/services/rollbar.js View File

@@ -36,7 +36,7 @@ class RollbarService extends BaseService {
* @type {boolean}
*/
get can() {
return isString(this.accessToken)
return isString(this.accessToken) && process.env.name === 'production'
}

/**

+ 175
- 0
src/modules/system/consola.js View File

@@ -0,0 +1,175 @@
// 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 {
isError, isString, isNil, isPlainObject,
} from 'lodash'
import Logger from 'logplease'
import { Log } from './log'
import { nucleus, logrocket } from '../services'

export class Consola {
/**
* @type {string}
*/
category

/**
* @type {Logger.Logger}
*/
logger

/**
*
* @param {string} [category]
*/
static create(category) {
return new this(category)
}

/**
*
* @param {Array} args
*/
static parseArgs(args) {
let title
let message
let error
let options = {}

args.forEach((value) => {
if (isError(value)) {
error = value
} else if (isPlainObject(value)) {
options = value
} else if (isString(value) && isNil(message)) {
message = value
} else if (isString(value) && isNil(title)) {
title = message
message = value
}
})

if (isNil(message)