From ebba553ed251d124981f5360a5c1f45ac2eeb84d Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Wed, 7 Apr 2021 20:31:02 -0400 Subject: [PATCH] Switch how assets are handled --- assets/emotes/index.js | 7 + assets/locales/en.json | 25 +- assets/locales/index.js | 6 + package.json | 1 + .../src/builtins/developer/devtoolswarning.js | 4 +- renderer/src/builtins/emotes/emotemenu.js | 91 ++--- renderer/src/builtins/emotes/emotes.js | 112 +++---- .../src/builtins/general/publicservers.js | 11 +- renderer/src/data/config.js | 1 + renderer/src/data/data.js | 5 +- .../emoteconfig.js => emotesettings.js} | 0 .../data/{settings/config.js => settings.js} | 0 renderer/src/data/strings.js | 312 ------------------ renderer/src/modules/core.js | 6 +- renderer/src/modules/datastore.js | 2 +- renderer/src/modules/localemanager.js | 41 +-- renderer/src/modules/pluginapi.js | 4 +- renderer/webpack.config.js | 16 +- scripts/emotes.js | 18 + scripts/pack.js | 6 +- 20 files changed, 185 insertions(+), 483 deletions(-) create mode 100644 assets/emotes/index.js create mode 100644 assets/locales/index.js rename renderer/src/data/{settings/emoteconfig.js => emotesettings.js} (100%) rename renderer/src/data/{settings/config.js => settings.js} (100%) delete mode 100644 renderer/src/data/strings.js create mode 100644 scripts/emotes.js diff --git a/assets/emotes/index.js b/assets/emotes/index.js new file mode 100644 index 00000000..35210c9c --- /dev/null +++ b/assets/emotes/index.js @@ -0,0 +1,7 @@ +module.exports = { + blocklist: require("./blocklist.json"), + BTTV: require("./bttv.json"), + FrankerFaceZ: require("./frankerfacez.json"), + TwitchGlobal: require("./twitchglobal.json"), + TwitchSubscriber: require("./twitchsubscriber.json") +}; \ No newline at end of file diff --git a/assets/locales/en.json b/assets/locales/en.json index 31619c40..d7d00d58 100644 --- a/assets/locales/en.json +++ b/assets/locales/en.json @@ -24,6 +24,10 @@ "showToasts": { "name": "Show Toasts", "note": "Shows a small notification for important information" + }, + "mediaKeys": { + "name": "Disable Media Keys", + "note": "Prevents Discord from hijacking your media keys after playing a video." } }, "appearance": { @@ -47,6 +51,10 @@ "hideGiftButton": { "name": "Hide Gift Button", "note": "Hides the Nitro Gift button in the textarea" + }, + "removeMinimumSize": { + "name": "Remove Minimum Size", + "note": "Removes Discord's forced minimum window size of 940x500" } }, "addons": { @@ -109,6 +117,14 @@ "inspectElement": { "name": "Inspect Element Hotkey", "note": "Enables the inspect element hotkey (ctrl + shift + c) that is common in most browsers" + }, + "devToolsWarning": { + "name": "Stop DevTools Warning", + "note": "Stops Discord from printing out their \"Hold Up!\" message" + }, + "debugLogs": { + "name": "Debug Logs", + "note": "Outputs everything from the console into the debug.log file in the BetterDiscord folder" } }, "window": { @@ -150,10 +166,6 @@ "animateOnHover": { "name": "Animate On Hover", "note": "Only animate the emote modifiers on hover" - }, - "mediaKeys": { - "name": "Disable Media Keys", - "note": "Prevents Discord from hijacking your media keys after playing a video." } }, "categories": { @@ -231,7 +243,9 @@ "loading": "Loading emotes in the background do not reload.", "loaded": "All emotes successfully loaded.", "clearEmotes": "Clear Emote Data", - "favoriteAction": "Favorite!" + "favoriteAction": "Favorite!", + "downloadFailed": "Download Failed", + "failureMessage": "BetterDiscord failed to download emotes, please check your internet connection and firewall." }, "PublicServers": { "button": "public", @@ -283,7 +297,6 @@ }, "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", diff --git a/assets/locales/index.js b/assets/locales/index.js new file mode 100644 index 00000000..775fd840 --- /dev/null +++ b/assets/locales/index.js @@ -0,0 +1,6 @@ +module.exports = { + en: require("./en.json"), + de: require("./de.json"), + ja: require("./ja.json"), + sv: require("./sv.json") +}; \ No newline at end of file diff --git a/package.json b/package.json index 0a0cb070..0f468b25 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build-prod": "npm run build-prod --prefix injector && npm run build-prod --prefix renderer", "build-injector": "npm run build --prefix injector", "build-renderer": "npm run build --prefix renderer", + "pack-emotes": "node scripts/emotes.js", "inject": "node scripts/inject.js", "lint": "eslint --ext .js common/ && npm run lint --prefix injector && npm run lint --prefix renderer", "test": "mocha --require @babel/register --recursive \"./tests/renderer/*.js\"", diff --git a/renderer/src/builtins/developer/devtoolswarning.js b/renderer/src/builtins/developer/devtoolswarning.js index 73eb45f0..a97903f5 100644 --- a/renderer/src/builtins/developer/devtoolswarning.js +++ b/renderer/src/builtins/developer/devtoolswarning.js @@ -9,7 +9,7 @@ export default new class StopDevToolsWarning extends Builtin { enabled() { // IPC.stopDevtoolsWarning(); - DiscordNative?.window?.setDevtoolsCallbacks(null, null); + window?.DiscordNative?.window?.setDevtoolsCallbacks(null, null); } disabled() { @@ -17,6 +17,6 @@ export default new class StopDevToolsWarning extends Builtin { const stringModule = WebpackModules.getByProps("Messages"); const hideModule = WebpackModules.getModule(m => Object.keys(m).some(k => k.startsWith("hide"))); if (!devtoolsModule || !stringModule || !hideModule) return; - devtoolsModule(stringModule, hideModule, DiscordNative); + devtoolsModule(stringModule, hideModule, window?.DiscordNative); } }; \ No newline at end of file diff --git a/renderer/src/builtins/emotes/emotemenu.js b/renderer/src/builtins/emotes/emotemenu.js index 81958f6f..85f7da75 100644 --- a/renderer/src/builtins/emotes/emotemenu.js +++ b/renderer/src/builtins/emotes/emotemenu.js @@ -25,48 +25,57 @@ export default new class EmoteMenu extends Builtin { enabled() { this.after(EmojiPicker, "type", (_, __, returnValue) => { - const head = Utilities.getNestedProp(returnValue, "props.children.props.children.props.children.1.props.children.0.props.children.props.children"); - const body = Utilities.getNestedProp(returnValue, "props.children.props.children.props.children.1.props.children"); - if (!head || !body) return returnValue; + const originalChildren = Utilities.getNestedProp(returnValue, "props.children.props.children"); + if (!originalChildren || originalChildren.__patched) return; + returnValue.props.children.props.children = (props) => { + const childrenReturn = Reflect.apply(originalChildren, null, [props]); + const head = Utilities.getNestedProp(childrenReturn, "props.children.props.children.1.props.children.0.props.children.props.children"); + const body = Utilities.getNestedProp(childrenReturn, "props.children.props.children.1.props.children"); + if (!head || !body) return childrenReturn; - let activePicker = this.getSelected(body); - let isActive = activePicker.id == "bd-emotes"; - const tabProps = head[0].props; - if (!isActive && activePicker.id == "emoji" && this.hideEmojis) { - activePicker = {id: "bd-emotes", index: 3}; - isActive = true; - } - if (this.hideEmojis) head.splice(head.findIndex(e => e && e.props && e.props.id == "emoji-picker-tab"), 1); - head.push( - React.createElement("div", { - "id": "bd-emotes-tab", - "role": "tab", - "aria-selected": isActive, - "className": tabProps.className, - }, React.createElement(tabProps.children.type, { - viewType: "bd-emotes", - isActive: isActive, - }, "Twitch") - )); - if (isActive) { - body[activePicker.index] = React.createElement(EmoteMenuCard, { - type: "twitch", - }, [ - React.createElement(Category, { - label: "Favorites", - icon: React.createElement(Favorite, {}), - }, Object.entries(EmoteModule.favorites).map(([emote, url]) => { - return React.createElement(EmoteIcon, {emote, url}); - })), - React.createElement(Category, { - label: "Twitch Emotes", - icon: React.createElement(Twitch, {}) - }, Object.keys(EmoteModule.getCategory("TwitchGlobal")).map(emote=> { - const url = EmoteModule.getUrl("TwitchGlobal", emote); - return React.createElement(EmoteIcon, {emote, url}); - })) - ]); - } + let activePicker = this.getSelected(body); + let isActive = activePicker.id == "bd-emotes"; + const tabProps = head[0].props; + if (!isActive && activePicker.id == "emoji" && this.hideEmojis) { + activePicker = {id: "bd-emotes", index: 3}; + isActive = true; + } + if (this.hideEmojis) head.splice(head.findIndex(e => e && e.props && e.props.id == "emoji-picker-tab"), 1); + head.push( + React.createElement("div", { + "id": "bd-emotes-tab", + "role": "tab", + "aria-selected": isActive, + "className": tabProps.className, + }, React.createElement(tabProps.children.type, { + viewType: "bd-emotes", + isActive: isActive, + }, "Twitch") + )); + if (isActive) { + body[activePicker.index] = React.createElement(EmoteMenuCard, { + type: "twitch", + }, [ + React.createElement(Category, { + label: "Favorites", + icon: React.createElement(Favorite, {}), + }, Object.entries(EmoteModule.favorites).map(([emote, url]) => { + return React.createElement(EmoteIcon, {emote, url}); + })), + React.createElement(Category, { + label: "Twitch Emotes", + icon: React.createElement(Twitch, {}) + }, Object.keys(EmoteModule.getCategory("TwitchGlobal")).map(emote=> { + const url = EmoteModule.getUrl("TwitchGlobal", emote); + return React.createElement(EmoteIcon, {emote, url}); + })) + ]); + } + + return childrenReturn; + }; + + returnValue.props.children.props.children.__patched = true; }); } diff --git a/renderer/src/builtins/emotes/emotes.js b/renderer/src/builtins/emotes/emotes.js index 59700834..a8e0bad7 100644 --- a/renderer/src/builtins/emotes/emotes.js +++ b/renderer/src/builtins/emotes/emotes.js @@ -1,11 +1,14 @@ import Builtin from "../../structs/builtin"; -import {EmoteConfig} from "data"; +import {EmoteConfig, Config} from "data"; import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings, Strings} from "modules"; import BDEmote from "../../ui/emote"; +import Modals from "../../ui/modals"; import Toasts from "../../ui/toasts"; import FormattableString from "../../structs/string"; const request = require("request"); +const path = require("path"); +const fs = require("fs"); const EmoteURLs = { TwitchGlobal: new FormattableString(`https://static-cdn.jtvnw.net/emoticons/v1/{{id}}/1.0`), @@ -25,13 +28,14 @@ const blocklist = []; const overrides = ["twitch", "subscriber", "bttv", "ffz"]; const modifiers = ["flip", "spin", "pulse", "spin2", "spin3", "1spin", "2spin", "3spin", "tr", "bl", "br", "shake", "shake2", "shake3", "flap"]; -export default new class EmoteModule extends Builtin { + export default new class EmoteModule extends Builtin { get name() {return "Emotes";} get collection() {return "settings";} get category() {return "general";} get id() {return "emotes";} get categories() {return Object.keys(Emotes).filter(k => this.isCategoryEnabled(k));} get shouldDownload() {return Settings.get("emotes", this.category, "download");} + get asarPath() {return path.join(DataStore.baseFolder, "emotes.asar");} isCategoryEnabled(id) {return super.get("emotes", "categories", id.toLowerCase());} @@ -63,7 +67,7 @@ export default new class EmoteModule extends Builtin { async enabled() { Settings.registerCollection("emotes", "Emotes", EmoteConfig, {title: Strings.Emotes.clearEmotes, onClick: this.resetEmotes.bind(this)}); - await this.getBlocklist(); + // await this.getBlocklist(); await this.loadEmoteData(); Events.on("emotes-favorite-added", this.addFavorite); @@ -177,30 +181,6 @@ export default new class EmoteModule extends Builtin { }); } - async getBlocklist() { - try { - const category = "Blocklist"; - const exists = DataStore.emotesExist(category); - const valid = await this.isCacheValid(category); - const useCache = (valid) || (!valid && exists && !this.shouldDownload); - const list = useCache ? DataStore.getEmoteData(category) : await this.downloadEmotes(category); - blocklist.push(...list); - } - catch (err) { - // TODO: Log this - } - } - - isCacheValid(category) { - return new Promise(resolve => { - const etag = DataStore.getCacheHash("emotes", category); - if (!etag) return resolve(false); - request.head({url: this.getRemoteFile(category), headers: {"If-None-Match": etag}}, (err, resp) => { - resolve(!err && resp.statusCode == 304); - }); - }); - } - async loadEmoteData(categories) { if (!categories) categories = this.categories; if (!Array.isArray(categories)) categories = [categories]; @@ -208,21 +188,25 @@ export default new class EmoteModule extends Builtin { categories = categories.map(k => all.find(c => c.toLowerCase() == k.toLowerCase())); Toasts.show(Strings.Emotes.loading, {type: "info"}); this.emotesLoaded = false; + const localOutdated = Config.release.tag_name > DataStore.getBDData("emoteVersion"); - for (const category of categories) { - const exists = DataStore.emotesExist(category); - const valid = await this.isCacheValid(category); - const useCache = (valid) || (!valid && exists && !this.shouldDownload); - let data = null; - if (useCache) { - this.log(`Loading ${category} emotes from local cache.`); - const cachedData = DataStore.getEmoteData(category); - const hasData = Object.keys(cachedData).length > 0; - if (hasData) data = cachedData; + if (!fs.existsSync(this.asarPath) || (localOutdated && this.shouldDownload)) await this.downloadEmotes(); + + try { + for (const category of categories) { + this.log(category); + const EmoteData = __non_webpack_require__(path.join(this.asarPath, category.toLowerCase())); + Object.assign(Emotes[category], EmoteData); + delete __non_webpack_require__.cache[path.join(this.asarPath, category.toLowerCase())]; + await new Promise(r => setTimeout(r, 1000)); } - if (!data) data = await this.downloadEmotes(category); - Object.assign(Emotes[category], data); - await new Promise(r => setTimeout(r, 1000)); + + const EmoteData = __non_webpack_require__(path.join(this.asarPath, "blocklist")); + blocklist.push(...EmoteData); + delete __non_webpack_require__.cache[path.join(this.asarPath, "blocklist")]; + } + catch (err) { + this.log("Failed to load emotes."); } this.emotesLoaded = true; @@ -241,36 +225,32 @@ export default new class EmoteModule extends Builtin { } } - downloadEmotes(category) { - const url = this.getRemoteFile(category); - this.log(`Downloading ${category} from ${url}`); - const options = {url: url, timeout: 10000, json: true}; - return new Promise(resolve => { - request.get(options, (error, response, parsedData) => { - if (error || response.statusCode != 200) { - this.stacktrace(`Could not download ${category} emotes.`, error); - return resolve({}); - } + async downloadEmotes() { + try { + const asar = Config.release.assets.find(a => a.name === "emotes.asar"); + this.log(`Downloading emotes from: ${asar.url}`); + const buff = await new Promise((resolve, reject) => + request(asar.url, {encoding: null, headers: {"User-Agent": "BetterDiscord Emotes", "Accept": "application/octet-stream"}}, (err, resp, body) => { + if (err || resp.statusCode != 200) return reject(err || `${resp.statusCode} ${resp.statusMessage}`); + return resolve(body); + })); - for (const emote in parsedData) { - if (emote.length < 4 || blocklist.includes(emote) || !parsedData[emote]) { - delete parsedData[emote]; - continue; - } - // parsedData[emote] = EmoteURLs[category].format({id: parsedData[emote]}); - } - DataStore.saveEmoteData(category, parsedData); - DataStore.setCacheHash("emotes", category, response.headers.etag); - resolve(parsedData); - this.log(`Downloaded ${category}`); - }); - }); + this.log("Successfully downloaded emotes.asar"); + const asarPath = this.asarPath; + const originalFs = require("original-fs"); + originalFs.writeFileSync(asarPath, buff); + this.log(`Saved emotes.asar to ${asarPath}`); + DataStore.setBDData("emoteVersion", Config.release.tag_name); + } + catch (err) { + this.stacktrace("Failed to download emotes.", err); + Modals.showConfirmationModal(Strings.Emotes.downloadFailed, Strings.Emotes.failureMessage, {cancelText: null}); + } } resetEmotes() { - const categories = Object.keys(Emotes); - this.unloadEmoteData(categories); - for (const cat of categories) DataStore.invalidateCache("emotes", cat); + this.unloadEmoteData(); + DataStore.setBDData("emoteVersion", "0"); this.loadEmoteData(); } }; \ No newline at end of file diff --git a/renderer/src/builtins/general/publicservers.js b/renderer/src/builtins/general/publicservers.js index f8dff9e8..914e31c7 100644 --- a/renderer/src/builtins/general/publicservers.js +++ b/renderer/src/builtins/general/publicservers.js @@ -13,7 +13,7 @@ export default new class PublicServers extends Builtin { const GuildList = WebpackModules.find(m => m.type && m.type.displayName == "NavigableGuilds"); const GuildListOld = WebpackModules.findByDisplayName("Guilds"); if (!GuildList && !GuildListOld) this.warn("Can't find GuildList component"); - this.guildPatch = this.after(GuildList ? GuildList : GuildListOld.prototype, GuildList ? "type" : "render", this._appendButton); + this.guildPatch = this.after(GuildList ? GuildList : GuildListOld.prototype, GuildList ? "type" : "render", () => {this._appendButton();}); this._appendButton(); } @@ -22,8 +22,15 @@ export default new class PublicServers extends Builtin { DOM.query("#bd-pub-li").remove(); } - _appendButton() { + async _appendButton() { + await new Promise(r => setTimeout(r, 1000)); + + const existing = DOM.query("#bd-pub-li"); + if (existing) return; + const guilds = DOM.query(`.${DiscordModules.GuildClasses.wrapper} .${DiscordModules.GuildClasses.listItem}`); + if (!guilds) return; + DOM.after(guilds, this.button); } diff --git a/renderer/src/data/config.js b/renderer/src/data/config.js index b3c5f2db..51bd306a 100644 --- a/renderer/src/data/config.js +++ b/renderer/src/data/config.js @@ -1,5 +1,6 @@ export default { version: process.env.__VERSION__, + release: {assets: []}, // Get from main process path: "", diff --git a/renderer/src/data/data.js b/renderer/src/data/data.js index 63eaa63c..9ab88c6c 100644 --- a/renderer/src/data/data.js +++ b/renderer/src/data/data.js @@ -1,5 +1,4 @@ export {default as Config} from "./config"; -export {default as EmoteConfig} from "./settings/emoteconfig"; -export {default as SettingsConfig} from "./settings/config"; -export {default as Strings} from "./strings"; +export {default as EmoteConfig} from "./emotesettings"; +export {default as SettingsConfig} from "./settings"; export {default as Changelog} from "./changelog"; \ No newline at end of file diff --git a/renderer/src/data/settings/emoteconfig.js b/renderer/src/data/emotesettings.js similarity index 100% rename from renderer/src/data/settings/emoteconfig.js rename to renderer/src/data/emotesettings.js diff --git a/renderer/src/data/settings/config.js b/renderer/src/data/settings.js similarity index 100% rename from renderer/src/data/settings/config.js rename to renderer/src/data/settings.js diff --git a/renderer/src/data/strings.js b/renderer/src/data/strings.js deleted file mode 100644 index cefa43f8..00000000 --- a/renderer/src/data/strings.js +++ /dev/null @@ -1,312 +0,0 @@ -export default { - Panels: { - plugins: "Plugins", - themes: "Themes", - customcss: "Custom CSS" - }, - Collections: { - settings: { - name: "Settings", - general: { - name: "General", - emotes: { - name: "Emote System", - note: "Enables BD's emote system" - }, - publicServers: { - name: "Public Servers", - note: "Display public servers button" - }, - voiceDisconnect: { - name: "Voice Disconnect", - note: "Disconnect from voice server when closing Discord" - }, - showToasts: { - name: "Show Toasts", - note: "Shows a small notification for important information" - }, - mediaKeys: { - name: "Disable Media Keys", - note: "Prevents Discord from hijacking your media keys after playing a video." - } - }, - appearance: { - name: "Appearance", - minimalMode: { - name: "Minimal Mode", - note: "Hide elements and reduce the size of elements" - }, - twentyFourHour: { - name: "24-Hour Timestamps", - note: "Converts 12-hour timestamps to 24-hour format" - }, - coloredText: { - name: "Colored Text", - note: "Make text colour the same as role color" - }, - hideGIFButton: { - name: "Hide GIF Button", - note: "Hides the GIF picker button in the textarea" - }, - hideGiftButton: { - name: "Hide Gift Button", - note: "Hides the Nitro Gift button in the textarea" - }, - removeMinimumSize: { - name: "Remove Minimum Size", - note: "Removes Discord's forced minimum window size of 940x500" - } - }, - addons: { - name: "Addon Manager", - addonErrors: { - name: "Show Addon Errors", - note: "Shows a modal with plugin/theme errors" - }, - autoReload: { - name: "Automatic Loading", - note: "Automatically loads, reloads, and unloads plugins and themes" - }, - editAction: { - name: "Edit Action", - note: "Where plugins & themes appear when editing", - options: { - detached: "Detached Window", - system: "System Editor" - } - } - }, - customcss: { - name: "Custom CSS", - customcss: { - name: "Custom CSS", - note: "Enables the Custom CSS tab" - }, - liveUpdate: { - name: "Live Update", - note: "Updates the css as you type" - }, - startDetached: { - name: "Start Detached", - note: "Clicking the Custom CSS tab opens the editor in a separate window", - }, - nativeOpen: { - name: "Open in Native Editor", - note: "Clicking the Custom CSS tab opens your custom css in your native editor" - }, - openAction: { - name: "Editor Location", - note: "Where Custom CSS should open by default", - options: { - settings: "Settings Menu", - detached: "Detached Window", - system: "System Editor" - } - } - }, - developer: { - name: "Developer Settings", - debuggerHotkey: { - name: "Debugger Hotkey", - note: "Allows activating debugger when pressing F8" - }, - reactDevTools: { - name: "React Developer Tools", - note: "Injects your local installation of React Developer Tools into Discord" - }, - inspectElement: { - name: "Inspect Element Hotkey", - note: "Enables the inspect element hotkey (ctrl + shift + c) that is common in most browsers" - }, - devToolsWarning: { - name: "Stop DevTools Warning", - note: "Stops Discord from printing out their \"Hold Up!\" message" - }, - debugLogs: { - name: "Debug Logs", - note: "Outputs everything from the console into the debug.log file in the BetterDiscord folder" - } - }, - window: { - name: "Window Preferences", - transparency: { - name: "Enable Transparency", - note: "Enables the main window to be see-through (requires restart)" - }, - frame: { - name: "Window Frame", - note: "Adds the native os window frame to the main window" - } - } - }, - emotes: { - name: "Emotes", - general: { - name: "General", - download: { - name: "Download Emotes", - note: "Download emotes whenever they are out of date" - }, - emoteMenu: { - name: "Emote Menu", - note: "Show Twitch/Favourite emotes in emote menu" - }, - hideEmojiMenu: { - name: "Hide Emoji Menu", - note: "Hides Discord's emoji menu when using emote menu" - }, - autoCaps: { - name: "Emote Autocapitalization", - note: "Autocapitalize emote commands" - }, - modifiers: { - name: "Show Emote Modifiers", - note: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)" - }, - animateOnHover: { - name: "Animate On Hover", - note: "Only animate the emote modifiers on hover" - } - }, - categories: { - name: "Categories", - twitchglobal: { - name: "Twitch Globals", - note: "Show Twitch global emotes" - }, - twitchsubscriber: { - name: "Twitch Subscribers", - note: "Show Twitch subscriber emotes" - }, - frankerfacez: { - name: "FrankerFaceZ", - note: "Show emotes from FFZ" - }, - bttv: { - name: "BetterTTV", - note: "Show emotes from BTTV" - } - } - } - }, - Addons: { - title: "{{name}} v{{version}} by {{author}}", - byline: "by {{author}}", - openFolder: "Open {{type}} Folder", - reload: "Reload", - addonSettings: "Settings", - website: "Website", - source: "Source", - invite: "Support Server", - donate: "Donate", - patreon: "Patreon", - name: "Name", - author: "Author", - version: "Version", - added: "Date Added", - modified: "Date Modified", - search: "Search {{type}}", - editAddon: "Edit", - deleteAddon: "Delete", - confirmDelete: "Are you sure you want to delete {{name}}?", - confirmationText: "You have unsaved changes to {{name}}. Closing this window will lose all those changes.", - enabled: "{{name}} has been enabled.", - disabled: "{{name}} has been disabled.", - couldNotEnable: "{{name}} could not be enabled.", - couldNotDisable: "{{name}} could not be disabled.", - couldNotStart: "{{name}} could not be started.", - couldNotStop: "{{name}} could not be stopped.", - settingsError: "Could not open settings for {{name}}", - methodError: "{{method}} could not be fired.", - unknownAuthor: "Unknown Author", - noDescription: "Description not provided.", - alreadyExists: "There is already a {{type}} with name {{name}}", - alreadWatching: "Already watching addons.", - metaError: "META could not be parsed.", - missingNameData: "META missing name data.", - metaNotFound: "META was not found.", - compileError: "Could not be compiled.", - wasUnloaded: "{{name}} was unloaded.", - blankSlateHeader: "You don't have any {{type}}s!", - blankSlateMessage: "Grab some from [this website]({{link}}) and add them to your {{type}} folder." - }, - CustomCSS: { - confirmationText: "You have unsaved changes to your Custom CSS. Closing this window will lose all those changes.", - update: "Update", - save: "Save", - openNative: "Open in System Editor", - openDetached: "Detach Window", - settings: "Editor Settings", - editorTitle: "Custom CSS Editor" - }, - Emotes: { - loading: "Loading emotes in the background do not reload.", - loaded: "All emotes successfully loaded.", - clearEmotes: "Clear Emote Data", - favoriteAction: "Favorite!" - }, - PublicServers: { - button: "public", - join: "Join", - joining: "Joining", - joined: "Joined", - loading: "Loading", - loadMore: "Load More", - notConnected: "Not Connected", - connectionRequired: "You must connect your account in order to join servers.", - connectionError: "Connection Error", - connectionErrorMessage: "There was an error connecting to DiscordServers.com, it's possible their website/api is down. Please try again later.", - pagination: "Page {{page}} of {{count}}", - search: "Search", - connect: "Connect", - reconnect: "Reconnect", - categories: "Categories", - keywords: "Keywords", - connection: "Connected as: {{username}}#{{discriminator}}", - results: "Showing {{start}}-{{end}} of {{total}} results in {{category}}", - query: "for {{query}}" - }, - Modals: { - confirmAction: "Are You Sure?", - okay: "Okay", - done: "Done", - cancel: "Cancel", - nevermind: "Nevermind", - close: "Close", - name: "Name", - message: "Message", - error: "Error", - addonErrors: "Addon Errors", - restartRequired: "Restart Required", - restartNow: "Restart Now", - restartLater: "Restart Later", - additionalInfo: "Additional Info", - restartPrompt: "In order to take effect, Discord needs to be restarted. Do you want to restart now?" - }, - ReactDevTools: { - notFound: "Extension Not Found", - notFoundDetails: "Unable to find the React Developer Tools extension on your PC. Please install the extension on your local Chrome installation." - }, - Sorting: { - sortBy: "Sort By", - order: "Order", - ascending: "Ascending", - descending: "Descending" - }, - Startup: { - notSupported: "Not Supported", - incompatibleApp: "BetterDiscord does not work with {{app}}. Please uninstall one of them.", - updateNow: "Update Now", - maybeLater: "Maybe Later", - updateAvailable: "Update Available", - updateInfo: "There is an update available for BetterDiscord's Injector ({{version}}).\n\nYou can either update and restart now, or later.", - updateFailed: "Could Not Update", - manualUpdate: "Unable to update automatically, please download the installer and reinstall normally.\n\n[Download Installer](https://github.com/rauenzi/BetterDiscordApp/releases/latest)", - jqueryFailed: "jQuery Failed To Load", - jqueryFailedDetails: "jQuery could not be loaded, and some plugins may not work properly. Proceed at your own risk." - }, - WindowPrefs: { - enabledInfo: "This option requires a transparent theme in order to work properly. On Windows this may break your aero snapping and maximizing.\n\nIn order to take effect, Discord needs to be restarted. Do you want to restart now?", - disabledInfo: "In order to take effect, Discord needs to be restarted. Do you want to restart now?" - } -}; diff --git a/renderer/src/modules/core.js b/renderer/src/modules/core.js index d1e58d59..1f2dba99 100644 --- a/renderer/src/modules/core.js +++ b/renderer/src/modules/core.js @@ -37,12 +37,13 @@ export default new class Core { DataStore.initialize(); Logger.log("Startup", "Initializing LocaleManager"); - await LocaleManager.initialize(); + LocaleManager.initialize(); Logger.log("Startup", "Performing incompatibility checks"); 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"})); + this.checkForUpdate(); Logger.log("Startup", "Initializing Settings"); Settings.initialize(); @@ -85,8 +86,6 @@ export default new class Core { Modals.showChangelogModal(Changelog); DataStore.setBDData("version", Config.version); } - - this.checkForUpdate(); } waitForGuilds() { @@ -118,6 +117,7 @@ export default new class Core { }); const data = await resp.json(); + Object.assign(Config.release, data); const remoteVersion = data.tag_name.startsWith("v") ? data.tag_name.slice(1) : data.tag_name; const hasUpdate = remoteVersion > Config.version; if (!hasUpdate) return; diff --git a/renderer/src/modules/datastore.js b/renderer/src/modules/datastore.js index b4fd1b38..bf7e853f 100644 --- a/renderer/src/modules/datastore.js +++ b/renderer/src/modules/datastore.js @@ -39,7 +39,7 @@ export default new class DataStore { if (!newStorageExists) fs.mkdirSync(this.baseFolder); if (!fs.existsSync(this.dataFolder)) fs.mkdirSync(this.dataFolder); - if (!fs.existsSync(this.localeFolder)) fs.mkdirSync(this.localeFolder); + // if (!fs.existsSync(this.localeFolder)) fs.mkdirSync(this.localeFolder); if (!fs.existsSync(this.emoteFolder)) fs.mkdirSync(this.emoteFolder); if (!fs.existsSync(this.cacheFile)) fs.writeFileSync(this.cacheFile, JSON.stringify({})); diff --git a/renderer/src/modules/localemanager.js b/renderer/src/modules/localemanager.js index 4d174494..9e7b0099 100644 --- a/renderer/src/modules/localemanager.js +++ b/renderer/src/modules/localemanager.js @@ -1,9 +1,7 @@ -import DefaultStrings from "../data/strings"; +import * as Locales from "../../../assets/locales"; import DiscordModules from "./discordmodules"; import Utilities from "./utilities"; import Events from "./emitter"; -import DataStore from "./datastore"; -const request = require("request"); const {Dispatcher, DiscordConstants, UserSettingsStore} = DiscordModules; @@ -13,53 +11,28 @@ export default new class LocaleManager { constructor() { this.locale = ""; - this.strings = Utilities.extend({}, DefaultStrings); + this.strings = Utilities.extend({}, Locales[this.defaultLocale]); } - async initialize() { - await this.setLocale(this.discordLocale); + initialize() { + this.setLocale(this.discordLocale); Dispatcher.subscribe(DiscordConstants.ActionTypes.USER_SETTINGS_UPDATE, ({settings}) => { const newLocale = settings.locale; if (newLocale && newLocale != this.locale) this.setLocale(newLocale.split("-")[0]); }); } - async setLocale(newLocale) { + setLocale(newLocale) { let newStrings; if (newLocale != this.defaultLocale) { - newStrings = await this.getLocaleStrings(newLocale); + newStrings = Locales[newLocale]; if (!newStrings) return this.setLocale(this.defaultLocale); } else { - newStrings = DefaultStrings; + newStrings = Locales[this.defaultLocale]; } this.locale = newLocale; Utilities.extend(this.strings, newStrings); Events.emit("strings-updated"); } - - async getLocaleStrings(locale) { - const hash = DataStore.getCacheHash("locales", locale); - if (!hash) return await this.downloadLocale(locale); - const invalid = await this.downloadLocale(locale, hash); - if (!invalid) return DataStore.getLocale(locale); - return invalid; - } - - downloadLocale(locale, hash = "") { - return new Promise(resolve => { - const options = { - url: Utilities.repoUrl(`assets/locales/${locale}.json`), - timeout: 2000, - json: true - }; - if (hash) options.headers = {"If-None-Match": hash}; - request.get(options, (err, resp, newStrings) => { - if (err || resp.statusCode !== 200) return resolve(null); - DataStore.saveLocale(locale, newStrings); - DataStore.setCacheHash("locales", locale, resp.headers.etag); - resolve(newStrings); - }); - }); - } }; \ No newline at end of file diff --git a/renderer/src/modules/pluginapi.js b/renderer/src/modules/pluginapi.js index bf3c877b..8f95bebf 100644 --- a/renderer/src/modules/pluginapi.js +++ b/renderer/src/modules/pluginapi.js @@ -20,12 +20,12 @@ const BdApi = { get settings() {return Settings.collections;}, get emotes() { return new Proxy(Emotes.Emotes, { - get(category) { + get(obj, category) { if (category === "blocklist") return Emotes.blocklist; const group = Emotes.Emotes[category]; if (!group) return undefined; return new Proxy(group, { - get(emote) {return group[emote];}, + get(cat, emote) {return group[emote];}, set() {Logger.warn("BdApi.emotes", "Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins");} }); }, diff --git a/renderer/webpack.config.js b/renderer/webpack.config.js index e3a1103e..d0de4df7 100644 --- a/renderer/webpack.config.js +++ b/renderer/webpack.config.js @@ -14,15 +14,15 @@ module.exports = { path: path.resolve(__dirname, "..", "dist") }, externals: { - electron: `require("electron")`, - fs: `require("fs")`, + "electron": `require("electron")`, + "fs": `require("fs")`, "original-fs": `require("original-fs")`, - path: `require("path")`, - request: `require("request")`, - events: `require("events")`, - rimraf: `require("rimraf")`, - yauzl: `require("yauzl")`, - mkdirp: `require("mkdirp")` + "path": `require("path")`, + "request": `require("request")`, + "events": `require("events")`, + "rimraf": `require("rimraf")`, + "yauzl": `require("yauzl")`, + "mkdirp": `require("mkdirp")` }, resolve: { extensions: [".js", ".jsx"], diff --git a/scripts/emotes.js b/scripts/emotes.js new file mode 100644 index 00000000..bfb81d70 --- /dev/null +++ b/scripts/emotes.js @@ -0,0 +1,18 @@ +const path = require("path"); +const asar = require("asar"); + +const emotes = path.resolve(__dirname, "..", "assets", "emotes"); +const dist = path.resolve(__dirname, "..", "dist"); +const bundleFile = path.join(dist, "emotes.asar"); + +const makeBundle = function() { + console.log(""); + console.log("Generating bundle"); + asar.createPackage(emotes, bundleFile).then(() => { + console.log(` ✅ Successfully created bundle ${bundleFile}`); + }).catch(err => { + console.log(` ❌ Could not build bundle: ${err.message}`); + }); +}; + +makeBundle(); \ No newline at end of file diff --git a/scripts/pack.js b/scripts/pack.js index d4de7cd7..d7efc0eb 100644 --- a/scripts/pack.js +++ b/scripts/pack.js @@ -5,7 +5,7 @@ const asar = require("asar"); const doSanityChecks = require("./validate"); const buildPackage = require("./package"); -const dist = path.join(__dirname, "..", "dist"); +const dist = path.resolve(__dirname, "..", "dist"); const bundleFile = path.join(dist, "betterdiscord.asar"); const cleanOldAsar = function() { @@ -19,7 +19,7 @@ const cleanOldAsar = function() { const makeBundle = function() { console.log(""); console.log("Generating bundle"); - asar.createPackage(dist, bundleFile).then(() => { + asar.createPackageFromFiles(dist, bundleFile, ["dist/injector.js", "dist/package.json", "dist/preload.js", "dist/renderer.js"]).then(() => { console.log(` ✅ Successfully created bundle ${bundleFile}`); }).catch(err => { console.log(` ❌ Could not build bundle: ${err.message}`); @@ -28,5 +28,5 @@ const makeBundle = function() { doSanityChecks(dist); buildPackage(dist); -cleanOldAsar(); +// cleanOldAsar(); makeBundle(); \ No newline at end of file