Merge pull request #293 from JsSucks/2.0.0-beta.4

beta 4 to master
This commit is contained in:
Alexei Stukov 2019-03-08 14:11:13 +02:00 committed by GitHub
commit 3219ff7c6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 1210 additions and 798 deletions

View File

@ -2,7 +2,7 @@
"name": "bdclient",
"description": "BetterDiscord client package",
"author": "Jiiks",
"version": "2.0.0-beta.3",
"version": "2.0.0-beta.4",
"homepage": "https://betterdiscord.net",
"license": "MIT",
"main": "dist/betterdiscord.client.js",

View File

@ -11,14 +11,13 @@
import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui';
import BdCss from './styles/index.scss';
import { Events, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules';
import { ClientLogger as Logger, ClientIPC, Utils } from 'common';
import { ClientLogger as Logger, ClientIPC, Utils, Axi } from 'common';
import { BuiltinManager, EmoteModule, ReactDevtoolsModule, VueDevtoolsModule, TrackingProtection, E2EE } from 'builtin';
import electron from 'electron';
import path from 'path';
import { setTimeout } from 'timers';
const tests = typeof PRODUCTION === 'undefined';
const ignoreExternal = true;
const ignoreExternal = tests && true;
class BetterDiscord {
@ -39,7 +38,7 @@ class BetterDiscord {
BdWebApi,
Connectivity,
Cache,
Logger, ClientIPC, Utils,
Logger, ClientIPC, Utils, Axi,
plugins: PluginManager.localContent,
themes: ThemeManager.localContent,

View File

@ -102,7 +102,7 @@ export default new class extends Module {
}
get version() {
return this.config.version;
return this.config.versions.core;
}
}

View File

@ -39,7 +39,7 @@ export default class Module {
}
setState(newState) {
const oldState = this.state;
const oldState = Object.assign({}, this.state);
Object.assign(this.state, newState);
if (this.stateChanged) this.stateChanged(oldState, newState);
}

View File

@ -8,81 +8,183 @@
* LICENSE file in the root directory of this source tree.
*/
import Events from './events';
import Globals from './globals';
import { ClientLogger as Logger } from 'common';
import request from 'request-promise-native';
import { Notifications } from 'ui';
import { Reflection, Globals } from 'modules';
export default new class {
import Events from './events';
import Module from './imodule';
export default new class extends Module {
get updates() { return this.state.updates }
get bdUpdates() { return this.state.updates.bd }
get error() { return null; }
get updatesAvailable() { return this.state.updatesAvailable; }
constructor() {
this.updatesAvailable = false;
this.latestVersion = undefined;
this.error = undefined;
this.init = this.init.bind(this);
this.checkForUpdates = this.checkForUpdates.bind(this);
super({
updatesAvailable: false,
error: null,
updates: { bd: [] },
updating: false
});
}
/**
* The interval to wait before checking for updates.
*/
get interval() {
return 60 * 1000 * 30;
bindings() {
this.restartNotif = this.restartNotif.bind(this);
this.reloadNotif = this.reloadNotif.bind(this);
this.startUpdate = this.startUpdate.bind(this);
this.setUpdateStatus = this.setUpdateStatus.bind(this);
this.testUi = this.testUi.bind(this);
}
init() {
this.updateInterval = setInterval(this.checkForUpdates, this.interval);
restartNotif() {
Notifications.add('Updates Finished!', 'Restart required.', [
{
text: 'Restart Later',
onClick: () => { setTimeout(this.restartNotif, 5 * 60000); return true; }
},
{
text: 'Restart Now',
onClick: () => {
try {
const { remote } = Globals.require('electron');
window.close();
Reflection.module.byProps('showToken', 'hideToken').showToken();
remote.app.relaunch();
remote.app.exit(0);
} catch (err) {
console.err(err);
return true;
}
}
}
]);
}
/**
* Installs an update.
* TODO
*/
async update() {
try {
await new Promise(resolve => setTimeout(resolve, 5000));
this.updatesAvailable = false;
this.latestVersion = Globals.version;
Events.emit('update-check-end');
} catch (err) {
this.error = err;
this.checkForUpdates();
throw err;
}
reloadNotif() {
Notifications.add('Updates Finished!', 'Reload required.', [
{
text: 'Reload Later',
onClick: () => { setTimeout(this.reloadNotif, 5 * 60000); return true; }
},
{
text: 'Reload Now',
onClick: () => {
document.location.reload();
}
}
]);
}
/**
* Checks for updates.
* @return {Promise}
*/
async checkForUpdates() {
if (this.updatesAvailable) return true;
Events.emit('update-check-start');
Logger.info('Updater', 'Checking for updates');
events(ipc) {
ipc.on('updater-checkForUpdates', () => {
if (this.state.updating) return; // We're already updating. Updater should be paused anyways at this point.
Events.emit('update-check-start');
});
try {
const response = await request({
uri: 'https://rawgit.com/JsSucks/BetterDiscordApp/master/package.json',
json: true
ipc.on('updater-noUpdates', () => {
if (this.state.updatesAvailable) return; // If for some reason we get this even though we have updates already.
this.setState({
updatesAvailable: false,
updates: {}
});
});
this.latestVersion = response.version;
Events.emit('update-check-end');
Logger.info('Updater', `Latest Version: ${response.version} - Current Version: ${Globals.version}`);
ipc.on('updater-updatesAvailable', (_, updates) => {
console.log(updates);
if (this.state.updating) return; // If for some reason we get more updates when we're already updating
updates.bd = updates.bd.map(update => {
update.text = `${update.id.charAt(0).toUpperCase()}${update.id.slice(1)}`;
update.hint = `Current: ${update.currentVersion} | Latest: ${update.version}`;
update.status = {
update: true,
updating: false,
updated: false,
error: null
};
if (this.latestVersion !== Globals.version) {
this.updatesAvailable = true;
Events.emit('updates-available');
return true;
return update;
});
this.setState({
updates,
updatesAvailable: true
});
});
ipc.on('updater-updated', (_, info) => {
const { reloadRequired, restartRequired } = info;
if (restartRequired) {
this.restartNotif();
return;
}
return false;
} catch (err) {
Events.emit('update-check-fail', err);
throw err;
if (reloadRequired) {
this.reloadNotif();
return;
}
});
ipc.on('updater-updateFinished', (_, update) => {
this.setUpdateStatus(update.id, 'updated', true);
});
ipc.on('updater-updateError', (_, update) => {
this.setUpdateStatus(update.id, 'error', update.error);
});
}
stateChanged(oldState, newState) {
if (!newState.updatesAvailable) return Events.emit('update-check-end');
if (!oldState.updatesAvailable && newState.updatesAvailable) {
Events.emit('updates-available');
Notifications.add('', 'Updates Available!', [
{
text: 'Ignore',
onClick: () => { return true; }
},
{
text: 'Show Updates',
onClick: () => {
Events.emit('bd-open-menu', 'updater');
return true;
}
}
]);
}
}
setUpdateStatus(updateId, statusChild, statusValue) {
for (const u of this.bdUpdates) {
if (u.id === updateId) {
u.status[statusChild] = statusValue;
return;
}
}
}
toggleUpdate(update) {
update.status.update = !update.status.update;
}
async startUpdate() {
console.log('start update');
const updates = { bd: [] };
for (const update of this.bdUpdates) {
if (update.status.update) {
update.status.updating = true;
updates.bd.push(update);
}
}
console.log(updates);
this.send('updater-startUpdate', updates);
}
testUi(updates) {
this.setState({
updates,
updatesAvailable: true
});
}
}

View File

@ -11,6 +11,7 @@
import jQuery from 'jquery';
import lodash from 'lodash';
import Vue from 'vue';
import { Axi } from 'common';
import request from 'request-promise-native';
@ -40,6 +41,8 @@ export default class {
*/
static get Vue() { return Vue }
static get axios() { return Axi.axios }
static get request() { return request }
static get Combokeys() { return Combokeys }

View File

@ -0,0 +1,9 @@
.bd-contentColumn .bd-devview {
display: grid;
grid-template-columns: 33% 33% 33%;
.bd-button {
font-size: 10px;
height: 20px;
}
}

View File

@ -10,3 +10,4 @@
@import './kvp';
@import './collection';
@import './e2ee';
@import './devview';

View File

@ -3,4 +3,22 @@
margin: 0 0 10px;
color: #fff;
}
.bd-settingSwitch {
.bd-spinner7 {
height: 24px;
}
.bd-updaterStatus {
text-align: right;
&.bd-err {
color: $colerr;
}
&.bd-ok {
color: $colok;
}
}
}
}

View File

@ -20,10 +20,11 @@
<SidebarItem :item="{text, type: 'header'}" />
<SidebarItem v-for="i in category" :key="i.id" :item="i" :active="item && i.id === item.id" @click="itemOnClick(i.id)" />
</template>
<SidebarItem v-if="superSecretMenu" :item="{ _type: 'button', text: 'Super Secret' }" :active="superSecretMenuActive" @click="itemOnClick('superSecretMenu')"/>
</Sidebar>
<div slot="sidebarfooter" class="bd-info">
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
<span class="bd-vtext">{{versionString}}</span>
<div @click="openGithub" v-tooltip="'GitHub'" class="bd-materialButton">
<MiGithubCircle size="16" />
</div>
@ -37,7 +38,8 @@
<ContentColumn slot="content">
<transition name="bd-contentcolumn" @before-enter="animating++" @after-enter="animating--" @enter-cancelled="animating--" @before-leave="animating++" @after-leave="animating--" @leave-cancelled="animating--">
<div v-if="item" :key="item.id">
<SuperSecretView v-if="superSecretMenuActive"/>
<div v-else-if="item" :key="item.id">
<template v-if="item.component">
<component :is="item.component" :SettingsWrapper="SettingsWrapper" />
</template>
@ -63,11 +65,11 @@
<script>
// Imports
import { Events, Settings } from 'modules';
import { Events, Settings, Globals, Reflection } from 'modules';
import { BdMenuItems } from 'ui';
import { shell } from 'electron';
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView } from './bd';
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView, SuperSecretView } from './bd';
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
export default {
@ -78,13 +80,15 @@
items: BdMenuItems.items,
Settings,
SettingsWrapper,
openMenuHandler: null
openMenuHandler: null,
superSecretMenu: false,
superSecretMenuActive: false
};
},
props: ['active'],
components: {
SidebarView, Sidebar, SidebarItem, ContentColumn,
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView,
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView, SuperSecretView,
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
},
computed: {
@ -96,10 +100,19 @@
category.push(item);
}
return categories;
},
versionString() {
return Globals.version;
}
},
methods: {
itemOnClick(id) {
if (id === 'superSecretMenu') {
this.item = 'supersecretmenu';
this.superSecretMenuActive = true;
return;
}
this.superSecretMenuActive = false;
this.item = this.items.find(item => item.id === id);
},
closeContent() {
@ -123,6 +136,10 @@
},
created() {
Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.items.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id));
try {
const currentUser = Reflection.module.byName('UserStore').getCurrentUser();
this.superSecretMenu = ['81388395867156480', '98003542823944192', '249746236008169473', '284056145272766465', '478559353516064769'].includes(currentUser.id)
} catch (err) {}
},
destroyed() {
if (this.openMenuHandler) Events.off('bd-open-menu', this.openMenuHandler);

View File

@ -0,0 +1,105 @@
/**
* BetterDiscord Developer View Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<SettingsWrapper headertext="Super Secret">
<div class="bd-flex bd-flexCol bd-devview">
<FormButton @click="forceUpdate">Force Update</FormButton>
<FormButton @click="debugConfig">Config Debug</FormButton>
<FormButton @click="testUpdateUi">Update UI Test</FormButton>
</div>
</SettingsWrapper>
</template>
<script>
import SettingsWrapper from './SettingsWrapper.vue';
import { FormButton } from '../common';
import { Globals, Events, Updater } from 'modules';
import { ClientIPC } from 'common';
export default {
data() {
return {
};
},
components: {
SettingsWrapper,
FormButton
},
methods: {
forceUpdate() {
ClientIPC.send('debug-updater-forceUpdate');
},
debugConfig() {
console.log(Globals);
},
testUpdateUi() {
Updater.testUi({
'bd': [
{
'id': 'update',
'version': '3.0.0',
'currentVersion': '2.0.0',
'text': 'Update test',
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
'status': {
'update': true,
'updating': false,
'updated': false,
'error': null
}
},
{
'id': 'updating',
'version': '3.0.0',
'currentVersion': '2.0.0',
'text': 'Updating test',
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
'status': {
'update': true,
'updating': true,
'updated': false,
'error': null
}
},
{
'id': 'updated',
'version': '3.0.0',
'currentVersion': '2.0.0',
'text': 'Updated test',
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
'status': {
'update': true,
'updating': true,
'updated': true,
'error': null
}
},
{
'id': 'error',
'version': '3.0.0',
'currentVersion': '2.0.0',
'text': 'Error test',
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
'status': {
'update': true,
'updating': true,
'updated': false,
'error': 'Failed to update.'
}
}
],
'haveUpdates': true
});
}
}
}
</script>

View File

@ -0,0 +1,28 @@
/**
* BetterDiscord Updater Status Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<div class="bd-settingSwitch">
<div class="bd-title">
<h3>{{item.text}}</h3>
<h3 class="bd-updaterStatus bd-err" v-if="item.status.error">Update Failed!</h3>
<h3 class="bd-updaterStatus bd-ok" v-else-if="item.status.updated">Done</h3>
<div class="bd-spinner7" v-else-if="item.status.updating" />
<h3 class="bd-updaterStatus" v-else>Unknown</h3>
</div>
<div class="bd-hint">{{item.hint}}</div>
</div>
</template>
<script>
export default {
props: ['item']
}
</script>

View File

@ -0,0 +1,28 @@
/**
* BetterDiscord Updater Switch Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<div class="bd-settingSwitch">
<div class="bd-title">
<h3>{{item.text}}</h3>
<div class="bd-switchWrapper" @click="() => toggle(item)">
<input type="checkbox" class="bd-switchCheckbox" />
<div class="bd-switch" :class="{'bd-checked': item.status.update}" />
</div>
</div>
<div class="bd-hint">{{item.hint}}</div>
</div>
</template>
<script>
export default {
props: ['item', 'toggle']
}
</script>

View File

@ -11,19 +11,22 @@
<template>
<SettingsWrapper headertext="Updates">
<div class="bd-flex bd-flexCol bd-updaterview">
<div v-if="error" class="bd-formItem">
<h5 style="margin-bottom: 10px;">Error installing updates</h5>
<div class="bd-err bd-preWrap"><div class="bd-pre">{{ error.formatted }}</div></div>
<div class="bd-formDivider"></div>
<div class="bd-settingsCategories">
<div class="bd-settingsCategory" v-if="bdUpdates && bdUpdates.length">
<div class="bd-formItem">
<h5>BetterDiscord</h5>
</div>
<div class="bd-formDivider"></div>
<div v-for="update in bdUpdates">
<UpdaterStatus :item="update" v-if="update.status.updating" />
<UpdaterToggle :item="update" :toggle="() => updater.toggleUpdate(update)" v-else />
<div class="bd-formDivider"></div>
</div>
</div>
</div>
<div class="bd-formButton bd-button" @click="update">
Update
</div>
<template v-if="updatesAvailable">
<p>Version {{ newVersion }} is available. You are currently running version {{ currentVersion }}.</p>
<FormButton :onClick="install" :loading="updating">Install</FormButton>
</template>
<template v-else>
<p>You're all up to date!</p>
</template>
</div>
</SettingsWrapper>
</template>
@ -32,7 +35,8 @@
import { Globals, Updater } from 'modules';
import { ClientLogger as Logger } from 'common';
import SettingsWrapper from './SettingsWrapper.vue';
import { FormButton } from '../common';
import UpdaterToggle from './UpdaterToggle.vue';
import UpdaterStatus from './UpdaterStatus.vue';
export default {
data() {
@ -44,26 +48,29 @@
},
components: {
SettingsWrapper,
FormButton
UpdaterToggle,
UpdaterStatus
},
computed: {
updatesAvailable() {
return this.updater.updatesAvailable;
},
newVersion() {
return this.updater.latestVersion;
return '2.0.0-beta.4';
},
error() {
return this.updater.error;
},
updates() {
return this.updater.updates;
},
bdUpdates() {
return this.updater.bdUpdates;
}
},
methods: {
async install() {
this.updating = true;
try {
await this.updater.update();
} catch (err) {}
this.updating = false;
update() {
this.updater.startUpdate();
}
}
}

View File

@ -4,5 +4,8 @@ export { default as CssEditorView } from './CssEditor.vue';
export { default as PluginsView } from './PluginsView.vue';
export { default as ThemesView } from './ThemesView.vue';
export { default as UpdaterView } from './UpdaterView.vue';
export { default as UpdaterStatus } from './UpdaterStatus.vue';
export { default as UpdaterToggle } from './UpdaterToggle.vue';
export { default as BdBadge } from './BdBadge.vue';
export { default as ConnectivityView } from './ConnectivityView.vue';
export { default as SuperSecretView } from './SuperSecretView.vue';

View File

@ -28,7 +28,6 @@ module.exports = {
},
externals: {
electron: 'require("electron")',
asar: 'require("asar")',
fs: 'require("fs")',
path: 'require("path")',
util: 'require("util")',

View File

@ -13,7 +13,10 @@ const config = {
},
plugins: [
new webpack.NamedModulesPlugin()
]
],
externals: {
asar: 'require("asar")'
}
};
module.exports = merge(baseconfig, config);

View File

@ -15,7 +15,10 @@ const config = {
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true)
})
]
],
externals: {
sparkplug: 'require("./sparkplug")'
}
};
module.exports = merge(baseconfig, config);

51
common/modules/axi.js Normal file
View File

@ -0,0 +1,51 @@
/**
* BetterDiscord axios wrapper
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import axios from 'axios';
export default class AxiosWrapper {
static get axios() { return axios; }
static get github() {
return this._github ? this._github : (
this._github = {
main: this.create('https://github.com'),
api: this.create('https://api.github.com')
}
);
}
static get zl() {
return this._zl ? this._zl : (this._zl = {
api: this.create('https://zl', 1000, this.zlHeaders),
cdn: this.create('https://zl', 1000, this.zlHeaders)
});
}
static create(baseUrl, timeout = 1000, headers = null) {
return axios.create({ baseURL: baseUrl, timeout, headers: headers ? headers : this.defaultHeaders });
}
static get defaultHeaders() {
return {
'User-Agent': 'BetterDiscordApp User'
};
}
static get zlHeaders() {
return {
'User-Agent': 'BetterDiscordApp User',
'X-ZL-Apikey': '1a20cce89a2dbd163fc9570f3246c20891e62b2818ada55f82fa3d1d96fa7ef4',
'X-ZL-User': 'anonymous'
}
}
}

View File

@ -3,3 +3,4 @@ export { default as Filters } from './filters';
export { default as Logger, ClientLogger } from './logger';
export { default as ClientIPC } from './bdipc';
export { default as AsyncEventEmitter } from './async-eventemitter';
export { default as Axi } from './axi';

View File

@ -2,7 +2,7 @@
"name": "bdcore",
"description": "BetterDiscord core package",
"author": "Jiiks",
"version": "2.0.0-beta.3",
"version": "2.0.0-beta.4",
"homepage": "https://betterdiscord.net",
"license": "MIT",
"main": "dist/main.js",

25
core/src/csp.json Normal file
View File

@ -0,0 +1,25 @@
{
"img-src": [
"https://cdn.betterttv.net",
"https://cdn.frankerfacez.com",
"https://i.imgur.com"
],
"style-src": [
"https://fonts.googleapis.com"
],
"script-src": [
"'sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4='",
"'sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU='",
"'sha256-VzDmLZ4PxPkOS/KY7ITzLQsSWhfCnvUrNculcj8UNgE='",
"'sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU='"
],
"connect-src": [
"https://github.com",
"https://api.github.com",
"https://betterdiscord.net",
"https://api.betterdiscord.net",
"https://cdn.betterdiscord.net",
"https://api.supersecretbdapiandcdn.net",
"https://cdn.supersecretbdapiandcdn.net"
]
}

3
core/src/csp.txt Normal file
View File

@ -0,0 +1,3 @@
React Devtools: sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4=
Vue Devtools: sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU=
Vue Detector: sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU=

View File

@ -8,11 +8,24 @@
* LICENSE file in the root directory of this source tree.
*/
/*PRODUCTION*/
const TESTS = typeof PRODUCTION === 'undefined';
const TEST_ARGS = () => {
const _basePath = path.resolve(__dirname, '..', '..');
const _baseDataPath = path.resolve(_basePath, 'tests');
const _baseDataPath = path.resolve(_basePath, 'tests');
const _corePkg = require(path.resolve(_basePath, 'core', 'package.json'));
const _clientPkg = require(path.resolve(_basePath, 'client', 'package.json'));
const _editorPkg = require(path.resolve(_basePath, 'editor', 'package.json'));
const coreVersion = _corePkg.version;
const clientVersion = _clientPkg.version;
const editorVersion = _editorPkg.version;
return {
coreVersion,
clientVersion,
editorVersion,
'options': {
'autoInject': true,
'commonCore': true,
@ -26,7 +39,7 @@ const TEST_ARGS = () => {
}
}
}
const TEST_EDITOR = true;
const TEST_EDITOR = TESTS && true;
import path from 'path';
import sass from 'node-sass';
@ -35,21 +48,14 @@ import deepmerge from 'deepmerge';
import ContentSecurityPolicy from 'csp-parse';
import keytar from 'keytar';
import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Editor, Database } from './modules';
import { FileUtils, BDIpc, Config, WindowUtils, Updater, Editor, Database } from './modules';
const packageJson = require(path.resolve(__dirname, 'package.json'));
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
let configProxy;
const CSP = {
'img-src': ['https://cdn.betterttv.net', 'https://cdn.frankerfacez.com'],
'script-src': [
`'sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4='`, // React Devtools
`'sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU='`, // Vue Devtools
`'sha256-VzDmLZ4PxPkOS/KY7ITzLQsSWhfCnvUrNculcj8UNgE=' 'sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU='` // Vue Detector
]
};
const CSP = TESTS ? require('../src/csp.json') : require('./csp.json');
class Comms {
constructor(bd) {
@ -195,6 +201,8 @@ export class BetterDiscord {
get config() { return this._config ? this._config : (this._config = new Config(this._args)); }
get window() { return this.windowUtils ? this.windowUtils.window : undefined; }
get editor() { return this._editor ? this._editor : (this._editor = new Editor(this, this.config.getPath('editor'))); }
get updater() { return this._updater ? this._updater : (this._updater = new Updater(this)); }
get sendToDiscord() { return this.windowUtils.send; }
constructor(args) {
if (TESTS) args = TEST_ARGS();
@ -209,13 +217,16 @@ export class BetterDiscord {
this.config.compatibility();
this.bindings();
this.parseClientPackage();
this.extraPaths();
this.parseClientPackage();
this.parseEditorPackage();
this.parseCorePackage();
this.database.init();
configProxy = () => this.config;
const autoInitComms = this.comms;
const autoInitEditor = this.editor;
this.updater.start();
this.init();
}
@ -280,7 +291,7 @@ export class BetterDiscord {
*/
parseClientPackage() {
const clientPath = this.config.getPath('client');
const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) :require(`${clientPath}/package.json`);
const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) : require(`${clientPath}/package.json`);
const { version } = clientPkg;
const main = TESTS ? 'betterdiscord.client.js' : clientPkg.main;
this.config.addPath('client_script', `${clientPath}/${main}`);
@ -288,6 +299,20 @@ export class BetterDiscord {
console.log(`[BetterDiscord] Client v${this.config.clientVersion} - ${this.config.getPath('client_script')}`);
}
parseCorePackage() {
const corePath = this.config.getPath('core');
const corePkg = TESTS ? require(`${path.resolve(corePath, '..')}/package.json`) : require(`${corePath}/package.json`);
const { version } = corePkg;
this.config.setCoreVersion(version);
}
parseEditorPackage() {
const editorPath = this.config.getPath('editor');
const editorPkg = TESTS ? require(`${path.resolve(editorPath, '..')}/package.json`) : require(`${editorPath}/package.json`);
const { version } = editorPkg;
this.config.setEditorVersion(version);
}
/**
* Add extra paths to config
*/

53
core/src/modules/axi.js Normal file
View File

@ -0,0 +1,53 @@
/**
* BetterDiscord axios wrapper
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import axios from 'axios';
export default class AxiosWrapper {
static get axios() { return axios; }
static get(url) { return axios.get(url) }
static get github() {
return this._github ? this._github : (
this._github = {
main: this.create('https://github.com'),
api: this.create('https://api.github.com')
}
);
}
static get zl() {
return this._zl ? this._zl : (this._zl = {
api: this.create('https://zl', 1000, this.zlHeaders),
cdn: this.create('https://zl', 1000, this.zlHeaders)
});
}
static create(baseUrl, timeout = 1000, headers = null) {
return axios.create({ baseURL: baseUrl, timeout, headers: headers ? headers : this.defaultHeaders });
}
static get defaultHeaders() {
return {
'User-Agent': 'BetterDiscordApp User'
};
}
static get zlHeaders() {
return {
'User-Agent': 'BetterDiscordApp User',
'X-ZL-Apikey': '1a20cce89a2dbd163fc9570f3246c20891e62b2818ada55f82fa3d1d96fa7ef4',
'X-ZL-User': 'anonymous'
}
}
}

View File

@ -16,12 +16,36 @@ export default class Config extends Module {
return this.args.version;
}
get versions() {
return {
core: this.coreVersion,
client: this.clientVersion,
editor: this.editorVersion
};
}
get coreVersion() {
return this.state.coreVersion;
}
get clientVersion() {
return this.args.clientVersion;
return this.state.clientVersion;
}
get editorVersion() {
return this.state.editorVersion;
}
setClientVersion(clientVersion) {
this.args.clientVersion = clientVersion;
this.state.clientVersion = clientVersion;
}
setCoreVersion(coreVersion) {
this.state.coreVersion = coreVersion;
}
setEditorVersion(editorVersion) {
this.state.editorVersion = editorVersion;
}
get paths() {
@ -41,6 +65,7 @@ export default class Config extends Module {
get config() {
return {
version: this.version,
versions: this.versions,
paths: this.paths
};
}

View File

@ -4,3 +4,4 @@ export { default as Config } from './config';
export { default as CSSEditor } from './csseditor';
export { default as Editor } from './editor';
export { default as Database } from './database';
export { default as Updater } from './updater';

View File

@ -11,6 +11,9 @@
/**
* Base Module that every non-static module should extend.
*/
import { default as BDIpc } from './bdipc';
export default class Module {
constructor(args) {
@ -24,6 +27,7 @@ export default class Module {
init() {
if (this.bindings) this.bindings();
if (this.setInitialState) this.setInitialState(this.state);
if (this.events) this.events(BDIpc);
}
set args(t) {}

287
core/src/modules/updater.js Normal file
View File

@ -0,0 +1,287 @@
/**
* BetterDiscord Updater Module
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
* All rights reserved.
* https://github.com/JsSucks - https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Module from './modulebase';
import { FileUtils } from './utils';
import semver from 'semver';
import Axi from './axi';
import zlib from 'zlib';
import tarfs from 'tar-fs';
const TEST_UPDATE = [
{
'id': 'core',
'version': '2.0.0-beta.5'
},
{
'id': 'client',
'version': '2.0.0-beta.5'
},
{
'id': 'editor',
'version': '0.4.1'
}
];
class ReleaseInfo {
constructor(versions) {
this.versions = versions;
}
get core() {
const f = this.files.find(f => f.id === 'core');
f.upToDate = semver.satisfies(this.versions.core, `>=${f.version}`, { includePrerelease: true });
f.currentVersion = this.versions.core;
return f;
}
get client() {
const f = this.files.find(f => f.id === 'client');
f.upToDate = semver.satisfies(this.versions.client, `>=${f.version}`, { includePrerelease: true });
f.currentVersion = this.versions.client;
return f;
}
get editor() {
const f = this.files.find(f => f.id === 'editor');
f.upToDate = semver.satisfies(this.versions.editor, `>=${f.version}`, { includePrerelease: true });
f.currentVersion = this.versions.editor;
return f;
}
test() {
this.files = TEST_UPDATE;
}
}
export default class Updater extends Module {
constructor(bd) {
super();
this.bd = bd;
}
bindings() {
this.checkForUpdates = this.checkForUpdates.bind(this);
this.checkForBdUpdates = this.checkForBdUpdates.bind(this);
this.updateAll = this.updateAll.bind(this);
this.updateFinished = this.updateFinished.bind(this);
this.start = this.start.bind(this);
}
events(ipc) {
ipc.on('updater-startUpdate', (_, updates) => {
clearInterval(this.updaterThread);
this.updateAll(updates);
});
ipc.on('debug-updater-forceUpdate', () => {
this.checkForUpdates(true);
});
}
async updateBd(update) {
try {
console.log('[BetterDiscord:Updater] Updating', update.id);
await this.downloadTarGz(`https://github.com/JsSucks/BetterDiscordApp${update.remote}`, this.bd.config.getPath('base'));
this.updateFinished(update);
// Cleanup
await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`);
} catch (err) {
console.log('[BetterDiscord:Updater] Failed to update', update.id);
console.log(err);
update.error = err;
this.bd.sendToDiscord('updater-updateError', update);
}
}
async updateAll(updates) {
const bd = updates.bd || [];
const plugins = updates.plugins || [];
const themes = updates.themes || [];
const modules = updates.modules || [];
this.restartRequired = this.reloadRequired = false;
this.finishedUpdates = 0;
this.totalUpdates = bd.length + plugins.length + themes.length + modules.length;
const renamed = [];
// TODO cleaner
if (bd.length) {
for (const update of bd) {
try {
await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`);
// Try to rename dirs first
await FileUtils.rn(this.bd.config.getPath(update.id), `${this.bd.config.getPath(update.id)}_old`);
renamed.push({ 'old': this.bd.config.getPath(update.id), 'new': `${this.bd.config.getPath(update.id)}_old`});
} catch (err) {
if (renamed.length) {
// Restore dirs
for (const r of renamed) {
await FileUtils.rn(r.new, r.old);
}
}
throw err;
}
}
for (const update of bd) {
this.updateBd(update);
}
}
}
updateFinished(update) {
if (update.id === 'core') this.restartRequired = true;
if (update.id === 'client') this.reloadRequired = true;
console.log('[BetterDiscord:Updater] Finished updating', update.id);
this.bd.sendToDiscord('updater-updateFinished', update);
this.finishedUpdates++;
if (this.finishedUpdates >= this.totalUpdates) {
this.bd.sendToDiscord('updater-updated', { restartRequired: this.restartRequired, reloadRequired: this.reloadRequired });
}
}
start(interval = 30) {
this.updaterThread = setInterval(this.checkForUpdates, interval * 60 * 1000);
}
validate(releaseInfo) {
return releaseInfo &&
typeof releaseInfo === 'object' &&
releaseInfo.files &&
Array.isArray(releaseInfo.files) &&
releaseInfo.files.length >= 4;
}
async latestRelease() {
try {
const release = await Axi.github.api.get('repos/JsSucks/BetterDiscordApp/releases/latest'); // TODO replace with config
const releaseInfoAsset = release.data.assets.find(asset => asset.name === 'releaseinfo.json');
const releaseInfo = await Axi.get(releaseInfoAsset['browser_download_url']);
if (this.validate(releaseInfo.data)) return releaseInfo.data;
return this.latestReleaseFallback();
} catch (err) {
console.log(err);
return this.latestReleaseFallback();
}
}
async latestReleaseFallback() {
console.log('fallback');
}
async checkForBdUpdates(forced = false) {
try {
const { coreVersion, clientVersion, editorVersion } = this.bd.config;
const releaseInfo = new ReleaseInfo({ core: coreVersion, client: clientVersion, editor: editorVersion });
const latestRelease = await this.latestRelease();
if (forced) {
latestRelease.files = latestRelease.files.map(file => {
file.version = '10.0.0';
return file;
});
}
releaseInfo.files = latestRelease.files;
const updates = [];
const { core, client, editor } = releaseInfo;
if (!core.upToDate) updates.push(core);
if (!client.upToDate) updates.push(client);
if (!editor.upToDate) updates.push(editor);
return updates;
} catch (err) {
console.log('[BetterDiscord:Updater]', err);
return [];
}
}
async checkForUpdates(forced = false) {
console.log('[BetterDiscord:Updater] Checking for updates');
this.bd.sendToDiscord('updater-checkForUpdates', '');
try {
const bd = await this.checkForBdUpdates(forced);
const updates = { bd, haveUpdates: false };
if (bd.length) updates.haveUpdates = true;
if (!updates.haveUpdates) {
this.bd.sendToDiscord('updater-noUpdates', '');
return true;
}
this.bd.sendToDiscord('updater-updatesAvailable', updates);
return true;
} catch (err) {
console.log('[BetterDiscord:Updater]', err);
this.bd.sendToDiscord('updater-error', err);
return 'err';
}
}
async downloadTarGz(url, dest, responseType = 'stream', headers = null) {
try {
const stream = await Axi.axios({
url,
type: 'GET',
responseType,
headers: headers ||
{
'Content-Type': 'application/octet-stream',
'Accept': 'application/octet-stream'
}
});
return new Promise((resolve, reject) => {
stream.data.pipe(zlib.createGunzip()).pipe(tarfs.extract(dest)).on('finish', resolve).on('error', reject);
});
} catch (err) {
throw err;
}
}
debug(releaseInfo) {
const { core, client, editor } = releaseInfo;
if (!core.upToDate) {
console.log(`[BetterDiscord:Updater] Core update available: ${core.currentVersion} > ${core.version}`);
} else {
console.log(`[BetterDiscord:Updater] Core up to date: ${core.currentVersion} = ${core.version}`);
}
if (!client.upToDate) {
console.log(`[BetterDiscord:Updater] Client update available: ${client.currentVersion} > ${client.version}`);
} else {
console.log(`[BetterDiscord:Updater] Client up to date: ${client.currentVersion} = ${client.version}`);
}
if (!editor.upToDate) {
console.log(`[BetterDiscord:Updater] Editor update available: ${editor.currentVersion} > ${editor.version}`);
} else {
console.log(`[BetterDiscord:Updater] Editor up to date: ${editor.currentVersion} = ${editor.version}`);
}
}
}

View File

@ -1,23 +0,0 @@
{
"name": "bdcsseditor",
"description": "BetterDiscord css editor package",
"author": "Jiiks",
"version": "0.4.0",
"homepage": "https://betterdiscord.net",
"license": "MIT",
"main": "dist/csseditor.js",
"contributors": [
"Jiiks",
"Pohky"
],
"repository": {
"type": "git",
"url": "https://github.com/JsSucks/BetterDiscordApp.git"
},
"private": false,
"scripts": {
"build": "webpack --progress --colors",
"watch": "webpack --progress --colors --watch",
"release": "webpack --progress --colors --config=webpack.production.config.js"
}
}

View File

@ -1,191 +0,0 @@
<template>
<div class="container">
<div class="titlebar">
<div class="draggable"></div>
<div class="icon">
<div class="inner"></div>
</div>
<div class="title">CSS Editor</div>
<div class="flex-spacer"></div>
<div class="controls">
<button :class="{active: alwaysOnTop}" ref="aot" title="Toggle always on top" @click="toggleaot">P</button>
<button title="Close CSS Editor" @click="close">X</button>
</div>
</div>
<div id="spinner" v-if="loading">
<div class="valign">Loading Please Wait...</div>
</div>
<div id="editor" class="editor">
<codemirror ref="mycm" :options="cmOptions" @input="cmOnChange" />
</div>
<div class="parser-error" v-if="error">{{ error.formatted }}</div>
<div class="tools">
<div class="flex-row">
<button @click="save">Save</button>
<button @click="update">Update</button>
<div class="flex-spacer"></div>
<div id="chkboxLiveUpdate">
<label><input type="checkbox" @click="toggleLiveUpdate" v-model="liveUpdate" /><span>Live Update</span></label>
</div>
</div>
</div>
</div>
</template>
<script>
import { ClientIPC } from 'common';
import { remote } from 'electron';
import 'codemirror/addon/scroll/simplescrollbars.js';
import 'codemirror/mode/css/css.js';
import 'codemirror/addon/hint/css-hint.js';
import 'codemirror/addon/search/search.js';
import 'codemirror/addon/search/searchcursor.js';
import 'codemirror/addon/search/jump-to-line.js';
import 'codemirror/addon/dialog/dialog.js';
import 'codemirror/addon/hint/show-hint.js';
const ExcludedIntelliSenseTriggerKeys = {
'8': 'backspace',
'9': 'tab',
'13': 'enter',
'16': 'shift',
'17': 'ctrl',
'18': 'alt',
'19': 'pause',
'20': 'capslock',
'27': 'escape',
'33': 'pageup',
'34': 'pagedown',
'35': 'end',
'36': 'home',
'37': 'left',
'38': 'up',
'39': 'right',
'40': 'down',
'45': 'insert',
'46': 'delete',
'91': 'left window key',
'92': 'right window key',
'93': 'select',
'107': 'add',
'109': 'subtract',
'110': 'decimal point',
'111': 'divide',
'112': 'f1',
'113': 'f2',
'114': 'f3',
'115': 'f4',
'116': 'f5',
'117': 'f6',
'118': 'f7',
'119': 'f8',
'120': 'f9',
'121': 'f10',
'122': 'f11',
'123': 'f12',
'144': 'numlock',
'145': 'scrolllock',
'186': 'semicolon',
'187': 'equalsign',
'188': 'comma',
'189': 'dash',
'190': 'period',
'191': 'slash',
'192': 'graveaccent',
'220': 'backslash',
'222': 'quote'
};
export default {
data() {
return {
loading: true,
codeMirror: null,
alwaysOnTop: false,
liveUpdate: false,
cmOptions: {
indentUnit: 4,
tabSize: 4,
mode: 'text/x-scss',
lineNumbers: true,
theme: 'material',
scrollbarStyle: 'overlay',
extraKeys: {
'Ctrl-Space': 'autocomplete'
},
dialog: {
'position': 'bottom'
}
},
error: null
}
},
computed: {
codemirror() {
return this.$refs.mycm.codemirror;
},
CodeMirror() {
return this.$refs.mycm;
}
},
created() {
ClientIPC.on('set-scss', (_, scss) => this.setScss(scss));
ClientIPC.on('scss-error', (_, err) => {
this.error = err;
this.$forceUpdate();
if (err)
console.error('SCSS parse error:', err);
});
ClientIPC.on('set-liveupdate', (e, liveUpdate) => this.liveUpdate = liveUpdate);
},
mounted() {
this.codemirror.on('keyup', this.cmOnKeyUp);
(async () => {
this.setScss(await ClientIPC.sendToDiscord('get-scss'));
this.liveUpdate = await ClientIPC.sendToDiscord('get-liveupdate');
})();
},
watch: {
liveUpdate(liveUpdate) {
ClientIPC.sendToDiscord('set-liveupdate', liveUpdate);
}
},
methods: {
save() {
const scss = this.codemirror.getValue();
ClientIPC.sendToDiscord('save-scss', scss);
},
update() {
const scss = this.codemirror.getValue();
ClientIPC.sendToDiscord('update-scss', scss);
},
toggleaot() {
this.alwaysOnTop = !this.alwaysOnTop;
remote.getCurrentWindow().setAlwaysOnTop(this.alwaysOnTop);
},
close() {
window.close();
},
setScss(scss) {
this.loading = false;
this.codemirror.setValue(scss || '');
},
cmOnChange(value) {
if(this.liveUpdate) ClientIPC.sendToDiscord('update-scss', value);
},
cmOnKeyUp(editor, event) {
if (event.ctrlKey) return;
if (ExcludedIntelliSenseTriggerKeys[event.keyCode]) return;
cmCommands.autocomplete(editor, null, { completeSingle: false });
},
toggleLiveUpdate(e) {
this.liveUpdate = !this.liveUpdate;
}
}
}
</script>

View File

@ -1,27 +0,0 @@
// const styles = require('./styles/index.scss');
import Vue from 'vue';
import VueCodemirror from 'vue-codemirror';
import Editor from './Editor.vue';
import styles from './styles/index.scss';
Vue.use(VueCodemirror, {});
window.cmCommands = VueCodemirror.CodeMirror.commands;
const mount = document.createElement('div');
mount.classList.add('container');
document.body.appendChild(mount);
const vue = new Vue({
el: mount,
components: { Editor },
template: '<Editor/>'
});
const style = document.createElement('style');
style.id = 'bd-main';
style.type = 'text/css';
style.appendChild(document.createTextNode(styles));
document.head.appendChild(style);

View File

@ -1,105 +0,0 @@
.CodeMirror-scroll {
cursor: text;
}
.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler {
background: #38444a;
}
.CodeMirror-overlayscroll-horizontal div,
.CodeMirror-overlayscroll-vertical div {
background: rgb(41, 43, 47);
}
.CodeMirror-overlayscroll-horizontal,
.CodeMirror-overlayscroll-horizontal div {
height: 10px;
}
.CodeMirror-overlayscroll-vertical,
.CodeMirror-overlayscroll-vertical div {
width: 10px;
}
.CodeMirror-scrollbar-filler {
width: 10px;
height: 10px;
background: rgb(41, 43, 47);
}
.cm-s-material.CodeMirror {
background: #36393f;
}
.CodeMirror-scroll {
cursor: text;
}
.cm-s-material .CodeMirror-gutters {
background: #292b2f;
}
.CodeMirror-gutter {
min-width: 34px;
border-right: 1px solid hsla(218,5%,47%,.3);
cursor: default;
}
.CodeMirror-hints {
/*background: #1e262a;*/
background: #292b2f;
box-shadow: 2px 3px 5px rgba(4, 4, 4, 0.22);
border: 1px solid #262f33;
&::-webkit-scrollbar {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,.4);
border-color: transparent;
}
&::-webkit-scrollbar-thumb,
&::-webkit-scrollbar-track {
background-clip: padding-box;
border-width: 3px;
border-style: solid;
border-radius: 7px;
}
&::-webkit-scrollbar-track {
background-color: transparent;
border-color: transparent;
}
}
.CodeMirror-linenumber,
.CodeMirror-line {
padding: 0 5px !important;
}
.CodeMirror-linenumber {
cursor: text;
}
.cm-s-material .CodeMirror-linenumber {
color: #f6f6f7;
}
.CodeMirror-hint {
color: #bac9d2;
}
li.CodeMirror-hint-active {
color: #bac9d2;
/*background: #3b4950;*/
background: #36393f;
}
.CodeMirror-dialog-top {
bottom: 0;
top: auto;
border: none;
background: #1e262a;
}

View File

@ -1,17 +0,0 @@
.editor {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
.vue-codemirror {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
&, & .CodeMirror {
flex-grow: 1;
}
}
}

View File

@ -1,2 +0,0 @@
$logoSmallGw: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkltYWdlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGUgdHlwZT0idGV4dC9jc3MiPi5zdDB7ZGlzcGxheTpub25lO30uc3Qxe2Rpc3BsYXk6aW5saW5lO2ZpbGw6IzAyMDAzNTtzdHJva2U6IzAwMDAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9LnN0MntmaWxsOiMzRUNDOUU7fS5zdDN7ZmlsbDojRkZGRkZGO308L3N0eWxlPjxnIGlkPSJMYXllcl8yIiBjbGFzcz0ic3QwIj48cmVjdCB4PSItNjQiIHk9Ii0zMiIgY2xhc3M9InN0MSIgd2lkdGg9IjYxOCIgaGVpZ2h0PSI1NzIiLz48L2c+PGcgaWQ9IkxheWVyXzEiIHhtbG5zOnZlY3Rvcm5hdG9yPSJodHRwOi8vdmVjdG9ybmF0b3IuaW8iPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik03MCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3YyMzMuNkM0Mi43LDM5Ny43LDEzNy45LDQ5MywyNTYsNDkzYzI5LjcsMCw1OC02LjEsODMuNi0xN1YzNDEuNWMtMTksMjUuNi00OS4zLDQyLjItODMuNiw0Mi4yYy01Ny42LDAtMTA0LjEtNDYuNS0xMDQuMS0xMDQuMVY0Ni4xYzAtMTMuNy0xMy43LTI3LjMtMjcuMy0yNy4zSDcweiIvPjxwYXRoIGNsYXNzPSJzdDMiIGQ9Ik0zODcuNCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3Y0Ny4zQzMyOS4zLDc2LjIsMjkzLjksNjYuMywyNTYsNjYuM2MtMjkuOCwwLTU3LjksNi4zLTgzLjYsMTcuM3YxMzQuMmMxOS0yNS42LDQ5LjMtNDIuMiw4My42LTQyLjJjNTcuNiwwLDEwNC4xLDQ2LjUsMTA0LjEsMTA0LjF2MTg2LjJjNjUuMi0zNi40LDEwOS4yLTEwNiwxMDkuMi0xODYuMlY0Ni4xYzAtMTguOC0xMy43LTI3LjMtMjcuMy0yNy4zSDM4Ny40eiIvPjwvZz48L3N2Zz4=);
$bdicon: $logoSmallGw;

View File

@ -1,13 +0,0 @@
@import '../../../node_modules/codemirror/lib/codemirror.css';
@import '../../../node_modules/codemirror/theme/material.css';
@import '../../../node_modules/codemirror/addon/scroll/simplescrollbars.css';
@import '../../../node_modules/codemirror/addon/dialog/dialog.css';
@import '../../../node_modules/codemirror/addon/hint/show-hint.css';
@import './images.scss';
@import './main.scss';
@import './titlebar.scss';
@import './spinner.scss';
@import './editor.scss';
@import './tools.scss';
@import './codemirror.scss';

View File

@ -1,36 +0,0 @@
html, body {
margin: 0;
padding: 0;
max-height: 100%;
height: 100%;
background: #2c383e;
min-width: 700px;
min-height: 400px;
}
* {
outline: none;
}
.flex-spacer {
flex-grow: 1;
}
.flex-row {
display: flex;
flex-direction: row;
}
.valign {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.container {
display: flex;
flex-grow: 1;
flex-direction: column;
height: 100%;
}

View File

@ -1,14 +0,0 @@
#spinner {
background: rgba(51, 48, 48, 0.41);
position: absolute;
top: 34px;
left: 0;
right: 0;
bottom: 0;
color: #bac9d2;
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
font-weight: 600;
font-size: 2em;
z-index: 90000;
user-select: none;
}

View File

@ -1,71 +0,0 @@
.titlebar {
display: flex;
height: 25px;
padding: 4px 5px;
background: #292b2f;
border-bottom: 1px solid hsla(218,5%,47%,.3);
user-select: none;
cursor: default;
.icon {
width: 31px;
height: 25px;
.inner {
width: 25px;
height: 25px;
background-image: $bdicon;
background-size: 22px 22px;
background-repeat: no-repeat;
background-position: center;
}
}
.title {
color: #bac9d2;
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
line-height: 25px;
font-size: 15px;
}
.controls {
margin: 0 0 0 2px;
font-size: 0;
button {
-webkit-app-region: no-drag;
border-radius: 3px;
width: 25px;
font-size: 12px;
font-weight: 600;
background: #36393f;
color: #bac9d2;
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
transition: background-color .2s ease, color .2s ease;
cursor: default;
border: 0;
height: 25px;
z-index: 900062;
padding: 0;
margin: 0 0 0 4px;
&:hover {
background: #44474e;
color: #FFF;
}
&.active {
background: #3a71c1;
}
}
}
.draggable {
top: 0;
left: 0;
right: 63px;
position: absolute;
height: 33px;
-webkit-app-region: drag;
}
}

View File

@ -1,66 +0,0 @@
.parser-error {
padding: 4px 6px;
background: #292b2f;
border-top: 1px solid hsla(218,5%,47%,.3);
color: #d84040;
font-family: monospace;
white-space: pre-wrap;
font-size: 12px;
}
.tools {
height: 36px;
background: #292b2f;
border-top: 1px solid hsla(218,5%,47%,.3);
display: flex;
flex-direction: column;
user-select: none;
.flex-row {
flex-grow: 1;
padding: 4px 5px;
}
button {
border-radius: 3px;
width: 100px;
padding: 3px 10px;
font-size: 12px;
font-weight: 600;
background: #36393f;
color: #bac9d2;
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
transition: background-color .2s ease, color .2s ease;
cursor: pointer;
border: 0;
margin-right: 4px;
flex: 0 0 auto;
&:hover {
background: #44474e;
color: #fff;
}
}
#chkboxLiveUpdate {
padding: 3px 10px;
line-height: 22px;
flex: 0 0 auto;
label {
cursor: pointer;
}
input[type="checkbox"] {
margin: 0 6px 0 0;
cursor: pointer;
}
span {
font-size: 12px;
font-weight: 500;
color: #bac9d2;
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
}
}
}

View File

@ -1,43 +0,0 @@
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const vueLoader = {
test: /\.(vue)$/,
exclude: /node_modules/,
use: 'vue-loader'
};
const scssLoader = {
test: /\.(css|scss)$/,
use: ['css-loader', 'sass-loader']
};
module.exports = {
entry: './src/index.js',
mode: 'development',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'csseditor.js'
},
module: {
rules: [vueLoader, scssLoader]
},
externals: {
electron: 'window.require("electron")',
fs: 'window.require("fs")',
util: 'window.require("util")',
process: 'require("process")'
},
resolve: {
alias: {
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
},
modules: [
path.resolve('..', 'node_modules'),
path.resolve('..', 'common', 'modules')
]
},
plugins: [
new VueLoaderPlugin()
]
};

View File

@ -1,47 +0,0 @@
const path = require('path');
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const vueLoader = {
test: /\.(vue)$/,
exclude: /node_modules/,
use: 'vue-loader'
};
const scssLoader = {
test: /\.(css|scss)$/,
use: ['css-loader', 'sass-loader']
};
module.exports = {
entry: './src/index.js',
mode: 'production',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'csseditor-release.js'
},
module: {
rules: [vueLoader, scssLoader]
},
externals: {
electron: 'window.require("electron")',
fs: 'window.require("fs")',
util: 'window.require("util")',
process: 'require("process")'
},
resolve: {
alias: {
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
},
modules: [
path.resolve('..', 'node_modules'),
path.resolve('..', 'common', 'modules')
]
},
plugins: [
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true)
}),
new VueLoaderPlugin()
]
};

View File

@ -5,7 +5,7 @@
"version": "0.4.0",
"homepage": "https://betterdiscord.net",
"license": "MIT",
"main": "dist/csseditor.js",
"main": "dist/editor.js",
"contributors": [
"Jiiks",
"Pohky"

View File

@ -4,6 +4,7 @@ import del from 'del';
import copy from 'gulp-copy';
import rename from 'gulp-rename';
import inject from 'gulp-inject-string';
import replace from 'gulp-replace';
import copydeps from './scripts/copydeps';
import file from 'gulp-file';
import editjson from 'gulp-json-editor';
@ -14,10 +15,10 @@ import editorpkg from './editor/package';
// core-release >
gulp.task('core-main', function () {
gulp.task('core-main', function() {
return pump([
gulp.src('core/dist/main.js'),
inject.after(`'use strict';\n`, 'const PRODUCTION = true;\n'),
replace('/*PRODUCTION*/', 'const PRODUCTION = true;'),
rename(`core.${corepkg.version}.js`),
gulp.dest('release/core')
]);
@ -36,27 +37,34 @@ gulp.task('core-pkg', function() {
]);
});
gulp.task('core-modules', function () {
gulp.task('core-modules', function() {
return pump([
gulp.src('core/dist/modules/**/*'),
copy('release/core', { prefix: 2 })
]);
});
gulp.task('core-sparkplug', function () {
gulp.task('core-sparkplug', function() {
return pump([
gulp.src('core/dist/sparkplug.js'),
gulp.dest('release/core')
]);
});
gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules'));
gulp.task('core-extras', function() {
return pump([
gulp.src(['core/src/csp.json']),
gulp.dest('release/core')
]);
});
gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules', 'core-extras'));
// < core-release
// client
gulp.task('client-main', function () {
gulp.task('client-main', function() {
return pump([
gulp.src('client/dist/*.client-release.js'),
rename(`client.${clientpkg.version}.js`),
@ -76,7 +84,7 @@ gulp.task('client-pkg', function() {
]);
});
gulp.task('client-sparkplug', function () {
gulp.task('client-sparkplug', function() {
return pump([
gulp.src('core/dist/sparkplug.js'),
gulp.dest('release/client')
@ -87,7 +95,7 @@ gulp.task('client-release', gulp.parallel('client-main', 'client-pkg', 'client-s
// Editor
gulp.task('editor-main', function () {
gulp.task('editor-main', function() {
return pump([
gulp.src('editor/dist/editor.release.js'),
rename(`editor.${editorpkg.version}.js`),
@ -95,10 +103,10 @@ gulp.task('editor-main', function () {
]);
});
gulp.task('editor-pkg', function () {
gulp.task('editor-pkg', function() {
return pump([
gulp.src('editor/package.json'),
editjson(function (pkg) {
editjson(function(pkg) {
pkg.main = `editor.${editorpkg.version}.js`;
delete pkg.scripts;
return pkg;
@ -118,18 +126,18 @@ gulp.task('node-modules', function() {
]);
});
gulp.task('node-sass-bindings', gulp.series(function () {
gulp.task('node-sass-bindings', gulp.series(function() {
return del(['release/node_modules/node-sass/vendor']);
}, function () {
}, function() {
return pump([
gulp.src('other/node_sass_bindings/**/*'),
copy('release/core/node_modules/node-sass/vendor', { prefix: 2 })
]);
}));
gulp.task('keytar-bindings', gulp.series(function () {
gulp.task('keytar-bindings', gulp.series(function() {
return del(['release/node_modules/keytar/build']);
}, function () {
}, function() {
return pump([
gulp.src('other/keytar/**/*'),
copy('release/core/node_modules/keytar/build/Release', { prefix: 2 })
@ -144,4 +152,4 @@ gulp.task('del-release', function() {
gulp.task('dependencies', gulp.series('node-modules', gulp.parallel('node-sass-bindings', 'keytar-bindings')));
gulp.task('build-release', gulp.parallel('core-release', 'client-release', 'editor-release', 'dependencies'));
gulp.task('release', gulp.series('del-release', 'build-release'));
gulp.task('release', gulp.series('del-release', 'build-release'));

Binary file not shown.

250
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "betterdiscord",
"version": "2.0.0-beta",
"version": "2.0.0-beta.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1583,6 +1583,15 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"axios": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": {
"follow-redirects": "^1.3.0",
"is-buffer": "^1.1.5"
}
},
"babel-loader": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz",
@ -1776,6 +1785,12 @@
"underscore": "~1.4.4"
}
},
"binaryextensions": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz",
"integrity": "sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==",
"dev": true
},
"bl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
@ -3022,6 +3037,12 @@
"object.defaults": "^1.1.0"
}
},
"easy-stack": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz",
"integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=",
"dev": true
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@ -3031,6 +3052,12 @@
"safer-buffer": "^2.1.0"
}
},
"editions": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz",
"integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==",
"dev": true
},
"editorconfig": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.2.tgz",
@ -3706,6 +3733,12 @@
"es5-ext": "~0.10.14"
}
},
"event-pubsub": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz",
"integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==",
"dev": true
},
"event-stream": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
@ -4188,6 +4221,29 @@
"readable-stream": "^2.3.6"
}
},
"follow-redirects": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
"integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
"requires": {
"debug": "^3.2.6"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@ -5343,6 +5399,17 @@
"integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==",
"dev": true
},
"gulp-replace": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz",
"integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==",
"dev": true,
"requires": {
"istextorbinary": "2.2.1",
"readable-stream": "^2.0.1",
"replacestream": "^4.0.0"
}
},
"gulp-watch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz",
@ -6396,6 +6463,17 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"istextorbinary": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz",
"integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==",
"dev": true,
"requires": {
"binaryextensions": "2",
"editions": "^1.3.3",
"textextensions": "2"
}
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
@ -6438,6 +6516,21 @@
"integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
"dev": true
},
"js-message": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
"integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=",
"dev": true
},
"js-queue": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz",
"integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=",
"dev": true,
"requires": {
"easy-stack": "^1.0.0"
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -6757,6 +6850,12 @@
"integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=",
"dev": true
},
"lodash.endswith": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz",
"integrity": "sha1-/tWawXOO0+I27dcGTsRWRIs3vAk=",
"dev": true
},
"lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
@ -7355,6 +7454,17 @@
}
}
},
"node-ipc": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz",
"integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==",
"dev": true,
"requires": {
"event-pubsub": "4.3.0",
"js-message": "1.0.5",
"js-queue": "2.0.0"
}
},
"node-libs-browser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz",
@ -7908,6 +8018,59 @@
"readable-stream": "^2.1.5"
}
},
"parallel-webpack": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/parallel-webpack/-/parallel-webpack-2.3.0.tgz",
"integrity": "sha512-RCIDF+YOqyAJeM8NumtOQ8JYjUXexDRIN4slFNfvUp1RxLB1zLeLZMAwlP6s7l9LhuR5xJ2pv8ckIsdESzSqog==",
"dev": true,
"requires": {
"ajv": "^4.9.2",
"bluebird": "^3.0.6",
"chalk": "^1.1.1",
"interpret": "^1.0.1",
"lodash.assign": "^4.0.8",
"lodash.endswith": "^4.0.1",
"lodash.flatten": "^4.2.0",
"minimist": "^1.2.0",
"node-ipc": "^9.1.0",
"pluralize": "^1.2.1",
"supports-color": "^3.1.2",
"worker-farm": "^1.3.1"
},
"dependencies": {
"ajv": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"dev": true,
"requires": {
"co": "^4.6.0",
"json-stable-stringify": "^1.0.1"
}
},
"has-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
"integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
"dev": true
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"supports-color": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
"integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
"dev": true,
"requires": {
"has-flag": "^1.0.0"
}
}
}
},
"param-case": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
@ -8347,6 +8510,28 @@
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"tar-fs": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz",
"integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==",
"requires": {
"chownr": "^1.0.1",
"mkdirp": "^0.5.1",
"pump": "^1.0.0",
"tar-stream": "^1.1.2"
},
"dependencies": {
"pump": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
"integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
}
}
}
}
},
@ -8473,7 +8658,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
@ -8849,6 +9033,17 @@
"remove-trailing-separator": "^1.1.0"
}
},
"replacestream": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz",
"integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.3",
"object-assign": "^4.0.1",
"readable-stream": "^2.0.2"
}
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
@ -10105,23 +10300,44 @@
}
},
"tar-fs": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz",
"integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz",
"integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==",
"requires": {
"chownr": "^1.0.1",
"chownr": "^1.1.1",
"mkdirp": "^0.5.1",
"pump": "^1.0.0",
"tar-stream": "^1.1.2"
"pump": "^3.0.0",
"tar-stream": "^2.0.0"
},
"dependencies": {
"pump": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
"integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
"bl": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz",
"integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
"readable-stream": "^3.0.1"
}
},
"readable-stream": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz",
"integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"tar-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.0.1.tgz",
"integrity": "sha512-I6OJF7wE62BC6zNPdHDtseK0D0187PBjbKSLYY4ffvVkBM6tyBn2O9plDvVM2229/mozfEL/X3++qSvYYQE2xw==",
"requires": {
"bl": "^3.0.0",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
}
}
}
@ -10264,6 +10480,12 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"textextensions": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz",
"integrity": "sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==",
"dev": true
},
"throttleit": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",

View File

@ -2,7 +2,7 @@
"name": "betterdiscord",
"description": "BetterDiscord",
"author": "Jiiks",
"version": "2.0.0-beta.3",
"version": "2.0.0-beta.4",
"homepage": "https://betterdiscord.net",
"license": "MIT",
"main": "core/dist/main.js",
@ -17,6 +17,7 @@
"private": false,
"dependencies": {
"asar": "^1.0.0",
"axios": "^0.18.0",
"chokidar": "^2.1.2",
"csp-parse": "github:macropodhq/csp-parse",
"deepmerge": "^3.2.0",
@ -24,7 +25,9 @@
"keytar": "^4.4.1",
"nedb": "^1.8.0",
"node-sass": "^4.11.0",
"original-fs": "^1.0.0"
"original-fs": "^1.0.0",
"semver": "^5.6.0",
"tar-fs": "^2.0.0"
},
"devDependencies": {
"@babel/core": "^7.3.4",
@ -51,6 +54,7 @@
"gulp-inject-string": "^1.1.2",
"gulp-json-editor": "^2.5.1",
"gulp-rename": "^1.4.0",
"gulp-replace": "^1.0.0",
"gulp-watch": "^5.0.1",
"hash-files": "^1.1.1",
"html-webpack-plugin": "^3.2.0",
@ -58,6 +62,7 @@
"lodash": "^4.17.11",
"mkdirp": "^0.5.1",
"node-gyp": "^3.8.0",
"parallel-webpack": "^2.3.0",
"pump": "^3.0.0",
"request-promise-native": "1.0.5",
"sass-lint": "^1.12.1",
@ -82,6 +87,8 @@
"watch_core": "npm run watch --prefix core",
"build_editor": "npm run build --prefix editor",
"watch_editor": "npm run watch --prefix editor",
"build_all": "parallel-webpack --progress --colors --config=webpack.all.config.js",
"watch_all": "parallel-webpack --progress --colors --watch --config=webpack.all.config.js",
"lint": "eslint -f unix client/src core/src editor/src common && npm run sasslint",
"lint_fix": "eslint -f unix client/src core/src",
"sasslint": "sass-lint client/src/styles/**/*.scss -v",
@ -91,7 +98,8 @@
"package_release": "node scripts/package-release.js",
"gulp_release": "gulp release",
"release": "npm run lint && npm run build_release && gulp release && npm run package_release",
"update_release": "npm run build_release && gulp build-release",
"release_test": "npm run build_release && gulp release",
"update_release": "npm run build_release && gulp release",
"inject": "node scripts/inject.js"
}
}

View File

@ -53,6 +53,7 @@ async function archiveCore(out = './release/core.tar.gz') {
coreArchive.file('./release/core/package.json', { name: 'core/package.json' });
coreArchive.file('./release/core/index.js', { name: 'core/index.js' });
coreArchive.file(`./release/core/${mainFn}`, { name: `core/${mainFn}` });
coreArchive.file('./release/core/csp.json', { name: 'core/csp.json' });
coreArchive.file('./release/core/sparkplug.js', { name: 'core/sparkplug.js' });
coreArchive.directory('./release/core/modules', 'core/modules');
coreArchive.directory('./release/core/node_modules', 'core/node_modules');

28
webpack.all.config.js Normal file
View File

@ -0,0 +1,28 @@
const path = require('path');
const editor = require('./editor/webpack.config');
editor.output.path = path.resolve('editor', 'dist');
editor.entry = path.resolve('editor', editor.entry);
editor.resolve.alias['vue$'] = path.resolve('node_modules', 'vue', 'dist', 'vue.esm.js');
editor.resolve.modules = [
path.resolve('node_modules'),
path.resolve('common', 'modules')
];
const client = require('./client/webpack.config');
client.output.path = path.resolve('client', 'dist');
client.entry = path.resolve('client', client.entry);
client.resolve.alias['vue$'] = path.resolve('node_modules', 'vue', 'dist', 'vue.esm.js');
client.resolve.modules = [
path.resolve('node_modules'),
path.resolve('common', 'modules'),
path.resolve('client', 'src', 'modules'),
path.resolve('client', 'src', 'ui'),
path.resolve('client', 'src', 'plugins'),
path.resolve('client', 'src', 'structs'),
path.resolve('client', 'src', 'builtin')
];
module.exports = [editor, client];