@@ -4,8 +4,7 @@ | |||
"@babel/preset-env", | |||
{ | |||
"targets": { | |||
"node": "10", | |||
"electron": "7" | |||
"node": "10" | |||
} | |||
} | |||
] |
@@ -18,11 +18,10 @@ module.exports = { | |||
globals: { | |||
$provider: false, | |||
AppError: false, | |||
LogError: false, | |||
LogEvent: false, | |||
Warning: false, | |||
Exception: false, | |||
consola: false, | |||
Consola: false, | |||
consola: false | |||
}, | |||
parserOptions: { | |||
parser: "babel-eslint", | |||
@@ -43,7 +42,7 @@ module.exports = { | |||
"comma-dangle": "warn", | |||
"global-require": "off", | |||
"import/default": "warn", | |||
"import/no-webpack-loader-syntax": "warn", | |||
"import/no-webpack-loader-syntax": "off", | |||
"import/order": ['error'], | |||
"import/prefer-default-export": "off", | |||
"import/no-extraneous-dependencies": "off", | |||
@@ -72,7 +71,6 @@ module.exports = { | |||
"no-continue": "off", | |||
"no-debugger": "error", | |||
"no-lone-blocks": "error", | |||
"no-param-reassign": "off", | |||
"no-restricted-globals": "warn", | |||
"no-restricted-syntax": "off", | |||
"no-shadow": "off", |
@@ -27,7 +27,7 @@ | |||
@apply px-4 pt-4; | |||
.title { | |||
@apply text-lg font-bold text-white; | |||
@apply text-lg font-semibold text-generic-200; | |||
} | |||
.subtitle { |
@@ -32,7 +32,7 @@ | |||
} | |||
&::placeholder { | |||
@apply text-generic-700; | |||
@apply text-generic-900; | |||
} | |||
&[disabled] { |
@@ -11,7 +11,7 @@ | |||
.notification { | |||
@apply mb-4 py-2 px-4 border-2 border-dark-100 rounded-sm; | |||
@apply bg-transparent text-generic-100 font-bold; | |||
@apply bg-transparent text-generic-100; | |||
a { | |||
@apply underline; |
@@ -0,0 +1,66 @@ | |||
/* | |||
* 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>, 2020. | |||
*/ | |||
.wizard-project { | |||
.project__content { | |||
@apply flex mb-6 pb-6 border-b border-dark-500; | |||
.project__overview { | |||
@apply flex-1 flex flex-col justify-center items-center; | |||
figure { | |||
@apply mb-6 text-6xl; | |||
img { | |||
height: 100px; | |||
} | |||
} | |||
h1 { | |||
@apply text-2xl text-white font-bold; | |||
} | |||
h2 { | |||
@apply text-lg; | |||
} | |||
.project__navigation { | |||
@apply mt-6; | |||
.button { | |||
&:not(:last-child) { | |||
@apply mr-2; | |||
} | |||
} | |||
} | |||
} | |||
.project__description { | |||
@apply flex-1 flex flex-col justify-center; | |||
p { | |||
@apply text-xl mb-6; | |||
} | |||
} | |||
} | |||
.project__installation { | |||
@apply flex; | |||
.project__update { | |||
@apply flex-1; | |||
} | |||
.project__settings { | |||
@apply flex-1; | |||
} | |||
} | |||
} |
@@ -5,3 +5,4 @@ | |||
@import './form'; | |||
@import './notification'; | |||
@import './markdown'; | |||
@import './wizard'; |
@@ -23,21 +23,48 @@ | |||
.swal2-html-container { | |||
pre { | |||
@apply text-xs overflow-auto bg-gray-300 p-2; | |||
@apply text-xs overflow-auto bg-black p-2; | |||
max-height: 100px; | |||
} | |||
} | |||
.swal2-container.swal2-backdrop-show { | |||
backdrop-filter: blur(6px); | |||
transition: all 0.1s; | |||
} | |||
.swal2-footer { | |||
code { | |||
@apply text-sm text-center; | |||
} | |||
} | |||
.swal2-popup { | |||
@apply bg-dark-600 border border-dark-100 border-solid shadow-lg; | |||
} | |||
.vue-slider { | |||
@apply w-full #{!important}; | |||
} | |||
.vue-slider-process { | |||
@apply bg-primary-500 #{!important}; | |||
} | |||
.introjs-tooltip { | |||
@apply bg-dark-500-90 #{!important}; | |||
min-width: 350px !important; | |||
max-width: 400px !important; | |||
} | |||
.introjs-arrow { | |||
//@apply bg-dark-500-90 #{!important}; | |||
} | |||
.introjs-helperLayer { | |||
background-color: transparent !important; | |||
} | |||
.introjs-overlay { | |||
backdrop-filter: blur(10px); | |||
} |
@@ -1 +0,0 @@ | |||
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700|Roboto+Slab:300,400,500,600,700'); |
@@ -5,16 +5,28 @@ | |||
Nudify | |||
</nuxt-link> | |||
<nuxt-link class="navbar__item" to="/settings"> | |||
<nuxt-link id="settings" class="navbar__item" to="/settings"> | |||
Settings | |||
</nuxt-link> | |||
<a class="navbar__item" :href="manualURL" target="_blank"> | |||
<a id="guide" class="navbar__item" :href="manualURL" target="_blank"> | |||
Help | |||
</a> | |||
<nuxt-link v-if="unlockedBadTime" class="navbar__item" to="/games/badtime"> | |||
Bad Time | |||
</nuxt-link> | |||
<a v-if="isDev" class="navbar__item" @click.prevent="createError"> | |||
Error | |||
Force Error | |||
</a> | |||
<a v-if="isDev" href="https://google.com" class="navbar__item"> | |||
External Page | |||
</a> | |||
<a v-if="isDev" href="https://google.com" target="_blank" class="navbar__item"> | |||
Popup | |||
</a> | |||
</div> | |||
@@ -35,10 +47,15 @@ | |||
</template> | |||
<script> | |||
import { requirements } from '~/modules/system' | |||
import { requirements, settings } from '~/modules/system' | |||
import { nucleus } from '~/modules/services' | |||
import { events } from '~/modules' | |||
export default { | |||
data: () => ({ | |||
unlockedBadTime: settings.achievements.badtime, | |||
}), | |||
computed: { | |||
canNudify() { | |||
return requirements.canNudify | |||
@@ -49,7 +66,7 @@ export default { | |||
}, | |||
manualURL() { | |||
return nucleus.urls?.docs?.manual || 'https://forum.dreamnet.tech/d/32-dreamtime-manual' | |||
return nucleus.urls?.docs?.manual || 'https://time.dreamnet.tech/docs/guide/upload' | |||
}, | |||
isDev() { | |||
@@ -57,10 +74,15 @@ export default { | |||
}, | |||
}, | |||
mounted() { | |||
events.on('achievements.badtime', () => { | |||
this.unlockedBadTime = true | |||
}) | |||
}, | |||
methods: { | |||
createError() { | |||
// throw new Error('User Interface test error.') | |||
throw new Warning('Warning Test') | |||
throw new Error('UI TEST ERROR') | |||
}, | |||
}, | |||
} | |||
@@ -74,7 +96,11 @@ export default { | |||
.navbar__left, | |||
.navbar__right { | |||
@apply flex-1 flex items-center; | |||
@apply flex items-center; | |||
} | |||
.navbar__left { | |||
@apply flex-1 mr-2; | |||
} | |||
.navbar__right { |
@@ -1,158 +0,0 @@ | |||
<template> | |||
<div class="layout-menu"> | |||
<div :class="{ 'is-active': isActive }" class="navbar"> | |||
<!-- App Navigation --> | |||
<section class="menu-section"> | |||
<nav class="menu-items"> | |||
<nuxt-link v-if="canNudify" to="/" class="menu-item"> | |||
<span class="icon">๐ท</span> | |||
<span>Nudify</span> | |||
</nuxt-link> | |||
<nuxt-link to="/system/about" class="menu-item"> | |||
<span class="icon">๐</span> | |||
<span>About</span> | |||
</nuxt-link> | |||
<nuxt-link to="/system/settings/processing" class="menu-item"> | |||
<span class="icon">๐ง</span> | |||
<span>Settings</span> | |||
</nuxt-link> | |||
</nav> | |||
</section> | |||
<!-- Developer Navigation --> | |||
<section v-if="isDev" class="menu-section"> | |||
<nav class="menu-items" /> | |||
</section> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { requirements } from '~/modules/system' | |||
const { settings } = $provider | |||
export default { | |||
computed: { | |||
canNudify() { | |||
return requirements.canNudify | |||
}, | |||
isDev() { | |||
return process.env.NODE_ENV === 'development' | |||
}, | |||
isActive() { | |||
// eslint-disable-next-line no-underscore-dangle | |||
return settings.welcome !== true | |||
}, | |||
}, | |||
methods: { | |||
testBug() { | |||
throw new Error('wow much error') | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
@keyframes navShowAnim { | |||
0% { | |||
left: -200px; | |||
} | |||
100% { | |||
left: 0; | |||
} | |||
} | |||
.layout-menu { | |||
@apply pb-6 shadow h-screen bg-dark-500 relative; | |||
@apply border-r border-dark-300; | |||
width: 200px; | |||
.menu { | |||
@apply absolute top-0 bottom-0; | |||
left: -200px; | |||
width: inherit; | |||
&.is-active { | |||
animation-name: navShowAnim; | |||
animation-fill-mode: forwards; | |||
animation-duration: 0.5s; | |||
animation-timing-function: ease-in-out; | |||
} | |||
} | |||
.menu-header { | |||
@apply mb-4 text-gray-300 flex flex-col items-center justify-center; | |||
animation: 20s ease-in-out infinite bgAnim; | |||
height: 70px; | |||
background: rgb(99, 66, 245); | |||
background: linear-gradient( | |||
40deg, | |||
rgba(99, 66, 245, 1) 0%, | |||
rgba(239, 125, 199, 1) 100% | |||
); | |||
background-size: 200% 100%; | |||
/* | |||
clip-path: polygon( | |||
50% 0%, | |||
100% 0, | |||
100% 85%, | |||
75% 100%, | |||
25% 100%, | |||
0 85%, | |||
0 0 | |||
); | |||
*/ | |||
.header-title { | |||
@apply text-white text-xl font-bold; | |||
} | |||
.header-greetings { | |||
@apply text-sm; | |||
} | |||
} | |||
.menu-section { | |||
@apply mb-4; | |||
} | |||
.section-title { | |||
@apply text-center font-bold; | |||
} | |||
.menu-items { | |||
.menu-item { | |||
@apply border-l-4 border-transparent pl-4 font-semibold flex items-center; | |||
height: 50px; | |||
transition: all 0.1s ease-in-out; | |||
.icon { | |||
@apply text-center mr-2; | |||
filter: grayscale(100%); | |||
width: 22px; | |||
transition: all 0.1s ease-in-out; | |||
} | |||
&:hover, | |||
&.nuxt-link-exact-active { | |||
@apply text-primary-500 border-primary-500; | |||
.icon { | |||
filter: unset; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -1,6 +1,6 @@ | |||
<template> | |||
<div class="layout__jobbar"> | |||
<section> | |||
<div id="queuebar" class="layout__jobbar"> | |||
<section id="queuebar-running"> | |||
<div class="section__header"> | |||
<div class="section__title"> | |||
<span class="icon"><font-awesome-icon icon="running" /></span> | |||
@@ -31,12 +31,12 @@ | |||
class="job" | |||
:class="{ 'job--running': photo.running }" | |||
@click.prevent="openJob(photo.id)"> | |||
<img :src="photo.file.dataURL"> | |||
<img :src="photo.file.path" data-private> | |||
</figure> | |||
</div> | |||
</section> | |||
<section> | |||
<section id="queuebar-pending"> | |||
<div class="section__header"> | |||
<div class="section__title"> | |||
<span class="icon"><font-awesome-icon icon="clipboard-list" /></span> | |||
@@ -66,12 +66,12 @@ | |||
:key="index" | |||
class="job" | |||
@click.prevent="openJob(photo.id)"> | |||
<img :src="photo.file.dataURL"> | |||
<img :src="photo.file.path" data-private> | |||
</figure> | |||
</div> | |||
</section> | |||
<section> | |||
<section id="queuebar-finished"> | |||
<div class="section__header"> | |||
<div class="section__title"> | |||
<span class="icon"><font-awesome-icon icon="clipboard-check" /></span> | |||
@@ -102,7 +102,7 @@ | |||
class="job" | |||
:class="{ 'job--failed': photo.failed }" | |||
@click.prevent="openJob(photo.id)"> | |||
<img :src="photo.file.dataURL"> | |||
<img :src="photo.file.path" data-private> | |||
</figure> | |||
</div> | |||
</section> | |||
@@ -167,7 +167,7 @@ section { | |||
} | |||
.section__actions { | |||
@apply flex flex-1 justify-end ml-2; | |||
@apply flex flex-1 justify-end ml-2 z-10 bg-dark-500; | |||
.button { | |||
@apply ml-2; | |||
@@ -180,11 +180,15 @@ section { | |||
@apply px-4 py-2 overflow-y-auto max-h-full; | |||
.job { | |||
@apply inline-block mb-2 mr-2 cursor-pointer; | |||
width: 48px; | |||
height: 48px; | |||
@apply inline-block mb-2 cursor-pointer; | |||
width: 47px; | |||
height: 47px; | |||
transition: all .1s ease-in-out; | |||
&:not(:nth-child(3n)) { | |||
@apply mr-2; | |||
} | |||
&.job--running { | |||
img { | |||
@apply border-primary-500; | |||
@@ -199,7 +203,7 @@ section { | |||
&:hover { | |||
@apply z-30; | |||
transform: scale(1.5) | |||
transform: scale(1.3) | |||
} | |||
img { |
@@ -11,7 +11,7 @@ | |||
<div v-show="badTime" class="topbar__badtime"> | |||
<img src="~/assets/images/games/sans.png"> | |||
here we go. | |||
i don't like what you are doing. | |||
</div> | |||
</div> | |||
@@ -32,7 +32,7 @@ | |||
</template> | |||
<script> | |||
import moment from 'moment' | |||
import dayjs from 'dayjs' | |||
const { activeWindow, api } = $provider.util | |||
@@ -43,7 +43,7 @@ export default { | |||
computed: { | |||
greetings() { | |||
const hours = moment().hours() | |||
const hours = dayjs().hour() | |||
if (hours >= 6 && hours <= 11) { | |||
return 'โ Good morning' | |||
@@ -62,7 +62,7 @@ export default { | |||
}, | |||
mounted() { | |||
this.$router.afterEach((to, from) => { | |||
this.$router.afterEach((to) => { | |||
if (to.path === '/games/badtime') { | |||
this.$dream.name = 'BadDreamTime' | |||
this.badTime = true |
@@ -2,8 +2,8 @@ import Vue from 'vue' | |||
import LayoutTopbar from './Topbar' | |||
import LayoutNavbar from './Navbar' | |||
import LayoutJobbar from './Jobbar' | |||
import LayoutQueuebar from './Queuebar' | |||
Vue.component('layout-topbar', LayoutTopbar) | |||
Vue.component('layout-navbar', LayoutNavbar) | |||
Vue.component('layout-jobbar', LayoutJobbar) | |||
Vue.component('LayoutTopbar', LayoutTopbar) | |||
Vue.component('LayoutNavbar', LayoutNavbar) | |||
Vue.component('LayoutQueuebar', LayoutQueuebar) |
@@ -1,23 +1,32 @@ | |||
<template> | |||
<div class="c-photo-run" :style="previewStyle"> | |||
<div v-if="run.preferences.body.randomize || run.preferences.body.progressive.enabled" class="run__details"> | |||
<table class="table"> | |||
<tr> | |||
<th>Boobs size</th> | |||
<th>Areola size</th> | |||
<th>Nipple size</th> | |||
<th>Vagina size</th> | |||
<th>Pubic hair</th> | |||
</tr> | |||
<tr> | |||
<td>{{ Number(run.preferences.body.boobs.size).toFixed(2) }}</td> | |||
<td>{{ Number(run.preferences.body.areola.size).toFixed(2) }}</td> | |||
<td>{{ Number(run.preferences.body.nipple.size).toFixed(2) }}</td> | |||
<td>{{ Number(run.preferences.body.vagina.size).toFixed(2) }}</td> | |||
<td>{{ Number(run.preferences.body.pubicHair.size).toFixed(2) }}</td> | |||
</tr> | |||
</table> | |||
<div class="c-photo-run" :style="previewStyle" data-private> | |||
<div v-if="run.preferences.body.randomize || run.preferences.body.progressive.enabled" class="run__preferences"> | |||
<div class="preference"> | |||
<span>Boobs</span> | |||
<span>{{ run.preferences.body.boobs.size | fixedValue }}</span> | |||
</div> | |||
<div class="preference"> | |||
<span>Areola</span> | |||
<span>{{ run.preferences.body.areola.size | fixedValue }}</span> | |||
</div> | |||
<div class="preference"> | |||
<span>Nipple</span> | |||
<span>{{ run.preferences.body.nipple.size | fixedValue }}</span> | |||
</div> | |||
<div class="preference"> | |||
<span>Vagina</span> | |||
<span>{{ run.preferences.body.vagina.size | fixedValue }}</span> | |||
</div> | |||
<div class="preference"> | |||
<span>Pubic hair</span> | |||
<span>{{ run.preferences.body.pubicHair.size | fixedValue }}</span> | |||
</div> | |||
</div> | |||
<div class="run__content"> | |||
<div v-if="run.running" class="content__item"> | |||
<p class="text-white"> | |||
@@ -70,12 +79,6 @@ | |||
</button> | |||
</div> | |||
<div v-if="run.preferences.body.randomize || run.preferences.body.progressive.enabled" class="content__item"> | |||
<button v-tooltip="'View preferences'" class="button button--info button--sm" @click.prevent="$refs.preferencesDialog.showModal()"> | |||
<font-awesome-icon icon="sliders-h" /> | |||
</button> | |||
</div> | |||
<div class="content__item"> | |||
<button v-tooltip="'View terminal'" class="button button--sm" @click.prevent="$refs.terminalDialog.showModal()"> | |||
<font-awesome-icon icon="terminal" /> | |||
@@ -87,13 +90,13 @@ | |||
<dialog ref="maskfinDialog"> | |||
<div class="dialog__content dialog__maskfin"> | |||
<div class="maskfin__preview"> | |||
<img :src="run.maskfinFile.dataURL"> | |||
<img :src="run.maskfinFile.path"> | |||
</div> | |||
<div class="maskfin__description"> | |||
<p>This is the Maskfin, a mask that represents in layers the areas that the algorithm will replace with the fake nude.</p> | |||
<p>Click on the "Add to queue" button to add it as an additional photo, edit the layers and continue with the nudification. You can also save it to your computer, edit it with an external program and continue the nudification manually.</p> | |||
<p>For more information please consult the <a :href="manualURL" target="_blank">manual</a>.</p> | |||
<p>For more information please consult the <a :href="manualURL" target="_blank">guide</a>.</p> | |||
</div> | |||
<div class="dialog__buttons"> | |||
@@ -128,39 +131,6 @@ | |||
</div> | |||
</div> | |||
</dialog> | |||
<!-- Preferences Dialog --> | |||
<dialog ref="preferencesDialog"> | |||
<div class="dialog__content"> | |||
<table class="table mb-2"> | |||
<tr> | |||
<th>Boobs size</th> | |||
<td>{{ Number(run.preferences.body.boobs.size).toFixed(2) }}</td> | |||
</tr> | |||
<tr> | |||
<th>Areola size</th> | |||
<td>{{ Number(run.preferences.body.areola.size).toFixed(2) }}</td> | |||
</tr> | |||
<tr> | |||
<th>Nipple size</th> | |||
<td>{{ Number(run.preferences.body.nipple.size).toFixed(2) }}</td> | |||
</tr> | |||
<tr> | |||
<th>Vagina size</th> | |||
<td>{{ Number(run.preferences.body.vagina.size).toFixed(2) }}</td> | |||
</tr> | |||
<tr> | |||
<th>Pubic hair</th> | |||
<td>{{ Number(run.preferences.body.pubicHair.size).toFixed(2) }}</td> | |||
</tr> | |||
</table> | |||
<div class="dialog__buttons"> | |||
<button class="button button--danger" @click.prevent="$refs.preferencesDialog.close()"> | |||
Close | |||
</button> | |||
</div> | |||
</div> | |||
</dialog> | |||
</div> | |||
</template> | |||
@@ -176,6 +146,10 @@ export default { | |||
size(value) { | |||
return Number.parseFloat(value).toFixed(2) | |||
}, | |||
fixedValue(value) { | |||
return Number(value).toFixed(2) | |||
}, | |||
}, | |||
props: { | |||
@@ -185,21 +159,13 @@ export default { | |||
}, | |||
}, | |||
data: () => ({ | |||
outputDataURL: undefined, | |||
}), | |||
computed: { | |||
previewDataURL() { | |||
return this.run.outputFile.dataURL | |||
}, | |||
previewStyle() { | |||
if (!this.previewDataURL) { | |||
if (!this.run.outputFile.exists) { | |||
return {} | |||
} | |||
return { backgroundImage: `url(${this.previewDataURL})` } | |||
return { backgroundImage: `url(${this.run.outputFile.path})` } | |||
}, | |||
hasMaskfin() { | |||
@@ -207,15 +173,7 @@ export default { | |||
}, | |||
manualURL() { | |||
return nucleus.urls?.docs?.manual || 'https://forum.dreamnet.tech/d/32-dreamtime-manual' | |||
}, | |||
}, | |||
watch: { | |||
'run.finished'(value) { | |||
if (value) { | |||
this.outputDataURL = this.run.outputFile.dataURL | |||
} | |||
return nucleus.urls?.docs?.manual || 'https://time.dreamnet.tech/docs/guide/upload' | |||
}, | |||
}, | |||
@@ -265,14 +223,6 @@ export default { | |||
this.run.maskfinFile.copy(savePath) | |||
}, | |||
viewPreferences() { | |||
//$refs.preferencesDialog.showModal() | |||
}, | |||
viewTerminal() { | |||
//$refs.terminalDialog.showModal() | |||
}, | |||
}, | |||
} | |||
</script> | |||
@@ -285,39 +235,42 @@ export default { | |||
height: 512px; | |||
&:hover { | |||
.run__content { | |||
@apply opacity-100; | |||
} | |||
.run__details { | |||
.run__content, | |||
.run__preferences { | |||
@apply opacity-100; | |||
} | |||
} | |||
} | |||
.run__details { | |||
@apply opacity-0 bg-dark-500-90 w-full; | |||
@apply absolute top-0; | |||
.run__content, | |||
.run__preferences { | |||
@apply absolute opacity-0 bg-dark-500-80 w-full; | |||
@apply flex; | |||
transition: all 0.1s linear; | |||
backdrop-filter: blur(6px); | |||
transition: all .1s linear; | |||
} | |||
.run__preferences { | |||
@apply flex top-0; | |||
height: 80px; | |||
table{ | |||
margin-left:auto; | |||
margin-right:auto; | |||
th{ | |||
padding:4px; | |||
} | |||
td{ | |||
@apply text-center; | |||
.preference { | |||
@apply flex flex-col flex-1 items-center justify-center; | |||
span { | |||
&:first-child { | |||
@apply text-xs; | |||
} | |||
&:last-child { | |||
@apply text-sm text-white font-bold; | |||
} | |||
} | |||
} | |||
} | |||
.run__content { | |||
@apply opacity-0 bg-dark-500-80 w-full; | |||
@apply absolute bottom-0; | |||
@apply flex; | |||
backdrop-filter: blur(5px); | |||
transition: all .1s linear; | |||
@apply bottom-0; | |||
height: 100px; | |||
.content__item { |
@@ -1,19 +1,19 @@ | |||
<template> | |||
<div class="c-uploader"> | |||
<div class="uploader__settings box box--items"> | |||
<div id="uploader" class="c-uploader"> | |||
<div id="uploader-settings" class="uploader__settings box box--items"> | |||
<div class="box__content"> | |||
<box-item | |||
label="Upload mode" | |||
description="What will happen when uploading a photo."> | |||
<select v-model="$settings.app.uploadMode" class="input"> | |||
<option value="none"> | |||
Stay | |||
Put in Pending | |||
</option> | |||
<option value="add-queue"> | |||
Start transformation | |||
Put in Queue | |||
</option> | |||
<option value="go-preferences"> | |||
Change preferences | |||
Put in Pending and open preferences | |||
</option> | |||
</select> | |||
</box-item> | |||
@@ -22,6 +22,7 @@ | |||
<!-- Dropzone --> | |||
<div | |||
id="uploader-dropzone" | |||
class="uploader__dropzone" | |||
:class="{'is-dragging': isDragging}" | |||
@dragenter="onDragEnter" | |||
@@ -30,11 +31,11 @@ | |||
@drop="openDrop"> | |||
<p class="dropzone-hint"> | |||
<font-awesome-icon icon="camera" /> | |||
Drop the photos here! | |||
Drop the dream here! | |||
</p> | |||
</div> | |||
<div class="uploader__alt"> | |||
<div id="uploader-alternatives" class="uploader__alt"> | |||
<!-- File --> | |||
<div class="box"> | |||
<div class="box__header"> | |||
@@ -94,7 +95,7 @@ | |||
</div> | |||
<div class="box__content"> | |||
<input v-model="webAddress" type="url" class="input mb-2" placeholder="https://"> | |||
<input v-model="webAddress" type="url" class="input mb-2" placeholder="https://" data-private="lipsum"> | |||
<button class="button" @click="openUrl"> | |||
Submit | |||
@@ -115,7 +116,7 @@ | |||
</div> | |||
<div class="box__content"> | |||
<input v-model="instagramPhoto" type="url" class="input mb-2" placeholder="https://www.instagram.com/p/dU4fHDw-Ho/"> | |||
<input v-model="instagramPhoto" type="url" class="input mb-2" placeholder="https://www.instagram.com/p/dU4fHDw-Ho/" data-private="lipsum"> | |||
<button class="button" @click="openInstagramPhoto"> | |||
Submit | |||
@@ -127,14 +128,13 @@ | |||
</template> | |||
<script> | |||
/* eslint-disable no-param-reassign */ | |||
import { | |||
isNil, isEmpty, startsWith, | |||
map, isArray, | |||
} from 'lodash' | |||
import Swal from 'sweetalert2' | |||
import { nucleus } from '~/modules/services' | |||
import { Nudify } from '~/modules/nudify' | |||
import { Consola } from '~/modules/consola' | |||
import { tutorial } from '~/modules' | |||
const consola = Consola.create('upload') | |||
@@ -155,6 +155,9 @@ export default { | |||
isDragging: false, | |||
}), | |||
mounted() { | |||
tutorial.upload() | |||
}, | |||
methods: { | |||
/** |
@@ -38,8 +38,7 @@ | |||
:description="`Min: ${currentValue.randomize.min} - Max: ${currentValue.randomize.max}`"> | |||
<VueSlider | |||
v-model="randomizeRange" | |||
:min-range="minRange" | |||
:max-range="maxRange" | |||
:min-range="0.05" | |||
:min="minRange" | |||
:max="maxRange" | |||
:interval="0.05" /> |
@@ -100,7 +100,7 @@ | |||
Overlay | |||
</option> | |||
<option value="cropjs"> | |||
Manual crop (Not recommended) | |||
Manual crop | |||
</option> | |||
</select> | |||
</box-item> | |||
@@ -123,7 +123,7 @@ | |||
<box-item | |||
label="Color transfer." | |||
description="Use a experimental color transfer algorithm to try to recover the original colors of the photo."> | |||
description="Use a experimental algorithm to try to recover the original colors of the photo."> | |||
<select v-model="currentValue.advanced.useColorTransfer" class="input"> | |||
<option :value="true"> | |||
Enabled |
@@ -26,9 +26,6 @@ | |||
/* eslint import/namespace: ['error', { allowComputed: true }] */ | |||
import * as providers from '~/modules/updater' | |||
const { shell } = $provider.api | |||
const { getPath } = $provider.paths | |||
export default { | |||
props: { | |||
project: { | |||
@@ -63,7 +60,6 @@ export default { | |||
methods: { | |||
next() { | |||
console.log(this.href) | |||
this.$router.push(this.href) | |||
}, | |||
}, |
@@ -155,7 +155,7 @@ export default { | |||
@apply flex-1 flex flex-col justify-center; | |||
.item__label { | |||
@apply block font-semibold; | |||
@apply block font-semibold text-generic-400; | |||
} | |||
.item__description { |
@@ -55,25 +55,19 @@ | |||
</template> | |||
<script> | |||
import { isString, toNumber } from 'lodash' | |||
import { toNumber } from 'lodash' | |||
import * as providers from '~/modules/updater' | |||
export default { | |||
filters: { | |||
progress(value) { | |||
if (isString(value)) { | |||
value = toNumber(value) | |||
} | |||
value = toNumber(value).toFixed(2) | |||
return `${value}%` | |||
}, | |||
size(value) { | |||
if (isString(value)) { | |||
value = toNumber(value) | |||
} | |||
return value.toFixed(2) | |||
value = toNumber(value).toFixed(2) | |||
return value | |||
}, | |||
domain(value) { | |||
@@ -136,7 +130,7 @@ export default { | |||
border-radius: 9px; | |||
&::-webkit-progress-bar { | |||
@apply bg-dark-800; | |||
@apply bg-dark-500; | |||
border-radius: 9px; | |||
} | |||
@@ -58,12 +58,6 @@ const macos = { | |||
to: '7zip-bin', | |||
}, | |||
], | |||
extraFiles: [ | |||
{ | |||
from: '.env', | |||
to: 'MacOS/.env', | |||
}, | |||
], | |||
}, | |||
dmg: { | |||
title: '${productName}', | |||
@@ -94,7 +88,7 @@ module.exports = { | |||
'!**/{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', | |||
'!electron/src', | |||
], | |||
extraFiles: [ | |||
{ |
@@ -10,7 +10,7 @@ | |||
import { startsWith } from 'lodash' | |||
import { app, BrowserWindow, shell } from 'electron' | |||
import { dirname, resolve } from 'path' | |||
import Logger from 'logplease' | |||
import Logger from '@dreamnet/logplease' | |||
import fs from 'fs-extra' | |||
import { AppError } from './modules/app-error' | |||
import { system } from './modules/tools/system' | |||
@@ -18,12 +18,6 @@ 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 | |||
@@ -44,6 +38,15 @@ class DreamApp { | |||
* | |||
*/ | |||
static async boot() { | |||
const logDir = getPath('userData', 'logs', new Date().toJSON().slice(0, 10)) | |||
fs.ensureDirSync(logDir) | |||
// logger setup | |||
Logger.setOptions({ | |||
filename: resolve(logDir, 'main.log'), | |||
logLevel: process.env.LOG || 'debug', | |||
}) | |||
logger.info('Booting...') | |||
logger.debug(`Enviroment: ${process.env.name}`) | |||
@@ -137,7 +140,6 @@ class DreamApp { | |||
event.preventDefault() | |||
logger.warn('Illegal page load blocked!', { | |||
event, | |||
url, | |||
}) | |||
}) | |||
@@ -172,10 +174,12 @@ class DreamApp { | |||
// | |||
this.createDirs() | |||
/* | |||
if (process.env.name === 'development') { | |||
const address = await ngrok.connect() | |||
logger.debug(`Proxy for debugging: ${address}`) | |||
} | |||
*/ | |||
} | |||
/** | |||
@@ -207,12 +211,13 @@ class DreamApp { | |||
webPreferences: { | |||
nodeIntegration: true, | |||
nodeIntegrationInWorker: true, | |||
webSecurity: false, // Necessary to load local photos and not put them in memory. | |||
preload: resolve(app.getAppPath(), 'electron', 'dist', 'provider.js'), | |||
}, | |||
}) | |||
// maximize | |||
// todo: custom preferences | |||
// TODO: custom preferences | |||
this.window.maximize() | |||
// disable menu |
@@ -12,7 +12,7 @@ import { | |||
} from 'lodash' | |||
import { app, dialog } from 'electron' | |||
const logger = require('logplease').create('error:main') | |||
const logger = require('@dreamnet/logplease').create('error:main') | |||
/** | |||
* @typedef {Object} ErrorOptions |
@@ -12,7 +12,7 @@ import { | |||
} from 'lodash' | |||
import { existsSync, readJsonSync, writeJsonSync } from 'fs-extra' | |||
const logger = require('logplease').create('services') | |||
const logger = require('@dreamnet/logplease').create('services') | |||
export function makeServiceProxy(obj) { | |||
return new Proxy(obj, { |
@@ -14,7 +14,7 @@ import { | |||
import { AppError } from './app-error' | |||
import { paths, system } from './tools' | |||
const logger = require('logplease').create('settings') | |||
const logger = require('@dreamnet/logplease').create('settings') | |||
/** | |||
* User settings. | |||
@@ -43,7 +43,7 @@ class Settings { | |||
} | |||
/** | |||
* Load the service file. | |||
* Load the settings. | |||
*/ | |||
async load() { | |||
if (isNil(this.path)) { | |||
@@ -54,13 +54,14 @@ class Settings { | |||
this.payload = fs.readJsonSync(this.path) | |||
logger.debug('Settings:', this.payload) | |||
} catch (error) { | |||
// eslint-disable-next-line no-console | |||
console.error(error) | |||
} | |||
} | |||
/** | |||
* Save the service file. | |||
* This function is called automatically if you set a first level variable. | |||
* Save the settings file. | |||
* This function is called automatically. | |||
*/ | |||
async save() { | |||
fs.writeJsonSync(this.path, this.payload, { spaces: 2 }) | |||
@@ -88,8 +89,6 @@ class Settings { | |||
} else { | |||
this.payload = set(this.payload, path, payload) | |||
} | |||
this.save() | |||
} | |||
/** | |||
@@ -127,8 +126,12 @@ class Settings { | |||
telemetry: false, | |||
}, | |||
achievements: { | |||
badtime: false, | |||
}, | |||
app: { | |||
disableHardwareAcceleration: true, | |||
disableHardwareAcceleration: false, | |||
uploadMode: 'none', | |||
}, | |||
@@ -347,6 +350,10 @@ class Settings { | |||
dom: true, | |||
} | |||
this.payload.achievements = { | |||
badtime: false, | |||
} | |||
const { body } = this.payload.preferences | |||
body.boobs.randomize = { | |||
@@ -384,7 +391,7 @@ class Settings { | |||
} | |||
} | |||
export const settingsRaw = new Settings | |||
export const theSettings = new Settings | |||
const saveHandler = { | |||
get(target, property, receiver) { | |||
@@ -394,13 +401,19 @@ const saveHandler = { | |||
return Reflect.get(target, property, receiver) | |||
} | |||
}, | |||
set(target, property, value, receiver) { | |||
const response = Reflect.set(target, property, value, receiver) | |||
theSettings.save() | |||
return response | |||
}, | |||
defineProperty(target, property, descriptor) { | |||
settingsRaw.save() | |||
return Reflect.defineProperty(target, property, descriptor) | |||
const response = Reflect.defineProperty(target, property, descriptor) | |||
theSettings.save() | |||
return response | |||
}, | |||
} | |||
const settingsHandler = { | |||
const handler = { | |||
get(target, property, receiver) { | |||
try { | |||
if (property in target) { | |||
@@ -413,51 +426,12 @@ const settingsHandler = { | |||
// eslint-disable-next-line no-empty | |||
} catch (err) { } | |||
if (property in target.payload) { | |||
return target.payload[property] | |||
} | |||
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) { | |||
return obj[prop] | |||
} | |||
if (prop in obj.payload) { | |||
return obj.payload[prop] | |||
} | |||
return undefined | |||
}, | |||
set: (obj, prop, value) => { | |||
console.log({ | |||
prop, | |||
value, | |||
}) | |||
if (!isNil(obj.payload)) { | |||
if (prop in obj.payload) { | |||
obj.payload[prop] = value | |||
obj.save() | |||
return true | |||
} | |||
} | |||
obj[prop] = value | |||
return true | |||
}, | |||
}) | |||
*/ | |||
} | |||
export const settings = make(settingsRaw) | |||
export const settings = new Proxy(theSettings, handler) |
@@ -7,7 +7,7 @@ import deferred from 'deferred' | |||
import { getAppResourcesPath } from './paths' | |||
import { AppError } from '../app-error' | |||
const logger = require('logplease').create('electron:modules:tools:fs') | |||
const logger = require('@dreamnet/logplease').create('electron:modules:tools:fs') | |||
// eslint-disable-next-line node/no-deprecated-api | |||
export * from 'fs-extra' |
@@ -19,7 +19,9 @@ import { settings } from '../settings' | |||
* @param {string} name Name of the base path: https://electronjs.org/docs/all#appgetpathname | |||
* @param {...string} args Series of path segments to join into one path | |||
*/ | |||
export const getPath = (name, ...args) => join(app.getPath(name), ...args) | |||
export function getPath(name, ...args) { | |||
return join(app.getPath(name), ...args) | |||
} | |||
/** | |||
* |
@@ -16,7 +16,7 @@ import * as fs from 'fs-extra' | |||
import { getPowerPath } from './paths' | |||
import { settings } from '../settings' | |||
const logger = require('logplease').create('power') | |||
const logger = require('@dreamnet/logplease').create('power') | |||
export function exec(args, options = {}) { | |||
args.push('--debug') | |||
@@ -25,7 +25,7 @@ export function exec(args, options = {}) { | |||
// python script | |||
args.unshift('main.py') | |||
logger.debug('Spawning Python script.', { | |||
logger.debug('[Python] Running:', { | |||
args, | |||
options, | |||
}) | |||
@@ -36,10 +36,7 @@ export function exec(args, options = {}) { | |||
}) | |||
} | |||
logger.debug('Spawning executable.', { | |||
args, | |||
options, | |||
}) | |||
logger.debug('Running:', args) | |||
return spawn(getPowerPath('dreampower'), args, { | |||
cwd: getPowerPath(), | |||
@@ -47,12 +44,60 @@ export function exec(args, options = {}) { | |||
}) | |||
} | |||
/** | |||
* | |||
* @param {Array} args | |||
* @param {EventBus} events | |||
*/ | |||
export function nudify(args, events, outputFile) { | |||
const process = exec(args) | |||
let cancelled = false | |||
process.on('error', (error) => { | |||
logger.error(error) | |||
events.emit('error', null, error) | |||
}) | |||
process.stdout.on('data', (output) => { | |||
const stdout = output.toString().trim().split('\n') | |||
events.emit('stdout', null, stdout) | |||
}) | |||
process.stderr.on('data', (output) => { | |||
logger.warn(`stderr: ${output}`) | |||
events.emit('stderr', null, output) | |||
}) | |||
process.on('close', (code) => { | |||
logger.info(`DreamPower exited with code ${code}`) | |||
events.emit('close', null, code) | |||
if (cancelled) { | |||
events.emit('cancelled') | |||
} else if (code === 0 || isNil(code)) { | |||
if (fs.existsSync(outputFile.path)) { | |||
events.emit('success') | |||
} else { | |||
events.emit('fail', null, true) | |||
} | |||
} else { | |||
events.emit('fail', null, false) | |||
} | |||
}) | |||
events.on('cancel', () => { | |||
cancelled = true | |||
process.stdin.pause() | |||
process.kill() | |||
}) | |||
} | |||
/** | |||
* | |||
* @param {PhotoRun} run | |||
*/ | |||
export const transform = (run) => { | |||
// Independent preferences for the photo | |||
// Preferences for the photo | |||
const { preferences } = run | |||
const { fileFinal, scaleMode, overlay } = run.photo | |||
@@ -100,52 +145,14 @@ export const transform = (run) => { | |||
args.push('--vsize', preferences.body.vagina.size) | |||
args.push('--hsize', preferences.body.pubicHair.size) | |||
logger.info('Spawning DreamPower.', { | |||
input: inputFilepath, | |||
output: outputFilepath, | |||
args, | |||
}) | |||
const process = exec(args) | |||
const bus = (new EventBus) | |||
process.on('error', (error) => { | |||
logger.error(error) | |||
bus.emit('error', null, error) | |||
}) | |||
process.stdout.on('data', (output) => { | |||
const stdout = output.toString().trim().split('\n') | |||
bus.emit('stdout', null, stdout) | |||
}) | |||
process.stderr.on('data', (output) => { | |||
logger.warn(`stderr: ${output}`) | |||
bus.emit('stderr', null, output) | |||
}) | |||
process.on('close', (code) => { | |||
logger.info(`DreamPower exited with code ${code}`) | |||
bus.emit('close', null, code) | |||
const events = (new EventBus) | |||
if (code === 0 || isNil(code)) { | |||
if (fs.existsSync(run.outputFile.path)) { | |||
bus.emit('success') | |||
} else { | |||
bus.emit('fail', null, true) | |||
} | |||
} else { | |||
bus.emit('fail', null, false) | |||
} | |||
}) | |||
bus.on('kill', () => { | |||
process.stdin.pause() | |||
process.kill() | |||
}) | |||
setTimeout(() => { | |||
// Give time for the renderer to receive the events object. | |||
nudify(args, events, run.outputFile) | |||
}, 10) | |||
return bus | |||
return events | |||
} | |||
/** |
@@ -13,7 +13,7 @@ import { | |||
import si from 'systeminformation' | |||
import isOnline from 'is-online' | |||
const logger = require('logplease').create('system') | |||
const logger = require('@dreamnet/logplease').create('system') | |||
class System { | |||
/** |
@@ -1,8 +1,7 @@ | |||
const { remote } = require('electron') | |||
const { make } = require('./modules/settings') | |||
const util = remote.require('electron-util') | |||
const { settingsRaw } = remote.require('./modules/settings') | |||
const { settings } = remote.require('./modules/settings') | |||
const tools = remote.require('./modules/tools') | |||
const ngrok = remote.require('./modules/ngrok') | |||
@@ -10,7 +9,7 @@ const ngrok = remote.require('./modules/ngrok') | |||
window.$provider = { | |||
...tools, | |||
settings: make(settingsRaw), | |||
settings, | |||
ngrok, | |||
api: util.api, |
@@ -1,13 +1,15 @@ | |||
<template> | |||
<div class="layout"> | |||
<layout-topbar /> | |||
<!-- Window Buttons --> | |||
<LayoutTopbar /> | |||
<layout-navbar /> | |||
<!-- Navigation --> | |||
<LayoutNavbar /> | |||
<layout-navigation v-if="false" /> | |||
<layout-jobbar /> | |||
<!-- Queue --> | |||
<LayoutQueuebar /> | |||
<!-- Content --> | |||
<div id="layout-content" class="layout__content"> | |||
<nuxt /> | |||
</div> |
@@ -1,7 +1,9 @@ | |||
<template> | |||
<div class="layout"> | |||
<layout-topbar /> | |||
<!-- Window Buttons --> | |||
<LayoutTopbar /> | |||
<!-- Content --> | |||
<div id="layout-content" class="layout__content"> | |||
<nuxt /> | |||
</div> |
@@ -1,40 +0,0 @@ | |||
// 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' | |||
/** | |||
* 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 (!requirements.power.installed || !requirements.power.compatible) { | |||
// DreamPower is missing | |||
if ( | |||
!route.path.includes('/settings') | |||
&& route.path !== '/about' | |||
) { | |||
redirect('/about') | |||
} | |||
return | |||
} | |||
if (!requirements.power.checkpoints) { | |||
// Checkpoints are missing | |||
if (route.path !== '/about') { | |||
redirect('/about#checkpoints') | |||
} | |||
} | |||
*/ | |||
} |
@@ -7,12 +7,10 @@ | |||
// | |||
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019. | |||
import { requirements } from '~/modules/system' | |||
const { wizard } = $provider.settings | |||
import { settings, requirements } from '~/modules/system' | |||
export default function ({ route, redirect }) { | |||
window.$redirect = redirect | |||
const { wizard } = settings | |||
if (!wizard.welcome) { | |||
if (route.path !== '/wizard/welcome') { | |||
@@ -51,14 +49,4 @@ export default function ({ route, redirect }) { | |||
redirect('/wizard/telemetry') | |||
} | |||
} | |||
/* | |||
if (!wizard.user) { | |||
if (route.path !== '/wizard/user') { | |||
redirect('/wizard/user') | |||
} | |||
return | |||
} | |||
*/ | |||
} |
@@ -1,33 +1,34 @@ | |||
import _ from 'lodash' | |||
import { isString } from 'lodash' | |||
import tippy from 'tippy.js' | |||
import { NudifyStore } from '~/modules/nudify' | |||
import { settings } from '~/modules/system' | |||
/** | |||
* @mixin | |||
*/ | |||
export default { | |||
directives: { | |||
/** | |||
* v-tooltip. | |||
* Tooltip creation. | |||
*/ | |||
tooltip: { | |||
inserted(el, binding) { | |||
let settings = {} | |||
let options = {} | |||
if (_.isString(binding.value)) { | |||
settings.content = binding.value | |||
if (isString(binding.value)) { | |||
options.content = binding.value | |||
} else { | |||
settings = binding.value | |||
options = binding.value | |||
} | |||
tippy(el, settings) | |||
tippy(el, options) | |||
}, | |||
}, | |||
}, | |||
created() { | |||
window.$router = this.$router | |||
}, | |||
filters: {}, | |||
data: () => ({ | |||
$nudify: NudifyStore, | |||
$settings: $provider.settings, | |||
$settings: settings, | |||
}), | |||
} |
@@ -1,8 +1,7 @@ | |||
import _ from 'lodash' | |||
const debug = require('debug').default('app:mixins:vmodel') | |||
import { cloneDeep, isEqual, isNative } from 'lodash' | |||
/** | |||
* Helper to handle custom v-model | |||
* @mixin | |||
*/ | |||
export default { | |||
@@ -17,66 +16,44 @@ export default { | |||
data: () => ({ | |||
/** | |||
* Contains the current value, this variable must be changed within the component. | |||
* Current value, this is the variable that must be changed. | |||
*/ | |||
currentValue: null, | |||
}), | |||
created() { | |||
// Initial value | |||
this.currentValue = _.cloneDeep(this.value) | |||
}, | |||
methods: { | |||
onChange() { | |||
// nothing | |||
}, | |||
$forceCurrentValueUpdate() { | |||
debug('$currentValue has changed, updating the v-model', { | |||
oldValue: this.value, | |||
newValue: this.currentValue, | |||
}) | |||
this.$emit('input', this.currentValue) | |||
this.onChange(this.currentValue) | |||
}, | |||
// initial value. | |||
if (!isNative(this.value)) { | |||
this.currentValue = this.value | |||
} else { | |||
this.currentValue = cloneDeep(this.value) | |||
} | |||
}, | |||
watch: { | |||
// The local value has changed, update the v-model | |||
/** | |||
* Local value changed, update the v-model. | |||
*/ | |||
currentValue: { | |||
handler(value) { | |||
if (_.isEqual(this.value, value)) { | |||
if (isEqual(this.value, value)) { | |||
return | |||
} | |||
// this.$forceCurrentValueUpdate() | |||
debug('$currentValue has changed, updating the v-model', { | |||
oldValue: this.value, | |||
newValue: value, | |||
}) | |||
this.$emit('input', value) | |||
this.onChange(value) | |||
}, | |||
deep: true, | |||
}, | |||
// The v-model value has changed, update the local value | |||
/** | |||
* v-model value changed, update the local value. | |||
*/ | |||
value(value) { | |||
if (_.isEqual(this.currentValue, value)) { | |||
if (isEqual(this.currentValue, value)) { | |||
return | |||
} | |||
debug('v-model value has changed, updating currentValue', { | |||
oldValue: this.currentValue, | |||
newValue: value, | |||
}) | |||
this.currentValue = value | |||
this.onChange(value) | |||
}, | |||
}, | |||
} |
@@ -1,219 +0,0 @@ | |||
// 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, isObject, isArray, attempt, | |||
} from 'lodash' | |||
import { mapStackTrace } from 'sourcemapped-stacktrace' | |||
import Swal from 'sweetalert2' | |||
import { logrocket, rollbar } from '~/modules/services' | |||
const logger = require('logplease').create('error:renderer') | |||
const { app } = $provider.api | |||
/** | |||
* @typedef {Object} ErrorOptions | |||
* @property {string} title | |||
* @property {string} level | |||
* @property {Error} error | |||
* @property {boolean} fatal | |||
* @property {boolean} quiet | |||
*/ | |||
export class AppError extends Error { | |||
/** | |||
* @type {ErrorOptions} | |||
*/ | |||
options = { | |||
title: null, | |||
message: null, | |||
level: 'error', | |||
error: null, | |||
fatal: false, | |||
quiet: false, | |||
} | |||
/** | |||
* @type {boolean} | |||
*/ | |||
reported = false | |||
/** | |||
* | |||
* @param {string} message | |||
* @param {ErrorOptions} options | |||
*/ | |||
constructor(message, options = {}) { | |||
if (isError(message)) { | |||
// that's better. | |||
options.error = message | |||
message = message.message | |||
} | |||
const { error } = options | |||
if (isError(error)) { | |||
// we want this error to be the closest to the original | |||
super(error.message) | |||
if (error.options) { | |||
// inherit error options. | |||
this.options = error.options | |||
} | |||
} else if (isString(message)) { | |||
super(message) | |||
} else { | |||
super() | |||
} | |||
this.options = { | |||
...this.options, | |||
...options, | |||
message, | |||
} | |||
if (this.options.level === 'warning') { | |||
// warning does not exist in logger. | |||
this.options.level = 'warn' | |||
} | |||
} | |||
/** | |||
* Copy the original error information. | |||
*/ | |||
async copyError() { | |||
const { error } = this.options | |||
if (!isError(error)) { | |||
return | |||
} | |||
// 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 }) | |||
}) | |||
// copy pasta | |||
this.name = error.name | |||
this.stack = await getStack() | |||
} | |||
/** | |||
* Report the error to the logger, bug and session tracking services. | |||
*/ | |||
report() { | |||
const { level, error } = this.options | |||
let rollbarResponse | |||
// logger. | |||
logger[level](this) | |||
// 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) | |||
} | |||
} | |||
} | |||
/** | |||
* Show the error to the user. | |||
*/ | |||
show() { | |||
let icon = 'error' | |||
if (this.level === 'warning' || this.level === 'warn') { | |||
icon = 'warning' | |||
} | |||
if (this.level === 'info') { | |||
icon = 'info' | |||
} | |||
Swal.fire({ | |||
title: this.options.title, | |||
html: `${this.options.message}<br><br><pre>${this.message}</pre>`, | |||
icon, | |||
footer: this.reported ? `<code>๐ This problem has been reported to DreamNet.<br>It will be fixed as soon as possible.</code>` : null, | |||
}) | |||
} | |||
/** | |||
* | |||
*/ | |||
async handle() { | |||
const { quiet, fatal, error } = this.options | |||
await this.copyError(error) | |||
attempt(() => { | |||
this.report() | |||
if (!quiet) { | |||
this.show() | |||
} | |||
}) | |||
if (fatal) { | |||
app.quit() | |||
} | |||
} | |||
/** | |||
* | |||
*/ | |||
static handle(error) { | |||
let appError = error | |||
if (!(error instanceof AppError)) { | |||
let exception | |||
if (isError(error)) { | |||
exception = error | |||
} else if (isObject(error) || isArray(error)) { | |||
exception = new Error(JSON.stringify(error)) | |||
} else { | |||
exception = new Error(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() | |||
} | |||
} |
@@ -1,62 +1,54 @@ | |||
[ | |||
{ | |||
"error": "Found no NVIDIA driver on your system", | |||
"message": "Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from [here](http://www.nvidia.com/Download/index.aspx). If you don't have an NVIDIA GPU please change the Device option in **Settings** to **CPU**.", | |||
"level": "debug" | |||
"query": "Found no NVIDIA driver on your system", | |||
"message": "Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed the latest driver." | |||
}, | |||
{ | |||
"error": "The NVIDIA driver on your system is too old", | |||
"message": "The NVIDIA driver installed on your system is too old! If the drivers are up to date then your GPU may not be compatible. You can also change the device option in **Settings** to **CPU**.", | |||
"level": "debug" | |||
"query": "The NVIDIA driver on your system is too old", | |||
"message": "The NVIDIA driver installed on your system is too old! If the drivers are up to date then your GPU is not compatible." | |||
}, | |||
{ | |||
"error": "no longer supports this GPU", | |||
"message": "DreamTime does not have support for your GPU. Please change the device option in **Settings** to **CPU**.", | |||
"level": "debug" | |||
"query": "no longer supports this GPU", | |||
"message": "DreamTime no longer supports your GPU." | |||
}, | |||
{ | |||
"error": "Buy new RAM!", | |||
"message": "You have run out of RAM on your system! Try a photo of smaller size or free all possible memory.", | |||
"level": "debug" | |||
"query": "Buy new RAM!", | |||
"message": "You have run out of RAM on your system! Try a photo of smaller size or close all the programs you can." | |||
}, | |||
{ | |||
"error": "CUDA out of memory", | |||
"message": "You have run out of VRAM on your GPU! Try a photo of smaller size or free all possible GPU use.", | |||
"level": "debug" | |||
"query": "CUDA out of memory", | |||
"message": "You have run out of VRAM on your GPU! Try a photo of smaller size or close all the programs you can." | |||