Add initial pass at core updater

- Fix duplicate file regex
- Add core updater
- Unify versions
- Add sanity for plugin/theme folder
This commit is contained in:
Zack Rauen 2021-04-05 01:43:30 -04:00
parent 66d8d7a069
commit 5b1900fe3d
10 changed files with 92 additions and 35 deletions

View File

@ -1,6 +1,5 @@
{
"name": "betterdiscord-renderer",
"version": "1.0.0",
"description": "Renderer portion of the BetterDiscord application.",
"private": true,
"main": "src/index.js",

View File

@ -1,14 +1,7 @@
export default {
local: false,
localPath: "",
minified: true,
branch: "stable",
repo: "rauenzi",
minSupportedVersion: "0.3.0",
bdVersion: "1.0.0",
version: process.env.__VERSION__,
// Get from main process
version: "0.6.0",
path: "",
appPath: "",
userData: ""

View File

@ -287,7 +287,6 @@ export default {
},
Startup: {
notSupported: "Not Supported",
versionMismatch: "BetterDiscord Injector v{{injector}} is not supported by the latest remote (v{{remote}}).\n\nPlease download the latest version from [GitHub](https://github.com/rauenzi/BetterDiscordApp/releases/latest)",
incompatibleApp: "BetterDiscord does not work with {{app}}. Please uninstall one of them.",
updateNow: "Update Now",
maybeLater: "Maybe Later",

View File

@ -45,21 +45,18 @@ export default new class ComponentPatcher {
children[children.length - 2].type = newOne;
}
const injector = DiscordModules.React.createElement("div", {className: "colorMuted-HdFt4q size12-3cLvbJ"}, `Injector ${Config.version}`);
const versionHash = `(${Config.hash ? Config.hash.substring(0, 7) : Config.branch})`;
const additional = DiscordModules.React.createElement("div", {className: "colorMuted-HdFt4q size12-3cLvbJ"}, `BD ${Config.bdVersion} `, DiscordModules.React.createElement("span", {className: "versionHash-2gXjIB da-versionHash"}, versionHash));
const additional = DiscordModules.React.createElement("div", {className: "colorMuted-HdFt4q size12-3cLvbJ"}, `BetterDiscord ${Config.version}`);
const originalVersions = children[children.length - 1].type;
children[children.length - 1].type = function() {
const returnVal = originalVersions(...arguments);
returnVal.props.children.splice(returnVal.props.children.length - 1, 0, injector);
returnVal.props.children.splice(1, 0, additional);
return returnVal;
};
});
}
/*
patchGuildListItems() {
if (this.guildListItemsPatch) return;
@ -158,7 +155,7 @@ export default new class ComponentPatcher {
// Tropical's notes
/*
/*
html [maximized | bd | stable | canary | ptb]
.iconWrapper-2OrFZ1 [type]
.sidebar-2K8pFh [guild-id]

View File

@ -1,3 +1,4 @@
const path = require("path");
import LocaleManager from "./localemanager";
import Logger from "common/logger";
@ -13,6 +14,7 @@ import DataStore from "./datastore";
import DiscordModules from "./discordmodules";
import ComponentPatcher from "./componentpatcher";
import Strings from "./strings";
import IPC from "./ipc";
import LoadingIcon from "../loadingicon";
import Styles from "../styles/index.css";
@ -39,7 +41,7 @@ export default new class Core {
// console.error = toFile(window.oce);
// console.exception = toFile(window.ocx);
// })();
Config.appPath = process.env.DISCORD_APP_PATH;
Config.userData = process.env.DISCORD_USER_DATA;
Config.dataPath = process.env.BETTERDISCORD_DATA_PATH;
@ -55,7 +57,6 @@ export default new class Core {
await LocaleManager.initialize();
Logger.log("Startup", "Performing incompatibility checks");
if (Config.version < Config.minSupportedVersion) return Modals.alert(Strings.Startup.notSupported, Strings.Startup.versionMismatch.format({injector: Config.version, remote: Config.bdVersion}));
if (window.ED) return Modals.alert(Strings.Startup.notSupported, Strings.Startup.incompatibleApp.format({app: "EnhancedDiscord"}));
if (window.WebSocket && window.WebSocket.name && window.WebSocket.name.includes("Patched")) return Modals.alert(Strings.Startup.notSupported, Strings.Startup.incompatibleApp.format({app: "Powercord"}));
@ -97,10 +98,12 @@ export default new class Core {
Modals.showAddonErrors({plugins: pluginErrors, themes: themeErrors});
const previousVersion = DataStore.getBDData("version");
if (Config.bdVersion > previousVersion) {
if (Config.version > previousVersion) {
Modals.showChangelogModal(Changelog);
DataStore.setBDData("version", Config.bdVersion);
DataStore.setBDData("version", Config.version);
}
this.checkForUpdate();
}
waitForGuilds() {
@ -112,12 +115,64 @@ export default new class Core {
const wrapper = GuildClasses.wrapper.split(" ")[0];
const guild = GuildClasses.listItem.split(" ")[0];
const blob = GuildClasses.blobContainer.split(" ")[0];
if (document.querySelectorAll(`.${wrapper} .${guild} .${blob}`).length > 0) return resolve(Config.deferLoaded = true);
// else if (timesChecked >= 50) return resolve(Config.deferLoaded = true);
if (document.querySelectorAll(`.${wrapper} .${guild} .${blob}`).length > 0) return resolve();
// else if (timesChecked >= 50) return resolve();
setTimeout(checkForGuilds, 100);
};
checkForGuilds();
});
}
async checkForUpdate() {
const resp = await fetch(`https://api.github.com/repos/rauenzi/BetterDiscordApp/releases/latest`,{
method: "GET",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "BetterDiscord Updater"
}
});
const data = await resp.json();
const remoteVersion = data.tag_name.startsWith("v") ? data.tag_name.slice(1) : data.tag_name;
const hasUpdate = remoteVersion > Config.version;
if (!hasUpdate) return;
Modals.showConfirmationModal("Update", "There is an update, would you like to update now?", {
confirmText: "Update",
cancelText: "Skip",
onConfirm: () => this.update(data)
});
}
async update(releaseInfo) {
try {
const asar = releaseInfo.assets.find(a => a.name === "betterdiscord.asar");
const request = require("request");
const buff = await new Promise((resolve, reject) =>
request(asar.url, {encoding: null, headers: {"User-Agent": "BD Updater", "Accept": "application/octet-stream"}}, (err, resp, body) => {
if (err || resp.statusCode != 200) return reject(err || `${resp.statusCode} ${resp.statusMessage}`);
return resolve(body);
}));
const asarPath = path.join(DataStore.baseFolder, "betterdiscord.asar");
console.log(asarPath);
const fs = require("original-fs");
fs.writeFileSync(asarPath, buff);
Modals.showConfirmationModal("Update Successful!", "BetterDiscord updated successfully. Discord needs to restart in order for it to take effect. Do you want to do this now?", {
confirmText: Strings.Modals.restartNow,
cancelText: Strings.Modals.restartLater,
danger: true,
onConfirm: () => IPC.relaunch()
});
}
catch (err) {
console.error(err);
Modals.showConfirmationModal("Update Failed", "BetterDiscord failed to update. Please download the latest version of the installer from GitHub (https://github.com/BetterDiscord/Installer/releases/latest) and reinstall.", {
cancelText: ""
});
}
}
};

View File

@ -29,6 +29,12 @@ export default new class DataStore {
const bdFolderExists = fs.existsSync(Config.dataPath);
if (!bdFolderExists) fs.mkdirSync(Config.dataPath);
const pluginFolderExists = fs.existsSync(this.pluginFolder);
if (!pluginFolderExists) fs.mkdirSync(this.pluginFolder);
const themeFolderExists = fs.existsSync(this.themeFolder);
if (!themeFolderExists) fs.mkdirSync(this.themeFolder);
const newStorageExists = fs.existsSync(this.baseFolder);
if (!newStorageExists) fs.mkdirSync(this.baseFolder);
@ -101,6 +107,8 @@ export default new class DataStore {
return this._injectionPath = realLocation;
}
get pluginFolder() {return this._pluginFolder || (this._pluginFolder = path.resolve(Config.dataPath, "plugins"));}
get themeFolder() {return this._themeFolder || (this._themeFolder = path.resolve(Config.dataPath, "themes"));}
get customCSS() {return this._customCSS || (this._customCSS = path.resolve(this.dataFolder, "custom.css"));}
get baseFolder() {return this._baseFolder || (this._baseFolder = path.resolve(Config.dataPath, "data"));}
get dataFolder() {return this._dataFolder || (this._dataFolder = path.resolve(this.baseFolder, `${releaseChannel}`));}

View File

@ -22,7 +22,7 @@ export default new class PluginManager extends AddonManager {
get name() {return "PluginManager";}
get moduleExtension() {return ".js";}
get extension() {return ".plugin.js";}
get duplicatePattern() {return /\.plugin\([0-9]+\)\.js/;}
get duplicatePattern() {return /\.plugin\s?\([0-9]+\)\.js/;}
get addonFolder() {return path.resolve(Config.dataPath, "plugins");}
get prefix() {return "plugin";}
get language() {return "javascript";}

View File

@ -14,7 +14,7 @@ export default new class ThemeManager extends AddonManager {
get name() {return "ThemeManager";}
get moduleExtension() {return ".css";}
get extension() {return ".theme.css";}
get duplicatePattern() {return /\.theme\([0-9]+\)\.css/;}
get duplicatePattern() {return /\.theme\s?\([0-9]+\)\.css/;}
get addonFolder() {return path.resolve(Config.dataPath, "themes");}
get prefix() {return "theme";}
get language() {return "css";}

View File

@ -78,7 +78,7 @@ export default class Modals {
const emptyFunction = () => {};
const {onConfirm = emptyFunction, onCancel = emptyFunction, confirmText = Strings.Modals.okay, cancelText = Strings.Modals.cancel, danger = false, key = undefined} = options;
if (!Array.isArray(content)) content = [content];
content = content.map(c => typeof(c) === "string" ? React.createElement(Markdown, null, c) : c);
@ -180,8 +180,8 @@ export default class Modals {
const Changelog = WebpackModules.getModule(m => m.defaultProps && m.defaultProps.selectable == false);
const MarkdownParser = WebpackModules.getByProps("defaultRules", "parse");
if (!Changelog || !ModalStack || !ChangelogClasses || !TextElement || !FlexChild || !Titles || !MarkdownParser) return Logger.warn("Modals", "showChangelogModal missing modules");
const {image = "https://i.imgur.com/8sctUVV.png", description = "", changes = [], title = "BetterDiscord", subtitle = `v${Config.bdVersion}`, footer} = options;
const {image = "https://i.imgur.com/8sctUVV.png", description = "", changes = [], title = "BetterDiscord", subtitle = `v${Config.version}`, footer} = options;
const ce = React.createElement;
const changelogItems = [options.video ? ce("video", {src: options.video, poster: options.poster, controls: true, className: ChangelogClasses.video}) : ce("img", {src: image})];
if (description) changelogItems.push(ce("p", null, MarkdownParser.parse(description)));
@ -199,7 +199,7 @@ export default class Modals {
ce(TextElement, {size: TextElement.Sizes.SMALL, color: TextElement.Colors.STANDARD, className: ChangelogClasses.date}, subtitle)
);
};
const renderFooter = () => {
const Anchor = WebpackModules.getModule(m => m.displayName == "Anchor");
const AnchorClasses = WebpackModules.getByProps("anchorUnderlineOnHover") || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"};
@ -228,7 +228,7 @@ export default class Modals {
renderFooter: renderFooter,
}, props), changelogItems);
});
const closeModal = ModalActions.closeModal;
ModalActions.closeModal = function(k) {
Reflect.apply(closeModal, this, arguments);
@ -248,7 +248,7 @@ export default class Modals {
this.elementRef = React.createRef();
this.element = panel;
}
componentDidMount() {
if (this.element instanceof Node) this.elementRef.current.appendChild(this.element);
// if (typeof(this.element) === "string") this.elementRef.current.appendChild(this.element);
@ -268,15 +268,15 @@ export default class Modals {
const mc = this.ModalComponents;
const modal = props => {
return React.createElement(mc.ModalRoot, Object.assign({size: mc.ModalSize.MEDIUM, className: "bd-addon-modal"}, props),
return React.createElement(mc.ModalRoot, Object.assign({size: mc.ModalSize.MEDIUM, className: "bd-addon-modal"}, props),
React.createElement(mc.ModalHeader, {separator: false, className: "bd-addon-modal-header"},
React.createElement(this.FormTitle, {tag: "h4"}, `${name} Settings`),
React.createElement(this.FlexElements.Child, {grow: 0},
React.createElement(mc.ModalCloseButton, {className: "bd-modal-close", onClick: props.onClose})
)
),
React.createElement(mc.ModalContent, {className: "bd-addon-modal-settings"},
React.createElement(ErrorBoundary, {}, child)
React.createElement(mc.ModalContent, {className: "bd-addon-modal-settings"},
React.createElement(ErrorBoundary, {}, child)
),
React.createElement(mc.ModalFooter, {className: "bd-addon-modal-footer"},
React.createElement(this.Buttons.default, {onClick: props.onClose, className: "bd-button"}, Strings.Modals.done)

View File

@ -1,6 +1,8 @@
const path = require("path");
const webpack = require("webpack");
const CircularDependencyPlugin = require("circular-dependency-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const basePkg = require("../package.json");
module.exports = {
mode: "development",
@ -14,6 +16,7 @@ module.exports = {
externals: {
electron: `require("electron")`,
fs: `require("fs")`,
"original-fs": `require("original-fs")`,
path: `require("path")`,
request: `require("request")`,
events: `require("events")`,
@ -40,7 +43,7 @@ module.exports = {
presets: [["@babel/env", {
targets: {
node: "12.14.1",
chrome: "80"
chrome: "83"
}
}], "@babel/react"]
}
@ -55,6 +58,9 @@ module.exports = {
new CircularDependencyPlugin({
exclude: /node_modules/,
cwd: process.cwd(),
}),
new webpack.DefinePlugin({
"process.env.__VERSION__": JSON.stringify(basePkg.version)
})
],
optimization: {