+
{
+ notices.pop()
+ events.emit("noticeUpdate")
+ }} />
+ {this.props.text}
+ {button}
+
+ }
+}
\ No newline at end of file
diff --git a/LightcordApi/src/components/private/Notices.tsx b/LightcordApi/src/components/private/Notices.tsx
new file mode 100644
index 0000000..4ef1b36
--- /dev/null
+++ b/LightcordApi/src/components/private/Notices.tsx
@@ -0,0 +1,50 @@
+import Notice from "./Notice"
+import uuid from "../../modules/uuid"
+import { EventEmitter } from "events"
+
+export const events = new EventEmitter()
+
+export default class Notices extends React.Component<{container: any}> {
+ static displayName = "LightcordNotices"
+ static defaultProps = {}
+ constructor(props: Readonly<{ container: any }>){
+ super(props)
+
+ this.noticeHandler = this.noticeHandler.bind(this)
+ }
+
+ noticeHandler(){
+ this.forceUpdate()
+ }
+
+ componentWillMount(){
+ events.on("noticeUpdate", this.noticeHandler)
+ }
+
+ componentWillUnmount(){
+ events.off("noticeUpdate", this.noticeHandler)
+ }
+
+ render(){
+ if(!this.hasNotice)return null
+ const notice = notices[0]
+ return
+ }
+
+ get hasNotice(){
+ return notices.length > 0
+ }
+}
+
+export const notices:notice[] = []
+
+export type noticeWithoutID = {
+ text: string,
+ buttonText?: string,
+ onClick?: () => void,
+ type: "default"|"info"|"success"|"danger"|"streamerMode"|"download"|"notification"|"premium"|"richPresence"|"premiumTier1"|"premiumTier2"|"facebook"|"brand"|"survey"|"spotify"
+}
+
+export type notice = {
+ id: string
+} & noticeWithoutID
\ No newline at end of file
diff --git a/LightcordApi/src/index.ts b/LightcordApi/src/index.ts
index 942bb77..43b8083 100644
--- a/LightcordApi/src/index.ts
+++ b/LightcordApi/src/index.ts
@@ -1,65 +1,69 @@
-import WebpackLoader from "./modules/WebpackLoader"
-import Components from "./components/components"
-import uuid from "./modules/uuid"
-import Utils from "./modules/Utils"
-
-const LightcordApi = {
- WebpackLoader: WebpackLoader,
- Components: Components,
- uuid: uuid,
- Utils: Utils
-}
-
-declare global {
- var React:typeof import("react")
- interface Window {
- Lightcord: LightcordGlobal,
- BDModules: {
- modules:any[],
- get(filter:(mod:any)=>boolean, modules?:any[]):any[],
- get(id:number, modules?:any[]):any,
- get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any
- }
- }
- var Lightcord:LightcordGlobal
-}
-
-export default LightcordApi
-
-Object.assign(window.Lightcord.Api, LightcordApi)
-
-/**
- * The main Lightcord exports. Can be accessed with `window.Lightcord`
- */
-export interface LightcordGlobal {
- DiscordModules: {
- /**
- * Internal Discord's dispatcher - can be used to subscribe to gateway events / client events.
- */
- dispatcher: import("./types/DiscordDispatcherTypes").default,
- constants: import("./types/DiscordConstantsTypes").default
- },
- Settings: {
- devMode: boolean,
- callRingingBeat: boolean
- },
- Api: LightcordApiGlobal
-}
-
-/**
- * The main Api. Can be accessed with `window.Lightcord.Api`
- */
-type LightcordApiGlobal = lightcordApiMainExports & typeof LightcordApi
-
-type lightcordApiMainExports = {
- /**
- * Waits until the first module that match the filter gets exported
- * @param filter The filter that specifies the module to match.
- */
- ensureExported(filter: (mod:any) => boolean):Promise
,
- /**
- * Recreate the object without the `__proto__` and `prototype` properties - usefull for better formatting in console.
- * @param obj The object to recreate
- */
- cloneNullProto(obj:Obj):Obj
+import WebpackLoader from "./modules/WebpackLoader"
+import Components from "./components/components"
+import uuid from "./modules/uuid"
+import Utils from "./modules/Utils"
+import DiscordTools from "./modules/DiscordTools"
+import * as patchers from "./modules/patchers"
+patchers.patch()
+
+const LightcordApi = {
+ WebpackLoader: WebpackLoader,
+ Components: Components,
+ uuid: uuid,
+ Utils: Utils,
+ DiscordTools: DiscordTools
+}
+
+declare global {
+ var React:typeof import("react")
+ interface Window {
+ Lightcord: LightcordGlobal,
+ BDModules: {
+ modules:any[],
+ get(filter:(mod:any)=>boolean, modules?:any[]):any[],
+ get(id:number, modules?:any[]):any,
+ get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any
+ }
+ }
+ var Lightcord:LightcordGlobal
+}
+
+export default LightcordApi
+
+Object.assign(window.Lightcord.Api, LightcordApi)
+
+/**
+ * The main Lightcord exports. Can be accessed with `window.Lightcord`
+ */
+export interface LightcordGlobal {
+ DiscordModules: {
+ /**
+ * Internal Discord's dispatcher - can be used to subscribe to gateway events / client events.
+ */
+ dispatcher: import("./types/DiscordDispatcherTypes").default,
+ constants: import("./types/DiscordConstantsTypes").default
+ },
+ Settings: {
+ devMode: boolean,
+ callRingingBeat: boolean
+ },
+ Api: LightcordApiGlobal
+}
+
+/**
+ * The main Api. Can be accessed with `window.Lightcord.Api`
+ */
+type LightcordApiGlobal = lightcordApiMainExports & typeof LightcordApi
+
+type lightcordApiMainExports = {
+ /**
+ * Waits until the first module that match the filter gets exported
+ * @param filter The filter that specifies the module to match.
+ */
+ ensureExported(filter: (mod:any) => boolean):Promise,
+ /**
+ * Recreate the object without the `__proto__` and `prototype` properties - usefull for better formatting in console.
+ * @param obj The object to recreate
+ */
+ cloneNullProto(obj:Obj):Obj
}
\ No newline at end of file
diff --git a/LightcordApi/src/modules/DiscordTools.ts b/LightcordApi/src/modules/DiscordTools.ts
new file mode 100644
index 0000000..d67e597
--- /dev/null
+++ b/LightcordApi/src/modules/DiscordTools.ts
@@ -0,0 +1,163 @@
+import { notices, noticeWithoutID, notice, events as noticeEvents } from "../components/private/Notices";
+import Utils from "./Utils";
+import uuid from "./uuid";
+import cloneNullProto from "./cloneNullProto";
+import { EventEmitter } from "events";
+import { defaultNotice } from "../components/private/Notice";
+import excludeProperties from "./excludeProperties";
+import NOOP from "./noop";
+import WebpackLoader, { WebpackLoaderError } from "./WebpackLoader";
+
+let soundModule
+export default new class DiscordTools {
+ showNotice(data:NoticeData):Notice{
+ if(typeof data !== "object" || typeof data.text !== "string")throw new Error(`This notice is not valid. Given: ${Utils.formatJSObject(data)}`)
+ let newData = cloneNullProto(Object.assign({}, defaultNotice, data)) as notice
+ newData.id = uuid()
+ notices.push(newData)
+ noticeEvents.emit("noticeUpdate")
+ const notice = new Notice(newData)
+ return notice
+ }
+
+ get notices():Notice[]{
+ return notices.map(data => new Notice(data))
+ }
+
+ /**
+ * Quickly send notification (Even when no focused.)
+ * @param data The notification. Be sure to include all properties except functions cause they're optional.
+ * Notifications have a timeout of 3-5 seconds.
+ * They look like this: https://i.imgur.com/jzuxKKu.png
+ */
+ showNotification(data:NotificationData):Notification{
+ const notification = new window.Notification(data.title, excludeProperties(data, [
+ "title",
+ "onClick",
+ "onClose",
+ "onShow"
+ ]))
+ notification.onclick = data.onClick || NOOP
+ notification.onshow = data.onShow || NOOP
+ notification.onclose = data.onClose || NOOP
+ return notification
+ }
+
+ playSound(sound:Sound){
+ soundModule = soundModule || WebpackLoader.findByUniqueProperties(["createSound"])
+ if(!soundModule)throw new WebpackLoaderError("Couldn't find soundModule here.")
+ const created = soundModule.createSound(sound)
+ created.play()
+ return created
+ }
+}
+
+export type Sound = "call_calling"|"call_ringing"|"call_ringing_beat"|"ddr-down"|"ddr-left"|"ddr-right"|"ddr-up"|"deafen"|"discodo"|"disconnect"|"human_man"|"mention1"|"mention2"|"mention3"|"message1"|"message2"|"message3"|"mute"|"overlayunlock"|"ptt_start"|"ptt_stop"|"reconnect"|"robot_man"|"stream_ended"|"stream_started"|"stream_user_joined"|"stream_user_left"|"undeafen"|"unmute"|"user_join"|"user_leave"|"user_moved"
+
+export type NotificationData = {
+ title: string,
+ body: string,
+ icon: string,
+ onShow?: () => void,
+ onClick?: () => void,
+ onClose?: () => void
+}
+
+export type NoticeData = noticeWithoutID
+
+const EventHandler = function(){
+ if(this.removed !== this.state.removed){
+ if(this.removed){
+ this.emit("removed")
+ }
+ }
+ if(this.showing !== this.state.showing){
+ if(this.showing){
+ this.emit("showing", true)
+ }else{
+ this.emit("showing", false)
+ }
+ }
+ if(this.index !== this.state.index){
+ this.emit("index", this.index)
+ }
+}
+
+/** A notice interface for modifying it and subscribing to events. */
+export class Notice extends EventEmitter {
+ constructor(data){
+ super()
+ this.data = data
+
+ this.state = {
+ removed: this.removed,
+ showing: this.showing,
+ index: this.index
+ }
+
+ let eventFunc = EventHandler.bind(this)
+ noticeEvents.on("noticeUpdate", eventFunc)
+ this.on("removed", () => {
+ noticeEvents.off("noticeUpdate", eventFunc)
+ })
+ }
+
+ state:{
+ removed:boolean,
+ showing:boolean,
+ index:number
+ }
+
+ get removed():boolean{
+ return !notices.find(e => e.id === this.id)
+ }
+ get showing():boolean{
+ return this.index === 0
+ }
+
+ get index():number{
+ return notices.findIndex(e => e.id === this.id)
+ }
+ get id(){
+ return this.data.id
+ }
+
+ get text(){
+ return this.data.text
+ }
+ set text(text){
+ this.data.text = text
+ noticeEvents.emit("noticeUpdate")
+ }
+
+ get type(){
+ return this.data.type
+ }
+ set type(type){
+ this.data.type = type
+ noticeEvents.emit("noticeUpdate")
+ }
+
+ get buttonText(){
+ return this.data.buttonText
+ }
+ set buttonText(buttonText:string){
+ this.data.buttonText = buttonText
+ noticeEvents.emit("noticeUpdate")
+ }
+
+ get onClick(){
+ return this.data.onClick
+ }
+ set onClick(onClick){
+ this.data.onClick = onClick
+ noticeEvents.emit("noticeUpdate")
+ }
+
+ remove(){
+ if(this.removed)return
+ notices.splice(this.index, 1)
+ noticeEvents.emit("noticeUpdate")
+ }
+ data:notice
+}
\ No newline at end of file
diff --git a/LightcordApi/src/modules/Utils.ts b/LightcordApi/src/modules/Utils.ts
index 9e38230..b447c89 100644
--- a/LightcordApi/src/modules/Utils.ts
+++ b/LightcordApi/src/modules/Utils.ts
@@ -31,4 +31,80 @@ export default new class Utils {
if(isNaN(res))throw new Error(`Invalid color: ${color}`)
return res
}
+
+ removeDa(className:string):string{
+ if(!className)return className
+ return className.split(" ").filter(e => !e.startsWith("da-")).join(" ")
+ }
+
+ FindReact(dom:Element, traverseUp:number = 0):React.Component|React.PureComponent{
+ /** took from https://stackoverflow.com/questions/29321742/react-getting-a-component-from-a-dom-element-for-debugging */
+ const key = Object.keys(dom).find(key=>key.startsWith("__reactInternalInstance$"));
+ const domFiber = dom[key];
+ if (domFiber == null) return null;
+
+ // react <16
+ if (domFiber._currentElement) {
+ let compFiber = domFiber._currentElement._owner;
+ for (let i = 0; i < traverseUp; i++) {
+ compFiber = compFiber._currentElement._owner;
+ }
+ return compFiber._instance;
+ }
+
+ // react 16+
+ const GetCompFiber = fiber=>{
+ //return fiber._debugOwner; // this also works, but is __DEV__ only
+ let parentFiber = fiber.return;
+ while (typeof parentFiber.type == "string") {
+ parentFiber = parentFiber.return;
+ }
+ return parentFiber;
+ };
+ let compFiber = GetCompFiber(domFiber);
+ for (let i = 0; i < traverseUp; i++) {
+ compFiber = GetCompFiber(compFiber);
+ }
+ return compFiber.stateNode;
+ }
+
+ hasClass(classNames:string, className:string):boolean{
+ if(!classNames || !className)return false
+ const classnames = classNames.split(" ")
+ for(let classname of this.removeDa(className).split(" ")){
+ if(!classnames.includes(classname))return false
+ }
+ return true
+ }
+
+ formatJSObject(obj:any):string{
+ if(["string", "number", "boolean", "bigint", "undefined"].includes(typeof obj))return JSON.stringify(obj)
+ if(obj === null)return "null"
+ if(typeof obj === "function")return String(obj)
+ if(typeof obj === "symbol")return String(obj)
+
+ if(Array.isArray(obj)){
+ if(!obj.length)return "[]"
+ return `[\n ${obj.map(e => this.formatJSObject(e)).join(",\n ")}\n]`
+ }else{
+ const keys = Object.keys(obj)
+ if(keys.length === 0)return "{}"
+ return `{\n ${keys.map(key => {
+ let original = key
+ if(typeof key === "symbol")key = "["+String(key)+"]"
+ else{
+ if(typeof key === "number")key = String(key)
+ else{
+ console.log(key)
+ if(isNaN(parseInt(key[0]))){
+ key = this.formatJSObject(key)
+ }else if(/[^\w\d_$]/g.test(key)){
+ key = this.formatJSObject(key)
+ }
+ }
+ }
+ return `${key}: ${this.formatJSObject(obj[original])}`
+ })}\n}`
+ }
+ }
}
\ No newline at end of file
diff --git a/LightcordApi/src/modules/WebpackLoader.ts b/LightcordApi/src/modules/WebpackLoader.ts
index 14fe6b3..70f699c 100644
--- a/LightcordApi/src/modules/WebpackLoader.ts
+++ b/LightcordApi/src/modules/WebpackLoader.ts
@@ -46,4 +46,12 @@ export default new class WebpackLoader {
return true
})
}
+}
+
+export class WebpackLoaderError extends Error {
+ constructor(message:string = ""){
+ message += "\n\tThis error is related to Lightcord not being able to find a WebpackModule. \n\tPlease show this error and a few lines of logs above this error. \n\tOpen an issue on https://github.com/Lightcord/Lightcord or in their discord server."
+ super(message)
+ this.name = "WebpackLoaderError"
+ }
}
\ No newline at end of file
diff --git a/LightcordApi/src/modules/patchers.ts b/LightcordApi/src/modules/patchers.ts
new file mode 100644
index 0000000..2286a5e
--- /dev/null
+++ b/LightcordApi/src/modules/patchers.ts
@@ -0,0 +1,61 @@
+import Utils from "./Utils"
+import Notices, { notices } from "../components/private/Notices"
+
+export function patch(){
+ /** START NOTICE */
+ getModule(e => e.default && e.default.displayName === "ConnectedAppView")
+ .then(async (mod) => {
+ const appClasses = await getModule(e => e.hasNotice);
+ const buildRender = original => {
+ return function render(){
+ const returnValue = original.call(this, ...arguments)
+ const newchildren = []
+ let children = returnValue.props.children[1].props.children
+ if(!Array.isArray(children))children = [children]
+
+ newchildren.push(children[0])
+ newchildren.push(React.createElement(Notices, {container: this}))
+ newchildren.push(children[1])
+ returnValue.props.children[1].props.children = newchildren
+
+ returnValue.props.children[1].props.children[2].props.children[0].props.render = buildRenderChannelSidebar(returnValue.props.children[1].props.children[2].props.children[0].props.render)
+
+ return returnValue
+ }
+ }
+ const buildRenderChannelSidebar = original => {
+ return function renderChannelSidebar(){
+ const returnValue = original.call(this, ...arguments)
+
+ const hasNotice = notices.length > 0
+ if(!hasNotice)return returnValue
+ if(!Utils.hasClass(returnValue.props.className, appClasses.hasNotice)){
+ returnValue.props.className += " "+Utils.removeDa(appClasses.hasNotice)
+ }
+
+ return returnValue
+ }
+ }
+ mod.default.prototype.render = buildRender(mod.default.prototype.render);
+ (async function(){
+ const base = document.querySelector("."+Utils.removeDa(appClasses.base))
+ if(!base)throw new Error(`Could not find base here`)
+ const elem = Utils.FindReact(base) as any
+ elem.render = buildRender(elem.render)
+ elem.forceUpdate()
+ })()
+ })
+ /** END NOTICE */
+
+
+}
+
+function getModule(filter: (mod:any) => boolean):Promise{
+ return new Promise((resolve) => {
+ window.Lightcord.Api.ensureExported(filter)
+ .then(resolve)
+ .catch(err => {
+ console.error("[LIGHTCORD]", err, filter)
+ })
+ })
+}
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/betterdiscord.js b/modules/discord_desktop_core/core/app/BetterDiscord/betterdiscord.js
new file mode 100644
index 0000000..1c89ab6
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/betterdiscord.js
@@ -0,0 +1,3 @@
+module.exports = {
+
+}
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/index.js b/modules/discord_desktop_core/core/app/BetterDiscord/index.js
index 603e78b..0f7ace3 100644
--- a/modules/discord_desktop_core/core/app/BetterDiscord/index.js
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/index.js
@@ -47,22 +47,11 @@ async function privateInit(){
ModuleLoader.get(e => e.getCurrentHub)[0].getCurrentHub().getClient().getOptions().enabled = false
// setting react in require cache
- try{
- window.React = require("react")
- }catch(e){
- const React = ModuleLoader.get(e => !["Component", "PureComponent", "Children", "createElement", "cloneElement"].map(c => !!e[c]).includes(false))[0]
- window.React = React
- require.cache["react"] = React
- }
+ const React = ModuleLoader.get(e => !["Component", "PureComponent", "Children", "createElement", "cloneElement"].map(c => !!e[c]).includes(false))[0]
+ window.React = React
-
- try{
- window.ReactDOM = require("react-dom")
- }catch(e){
- const ReactDOM = ModuleLoader.get(e => e.findDOMNode)[0]
- window.ReactDOM = ReactDOM
- require.cache["react-dom"] = ReactDOM
- }
+ const ReactDOM = ModuleLoader.get(e => e.findDOMNode)[0]
+ window.ReactDOM = ReactDOM
//stop here if betterdiscord is disabled.
if(electron.remote.process.argv.includes("--disable-betterdiscord")){
@@ -290,7 +279,7 @@ async function privateInit(){
DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme)
})
- require("../../../../../LightcordApi/js/main.js")
+ require("lightcordapi/js/main.js")
/*
if(shouldShowPrompt){
@@ -363,7 +352,7 @@ async function privateInit(){
dispatcher.subscribe(constants.ActionTypes.CONNECTION_OPEN || "CONNECTION_OPEN", onConn)
}*/
- const BetterDiscord = window.BetterDiscord = window.mainCore = new(require("../../../../../BetterDiscordApp/js/main.js").default)(BetterDiscordConfig)
+ const BetterDiscord = window.BetterDiscord = window.mainCore = new(require("../../../../../BetterDiscordApp/js/main.js").default)(BetterDiscordConfig, require("./betterdiscord"))
const Utils = window.Lightcord.BetterDiscord.Utils
const DOMTools = window.Lightcord.BetterDiscord.DOM
@@ -1247,6 +1236,10 @@ require.extensions[".jsbr"] = (m, filename) => {
fs.writeFileSync(tmpFile.name+".js", zlib.brotliDecompressSync(fs.readFileSync(filename)))
return require.extensions[".js"](m, tmpFile.name+".js")
}
+require.extensions[".txt"] = (m, filename) => {
+ m.exports = fs.readFileSync(filename, "utf8")
+ return m.exports
+}
const LightcordBDFolder = path.join(electron.remote.app.getPath("appData"), "Lightcord_BD")
@@ -1337,7 +1330,7 @@ path.originalResolve = originalResolve
let blacklist
function isBlacklisted(id){
- if(!blacklist)blacklist = fs.readFileSync(path.join(__dirname, "blacklist.txt"), "utf8").split(/[\n\r]+/g).map((line, index, lines) => {
+ if(!blacklist)blacklist = require("./blacklist.txt").split(/[\n\r]+/g).map((line, index, lines) => {
let id = ""
let comment = ""
line.split("#").forEach((idOrComment, index, array) => {
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/loaders/module-alias.js b/modules/discord_desktop_core/core/app/BetterDiscord/loaders/module-alias.js
new file mode 100644
index 0000000..a99b241
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/loaders/module-alias.js
@@ -0,0 +1,253 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, Nick Gavrilov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * From https://github.com/ilearnio/module-alias
+ */
+
+'use strict'
+
+var BuiltinModule = require('module')
+
+// Guard against poorly mocked module constructors
+var Module = module.constructor.length > 1
+ ? module.constructor
+ : BuiltinModule
+
+var nodePath = require('path')
+
+var modulePaths = []
+var moduleAliases = {}
+var moduleAliasNames = []
+
+var oldNodeModulePaths = Module._nodeModulePaths
+Module._nodeModulePaths = function (from) {
+ var paths = oldNodeModulePaths.call(this, from)
+
+ // Only include the module path for top-level modules
+ // that were not installed:
+ if (from.indexOf('node_modules') === -1) {
+ paths = modulePaths.concat(paths)
+ }
+
+ return paths
+}
+
+var oldResolveFilename = Module._resolveFilename
+Module._resolveFilename = function (request, parentModule, isMain, options) {
+ for (var i = moduleAliasNames.length; i-- > 0;) {
+ var alias = moduleAliasNames[i]
+ if (isPathMatchesAlias(request, alias)) {
+ var aliasTarget = moduleAliases[alias]
+ // Custom function handler
+ if (typeof moduleAliases[alias] === 'function') {
+ var fromPath = parentModule.filename
+ aliasTarget = moduleAliases[alias](fromPath, request, alias)
+ if (!aliasTarget || typeof aliasTarget !== 'string') {
+ throw new Error('[module-alias] Expecting custom handler function to return path.')
+ }
+ }
+ request = nodePath.join(aliasTarget, request.substr(alias.length))
+ // Only use the first match
+ break
+ }
+ }
+
+ return oldResolveFilename.call(this, request, parentModule, isMain, options)
+}
+
+function isPathMatchesAlias (path, alias) {
+ // Matching /^alias(\/|$)/
+ if (path.indexOf(alias) === 0) {
+ if (path.length === alias.length) return true
+ if (path[alias.length] === '/') return true
+ }
+
+ return false
+}
+
+function addPathHelper (path, targetArray) {
+ path = nodePath.normalize(path)
+ if (targetArray && targetArray.indexOf(path) === -1) {
+ targetArray.unshift(path)
+ }
+}
+
+function removePathHelper (path, targetArray) {
+ if (targetArray) {
+ var index = targetArray.indexOf(path)
+ if (index !== -1) {
+ targetArray.splice(index, 1)
+ }
+ }
+}
+
+function addPath (path) {
+ var parent
+ path = nodePath.normalize(path)
+
+ if (modulePaths.indexOf(path) === -1) {
+ modulePaths.push(path)
+ // Enable the search path for the current top-level module
+ var mainModule = getMainModule()
+ if (mainModule) {
+ addPathHelper(path, mainModule.paths)
+ }
+ parent = module.parent
+
+ // Also modify the paths of the module that was used to load the
+ // app-module-paths module and all of it's parents
+ while (parent && parent !== mainModule) {
+ addPathHelper(path, parent.paths)
+ parent = parent.parent
+ }
+ }
+}
+
+function addAliases (aliases) {
+ for (var alias in aliases) {
+ addAlias(alias, aliases[alias])
+ }
+}
+
+function addAlias (alias, target) {
+ moduleAliases[alias] = target
+ // Cost of sorting is lower here than during resolution
+ moduleAliasNames = Object.keys(moduleAliases)
+ moduleAliasNames.sort()
+}
+
+/**
+ * Reset any changes maded (resets all registered aliases
+ * and custom module directories)
+ * The function is undocumented and for testing purposes only
+ */
+function reset () {
+ var mainModule = getMainModule()
+
+ // Reset all changes in paths caused by addPath function
+ modulePaths.forEach(function (path) {
+ if (mainModule) {
+ removePathHelper(path, mainModule.paths)
+ }
+
+ // Delete from require.cache if the module has been required before.
+ // This is required for node >= 11
+ Object.getOwnPropertyNames(require.cache).forEach(function (name) {
+ if (name.indexOf(path) !== -1) {
+ delete require.cache[name]
+ }
+ })
+
+ var parent = module.parent
+ while (parent && parent !== mainModule) {
+ removePathHelper(path, parent.paths)
+ parent = parent.parent
+ }
+ })
+
+ modulePaths = []
+ moduleAliases = {}
+ moduleAliasNames = []
+}
+
+/**
+ * Import aliases from package.json
+ * @param {object} options
+ */
+function init (options) {
+ if (typeof options === 'string') {
+ options = { base: options }
+ }
+
+ options = options || {}
+
+ var candidatePackagePaths
+ if (options.base) {
+ candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, ''))]
+ } else {
+ // There is probably 99% chance that the project root directory in located
+ // above the node_modules directory,
+ // Or that package.json is in the node process' current working directory (when
+ // running a package manager script, e.g. `yarn start` / `npm run start`)
+ candidatePackagePaths = [nodePath.join(__dirname, '../..'), process.cwd()]
+ }
+
+ var npmPackage
+ var base
+ for (var i in candidatePackagePaths) {
+ try {
+ base = candidatePackagePaths[i]
+
+ npmPackage = require(nodePath.join(base, 'package.json'))
+ break
+ } catch (e) {
+ // noop
+ }
+ }
+
+ if (typeof npmPackage !== 'object') {
+ var pathString = candidatePackagePaths.join(',\n')
+ throw new Error('Unable to find package.json in any of:\n[' + pathString + ']')
+ }
+
+ //
+ // Import aliases
+ //
+
+ var aliases = npmPackage._moduleAliases || {}
+
+ for (var alias in aliases) {
+ if (aliases[alias][0] !== '/') {
+ aliases[alias] = nodePath.join(base, aliases[alias])
+ }
+ }
+
+ addAliases(aliases)
+
+ //
+ // Register custom module directories (like node_modules)
+ //
+
+ if (npmPackage._moduleDirectories instanceof Array) {
+ npmPackage._moduleDirectories.forEach(function (dir) {
+ if (dir === 'node_modules') return
+
+ var modulePath = nodePath.join(base, dir)
+ addPath(modulePath)
+ })
+ }
+}
+
+function getMainModule () {
+ return require.main._simulateRepl ? undefined : require.main
+}
+
+module.exports = init
+module.exports.addPath = addPath
+module.exports.addAlias = addAlias
+module.exports.addAliases = addAliases
+module.exports.isPathMatchesAlias = isPathMatchesAlias
+module.exports.reset = reset
+module.exports.setMain = function(main){
+ require.main = main
+}
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/README.md b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/README.md
new file mode 100644
index 0000000..b5ab4bd
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/README.md
@@ -0,0 +1 @@
+An alias for react-dom
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/index.js b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/index.js
new file mode 100644
index 0000000..f1f86b5
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/index.js
@@ -0,0 +1 @@
+module.exports = window.ReactDOM
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/package.json b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/package.json
new file mode 100644
index 0000000..44b8273
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react-dom/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "react-dom",
+ "version": "1.0.0",
+ "description": "An alias for react-dom",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/README.md b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/README.md
new file mode 100644
index 0000000..87d4320
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/README.md
@@ -0,0 +1 @@
+An alias for the react module.
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/index.js b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/index.js
new file mode 100644
index 0000000..ce30dac
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/index.js
@@ -0,0 +1 @@
+module.exports = window.React
\ No newline at end of file
diff --git a/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/package.json b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/package.json
new file mode 100644
index 0000000..ec12d67
--- /dev/null
+++ b/modules/discord_desktop_core/core/app/BetterDiscord/modules/react/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "react",
+ "version": "1.0.0",
+ "description": "An alias for the react module.",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/modules/discord_desktop_core/core/app/mainScreenPreload.js b/modules/discord_desktop_core/core/app/mainScreenPreload.js
index b9fd52a..2fdf09f 100644
--- a/modules/discord_desktop_core/core/app/mainScreenPreload.js
+++ b/modules/discord_desktop_core/core/app/mainScreenPreload.js
@@ -7,8 +7,16 @@ process.on("uncaughtException", console.error)
const ipcRenderer = require('./discord_native/ipc');
const electron = require("electron")
+const moduleAlias = require("./BetterDiscord/loaders/module-alias")
+const path = require("path")
+
electron.remote.getCurrentWindow().setBackgroundColor("#2f3136")
+moduleAlias.setMain(module)
+moduleAlias.addAlias("@lightcord/api", path.join(__dirname, "../../../../LightcordApi"))
+moduleAlias.addAlias("lightcordapi", path.join(__dirname, "../../../../LightcordApi"))
+moduleAlias.addPath(path.join(__dirname, "BetterDiscord", "modules"))
+
const TRACK_ANALYTICS_EVENT = 'TRACK_ANALYTICS_EVENT';
const TRACK_ANALYTICS_EVENT_COMMIT = 'TRACK_ANALYTICS_EVENT_COMMIT';
diff --git a/package-lock.json b/package-lock.json
index c215bb0..97f1009 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "lightcord",
- "version": "0.1.1",
+ "version": "0.1.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -721,12 +721,6 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
@@ -789,15 +783,6 @@
"dev": true,
"optional": true
},
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -884,12 +869,6 @@
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -962,17 +941,6 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -1005,35 +973,6 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
- "react": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
- "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- }
- },
- "react-dom": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
- "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2",
- "scheduler": "^0.19.1"
- }
- },
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- },
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
@@ -1127,16 +1066,6 @@
"truncate-utf8-bytes": "^1.0.0"
}
},
- "scheduler": {
- "version": "0.19.1",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
- "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
"semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
diff --git a/package.json b/package.json
index 5be1824..8d5f9a0 100644
--- a/package.json
+++ b/package.json
@@ -40,8 +40,6 @@
"@types/yauzl": "^2.9.1",
"cross-spawn": "^7.0.3",
"electron": "^8.4.0",
- "react": "^16.13.1",
- "react-dom": "^16.13.1",
"terser": "^4.7.0",
"yazl": "^2.5.1"
}