`), app);\r\n return true;\r\n }\r\n\r\n render() {\r\n const self = this;\r\n return BDV2.react.createElement(\r\n \"div\",\r\n {className: \"bd-detached-css-editor\", id: \"bd-customcss-detach-editor\"},\r\n BDV2.react.createElement(\r\n \"div\",\r\n {id: \"bd-customcss-innerpane\"},\r\n BDV2.react.createElement(\"div\", {className: \"editor-wrapper\"},\r\n BDV2.react.createElement(\"div\", {id: \"bd-customcss-editor-detached\", className: \"editor\", ref: \"editor\"}, self.css)\r\n ),\r\n BDV2.react.createElement(\r\n \"div\",\r\n {id: \"bd-customcss-attach-controls\"},\r\n BDV2.react.createElement(\r\n \"ul\",\r\n {className: \"checkbox-group\"},\r\n BDV2.react.createElement(Checkbox, {id: \"live-update\", text: \"Live Update\", onChange: self.onChange, checked: settingsCookie[\"bda-css-0\"]})\r\n ),\r\n BDV2.react.createElement(\r\n \"div\",\r\n {id: \"bd-customcss-detach-controls-button\"},\r\n BDV2.react.createElement(\r\n \"button\",\r\n {style: {borderRadius: \"3px 0 0 3px\", borderRight: \"1px solid #3f4146\"}, className: \"btn btn-primary\", onClick: () => {\r\n self.onClick(\"update\");\r\n }},\r\n \"Update\"\r\n ),\r\n BDV2.react.createElement(\r\n \"button\",\r\n {style: {borderRadius: \"0\", borderLeft: \"1px solid #2d2d2d\", borderRight: \"1px solid #2d2d2d\"}, className: \"btn btn-primary\", onClick: () => {\r\n self.onClick(\"save\");\r\n }},\r\n \"Save\"\r\n ),\r\n BDV2.react.createElement(\r\n \"button\",\r\n {style: {borderRadius: \"0 3px 3px 0\", borderLeft: \"1px solid #3f4146\"}, className: \"btn btn-primary\", onClick: () => {\r\n self.onClick(\"attach\");\r\n }},\r\n \"Attach\"\r\n ),\r\n BDV2.react.createElement(\r\n \"span\",\r\n {style: {fontSize: \"10px\", marginLeft: \"5px\"}},\r\n \"Unsaved changes are lost on attach\"\r\n )\r\n )\r\n )\r\n )\r\n );\r\n }\r\n\r\n onChange(id, checked) {\r\n switch (id) {\r\n case \"live-update\":\r\n settingsCookie[\"bda-css-0\"] = checked;\r\n Settings.saveSettings();\r\n break;\r\n }\r\n }\r\n\r\n onClick(id) {\r\n const self = this;\r\n switch (id) {\r\n case \"attach\":\r\n if (DOM.query(\"#editor-detached\")) self.props.attach();\r\n BDV2.reactDom.unmountComponentAtNode(self.root);\r\n self.root.remove();\r\n break;\r\n case \"update\":\r\n self.updateCss();\r\n break;\r\n case \"save\":\r\n self.saveCss();\r\n break;\r\n }\r\n }\r\n\r\n updateCss() {\r\n DOM.removeStyle(\"customcss\");\r\n DOM.addStyle(\"customcss\", this.editor.session.getValue());\r\n }\r\n\r\n saveCss() {\r\n DataStore.setBDData(\"bdcustomcss\", Buffer.from(this.editor.session.getValue(), \"utf-8\").toString(\"base64\"));\r\n }\r\n}","import {settingsCookie} from \"../0globals\";\r\nimport Settings from \"../modules/settingsPanel\";\r\nimport BDV2 from \"../modules/v2\";\r\nimport DataStore from \"../modules/dataStore\";\r\nimport DOM from \"../modules/domtools\";\r\nimport Utils from \"../modules/utils\"\r\n\r\nimport SettingsTitle from \"./settingsTitle\";\r\nimport Checkbox from \"./checkbox\";\r\nimport V2C_CssEditorDetached from \"./cssEditorDetached\";\r\n\r\nexport default class V2C_CssEditor extends BDV2.reactComponent {\r\n\r\n constructor(props) {\r\n super(props);\r\n const self = this;\r\n self.props.lines = 0;\r\n self.setInitialState();\r\n self.attach = self.attach.bind(self);\r\n self.detachedEditor = BDV2.react.createElement(V2C_CssEditorDetached, {attach: self.attach});\r\n self.onClick = self.onClick.bind(self);\r\n self.updateCss = self.updateCss.bind(self);\r\n self.saveCss = self.saveCss.bind(self);\r\n self.detach = self.detach.bind(self);\r\n }\r\n\r\n setInitialState() {\r\n this.state = {\r\n detached: this.props.detached || BDV2.editorDetached\r\n };\r\n }\r\n\r\n componentDidMount() {\r\n // this.updateLineCount();\r\n this.editor = ace.edit(\"bd-customcss-editor\");\r\n this.editor.setTheme(\"ace/theme/discord\");\r\n this.editor.session.setMode(\"ace/mode/css\");\r\n this.editor.setShowPrintMargin(false);\r\n this.editor.setFontSize(14);\r\n this.editor.on(\"change\", () => {\r\n if (!settingsCookie[\"bda-css-0\"]) return;\r\n this.saveCss();\r\n this.updateCss();\r\n });\r\n }\r\n\r\n componentWillUnmount() {\r\n this.editor.destroy();\r\n }\r\n\r\n componentDidUpdate(prevProps, prevState) {\r\n const self = this;\r\n if (prevState.detached && !self.state.detached) {\r\n BDV2.reactDom.unmountComponentAtNode(self.detachedRoot);\r\n }\r\n }\r\n\r\n codeMirror() {\r\n }\r\n\r\n get options() {\r\n return {\r\n lineNumbers: true,\r\n mode: \"css\",\r\n indentUnit: 4,\r\n theme: \"material\",\r\n scrollbarStyle: \"simple\"\r\n };\r\n }\r\n\r\n get css() {\r\n const _ccss = DataStore.getBDData(\"bdcustomcss\");\r\n let ccss = \"\";\r\n if (_ccss && _ccss !== \"\") {\r\n ccss = Buffer.from(_ccss, \"base64\").toString(\"utf8\");\r\n }\r\n return ccss;\r\n }\r\n\r\n updateLineCount() {\r\n const lineCount = this.refs.editor.value.split(\"\\n\").length;\r\n if (lineCount == this.props.lines) return;\r\n this.refs.lines.textContent = Array.from(new Array(lineCount), (_, i) => i + 1).join(\".\\n\") + \".\";\r\n this.props.lines = lineCount;\r\n }\r\n\r\n render() {\r\n const self = this;\r\n\r\n const {detached} = self.state;\r\n return [\r\n detached && BDV2.react.createElement(\r\n \"div\",\r\n {id: \"editor-detached\"},\r\n BDV2.react.createElement(SettingsTitle, {text: \"Custom CSS Editor\"}),\r\n BDV2.react.createElement(\r\n \"h3\",\r\n null,\r\n \"Editor Detached\"\r\n ),\r\n BDV2.react.createElement(\r\n \"button\",\r\n {className: \"btn btn-primary\", onClick: () => {\r\n self.attach();\r\n }},\r\n \"Attach\"\r\n )\r\n ),\r\n !detached && BDV2.react.createElement(\r\n \"div\",\r\n null,\r\n BDV2.react.createElement(SettingsTitle, {text: \"Custom CSS Editor\"}),\r\n BDV2.react.createElement(\"div\", {className: \"editor-wrapper\"},\r\n BDV2.react.createElement(\"div\", {id: \"bd-customcss-editor\", className: \"editor\", ref: \"editor\"}, self.css)\r\n ),\r\n BDV2.react.createElement(\r\n \"div\",\r\n {id: \"bd-customcss-attach-controls\"},\r\n BDV2.react.createElement(\r\n \"ul\",\r\n {className: \"checkbox-group\"},\r\n BDV2.react.createElement(Checkbox, {id: \"live-update\", text: \"Live Update\", onChange: this.onChange, checked: settingsCookie[\"bda-css-0\"]})\r\n ),\r\n BDV2.react.createElement(\r\n \"div\",\r\n {id: \"bd-customcss-detach-controls-button\"},\r\n BDV2.react.createElement(\r\n \"button\",\r\n {style: {borderRadius: \"3px 0 0 3px\", borderRight: \"1px solid #3f4146\"}, className: \"btn btn-primary\", onClick: () => {\r\n self.onClick(\"update\");\r\n }},\r\n \"Update\"\r\n ),\r\n BDV2.react.createElement(\r\n \"button\",\r\n {style: {borderRadius: \"0\", borderLeft: \"1px solid #2d2d2d\", borderRight: \"1px solid #2d2d2d\"}, className: \"btn btn-primary\", onClick: () => {\r\n self.onClick(\"save\");\r\n }},\r\n \"Save\"\r\n ),\r\n BDV2.react.createElement(\r\n \"button\",\r\n {style: {borderRadius: \"0 3px 3px 0\", borderLeft: \"1px solid #3f4146\"}, className: \"btn btn-primary\", onClick: () => {\r\n self.onClick(\"detach\");\r\n }},\r\n \"Detach\"\r\n ),\r\n BDV2.react.createElement(\r\n \"span\",\r\n {style: {fontSize: \"10px\", marginLeft: \"5px\"}},\r\n \"Unsaved changes are lost on detach\"\r\n ),\r\n BDV2.react.createElement(\"div\", {className: \"help-text\"},\r\n \"Press \",\r\n BDV2.react.createElement(\"code\", {className: \"inline\"}, \"ctrl\"),\r\n \"+\",\r\n BDV2.react.createElement(\"span\", {className: \"inline\"}, \",\"),\r\n \" with the editor focused to access the editor's settings.\"\r\n )\r\n )\r\n )\r\n )\r\n ]\r\n }\r\n\r\n onClick(arg) {\r\n const self = this;\r\n switch (arg) {\r\n case \"update\":\r\n self.updateCss();\r\n break;\r\n case \"save\":\r\n self.saveCss();\r\n break;\r\n case \"detach\":\r\n self.detach();\r\n break;\r\n }\r\n }\r\n\r\n onChange(id, checked) {\r\n switch (id) {\r\n case \"live-update\":\r\n settingsCookie[\"bda-css-0\"] = checked;\r\n Settings.saveSettings();\r\n break;\r\n }\r\n }\r\n\r\n updateCss() {\r\n DOM.removeStyle(\"customcss\");\r\n DOM.addStyle(\"customcss\", this.editor.session.getValue());\r\n }\r\n\r\n saveCss() {\r\n DataStore.setBDData(\"bdcustomcss\", Buffer.from(this.editor.session.getValue(), \"utf-8\").toString(\"base64\"));\r\n }\r\n\r\n detach() {\r\n const self = this;\r\n self.setState({\r\n detached: true\r\n });\r\n const droot = self.detachedRoot;\r\n if (!droot) {\r\n console.log(\"FAILED TO INJECT ROOT: .app\");\r\n return;\r\n }\r\n BDV2.reactDom.render(self.detachedEditor, droot);\r\n }\r\n\r\n get detachedRoot() {\r\n const _root = DOM.query(\"#bd-customcss-detach-container\");\r\n if (!_root) {\r\n if (!this.injectDetachedRoot()) return null;\r\n return this.detachedRoot;\r\n }\r\n return _root;\r\n }\r\n\r\n injectDetachedRoot() {\r\n const app = DOM.query(\".app, .\"+Utils.removeDa(BDModules.get(e => e.app && e.layers)[0].app));\r\n if (!app) return false;\r\n DOM.insertAfter(DOM.createElement(`
`), app);\r\n return true;\r\n }\r\n\r\n attach() {\r\n const self = this;\r\n self.setState({\r\n detached: false\r\n });\r\n }\r\n}","import BDV2 from \"../modules/v2\";\r\n\r\nexport default class BDErrorBoundary extends BDV2.reactComponent {\r\n constructor(props) {\r\n super(props);\r\n this.state = {hasError: false};\r\n }\r\n\r\n componentDidCatch() {\r\n this.setState({hasError: true});\r\n }\r\n\r\n render() {\r\n if (this.state.hasError) return BDV2.react.createElement(\"div\", {className: \"react-error\"}, \"Component Error\"); \r\n return this.props.children; \r\n }\r\n}\r\n\r\nconst originalRender = BDErrorBoundary.prototype.render;\r\nObject.defineProperty(BDErrorBoundary.prototype, \"render\", {\r\n enumerable: false,\r\n configurable: false,\r\n set: function() {console.warn(\"Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins\");},\r\n get: () => originalRender\r\n}); ","import BDV2 from \"../modules/v2\";\r\n\r\nexport default class V2C_ContentColumn extends BDV2.reactComponent {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n static get displayName() {return \"ContentColumn\";}\r\n\r\n render() {\r\n //let contentModule = BDModules.get(e => e.contentColumn)[0]\r\n let title = this.props.title ? BDV2.react.createElement(\"h2\", {className: \"ui-form-title h2 margin-reset margin-bottom-20\"}, this.props.title) : null\r\n return [\r\n title,\r\n this.props.children\r\n ]\r\n return BDV2.react.createElement(\r\n \"div\",\r\n {className: contentModule.contentColumn + \" \"+contentModule.contentColumnDefault+\" content-column default\", style: {padding: \"60px 40px 0px\"}},\r\n title,\r\n this.props.children\r\n );\r\n }\r\n}","import BDV2 from \"../modules/v2\";\r\n\r\nexport default class V2C_ReloadIcon extends BDV2.reactComponent {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n return BDV2.react.createElement(\"svg\", {\r\n xmlns: \"http://www.w3.org/2000/svg\",\r\n viewBox: \"0 0 24 24\",\r\n fill: \"#dcddde\",\r\n className: \"bd-reload \" + this.props.className,\r\n onClick: this.props.onClick,\r\n style: {width: this.props.size || \"24px\", height: this.props.size || \"24px\"}\r\n },\r\n BDV2.react.createElement(\"path\", {d: \"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"}),\r\n BDV2.react.createElement(\"path\", {fill: \"none\", d: \"M0 0h24v24H0z\"})\r\n );\r\n }\r\n}","import BDV2 from \"../../modules/v2\";\r\n\r\nconst React = BDV2.React;\r\n\r\nexport default class Edit extends React.Component {\r\n render() {\r\n const size = this.props.size || \"24px\";\r\n return
;\r\n }\r\n}","import BDV2 from \"../../modules/v2\";\r\n\r\nconst React = BDV2.React;\r\n\r\nexport default class Delete extends React.Component {\r\n render() {\r\n const size = this.props.size || \"24px\";\r\n return
;\r\n }\r\n}","import {settingsCookie} from \"../0globals\";\r\nimport BDV2 from \"../modules/v2\";\r\nimport Utils from \"../modules/utils\";\r\nimport DOM from \"../modules/domtools\";\r\n\r\nimport XSvg from \"./xSvg\";\r\nimport ReloadIcon from \"./reloadIcon\";\r\nimport EditIcon from \"./icons/edit\";\r\nimport DeleteIcon from \"./icons/delete\";\r\nimport Switch from \"./components/switch\";\r\nimport TooltipWrap from \"./tooltipWrap\";\r\nimport { processFile } from \"../modules/pluginCertifier\";\r\nimport contentManager from \"../modules/contentManager\";\r\nimport { resolve } from \"path\";\r\n\r\nconst React = BDV2.React;\r\nconst anchorClasses = BDV2.anchorClasses;\r\n\r\nexport default class V2C_PluginCard extends BDV2.reactComponent {\r\n\r\n constructor(props) {\r\n super(props);\r\n this.onChange = this.onChange.bind(this);\r\n this.showSettings = this.showSettings.bind(this);\r\n this.setInitialState();\r\n this.hasSettings = this.props.addon.plugin && typeof(this.props.addon.plugin.getSettingsPanel) === \"function\";\r\n this.settingsPanel = \"\";\r\n\r\n this.edit = this.edit.bind(this);\r\n this.delete = this.delete.bind(this);\r\n this.reload = this.reload.bind(this);\r\n }\r\n\r\n setInitialState() {\r\n this.state = {\r\n checked: this.props.enabled,\r\n settings: false,\r\n reloads: 0,\r\n trusted: false\r\n };\r\n }\r\n\r\n showSettings() {\r\n if (!this.hasSettings) return;\r\n this.setState({settings: true});\r\n }\r\n\r\n closeSettings() {\r\n this.panelRef.current.innerHTML = \"\";\r\n this.setState({settingsOpen: false});\r\n }\r\n\r\n componentDidUpdate() {\r\n if (!this.state.settings) return;\r\n if (typeof this.settingsPanel === \"object\") {\r\n this.refs.settingspanel.appendChild(this.settingsPanel);\r\n }\r\n\r\n if (!settingsCookie[\"fork-ps-3\"]) return;\r\n setImmediate(() => {\r\n const isHidden = (container, element) => {\r\n if(!container){\r\n console.error(new Error(`Container is undefined.`))\r\n return false\r\n }\r\n const cTop = container.scrollTop;\r\n const cBottom = cTop + container.clientHeight;\r\n const eTop = element.offsetTop;\r\n const eBottom = eTop + element.clientHeight;\r\n return (eTop < cTop || eBottom > cBottom);\r\n };\r\n\r\n const thisNode = this.refs.cardNode;\r\n const container = thisNode.closest(\"div[class*=\\\"contentRegionScroller-\\\"]\")\r\n if (!isHidden(container, thisNode)) return;\r\n const thisNodeOffset = DOM.offset(thisNode);\r\n const containerOffset = DOM.offset(container);\r\n const original = container.scrollTop;\r\n const endPoint = thisNodeOffset.top - containerOffset.top + container.scrollTop - 30;\r\n DOM.animate({\r\n duration: 300,\r\n update: function(progress) {\r\n if (endPoint > original) container.scrollTop = original + (progress * (endPoint - original));\r\n else container.scrollTop = original - (progress * (original - endPoint));\r\n }\r\n });\r\n });\r\n }\r\n\r\n\r\n getString(value) {\r\n if (!value) return \"???\";\r\n return typeof value == \"string\" ? value : value.toString();\r\n }\r\n\r\n get settingsComponent() {\r\n try { this.settingsPanel = this.props.addon.plugin.getSettingsPanel(); }\r\n catch (err) { Utils.err(\"Plugins\", \"Unable to get settings panel for \" + this.name + \".\", err); }\r\n\r\n return BDV2.react.createElement(\"div\", {className: \"bd-card bd-addon-card settings-open ui-switch-item\", ref: \"cardNode\"},\r\n BDV2.react.createElement(\"div\", {style: {\"float\": \"right\", \"cursor\": \"pointer\"}, onClick: () => {\r\n this.refs.settingspanel.innerHTML = \"\";\r\n this.setState({settings: false});\r\n }},\r\n BDV2.react.createElement(XSvg, null)\r\n ),\r\n typeof this.settingsPanel === \"object\" && BDV2.react.createElement(\"div\", {id: `plugin-settings-${this.name}`, className: \"plugin-settings\", ref: \"settingspanel\"}),\r\n typeof this.settingsPanel !== \"object\" && BDV2.react.createElement(\"div\", {id: `plugin-settings-${this.name}`, className: \"plugin-settings\", ref: \"settingspanel\", dangerouslySetInnerHTML: {__html: this.settingsPanel}})\r\n );\r\n }\r\n\r\n buildTitle(name, version, author) {\r\n const title = \"{{name}} v{{version}} by {{author}}\".split(/({{[A-Za-z]+}})/);\r\n const nameIndex = title.findIndex(s => s == \"{{name}}\");\r\n if (nameIndex) title[nameIndex] = React.createElement(\"span\", {className: \"name bda-name\"}, name);\r\n const versionIndex = title.findIndex(s => s == \"{{version}}\");\r\n if (nameIndex) title[versionIndex] = React.createElement(\"span\", {className: \"version bda-version\"}, version);\r\n const authorIndex = title.findIndex(s => s == \"{{author}}\");\r\n if (nameIndex) {\r\n const props = {className: \"author bda-author\"};\r\n if (author.link || author.id) {\r\n props.className += ` ${anchorClasses.anchor} ${anchorClasses.anchorUnderlineOnHover}`;\r\n props.target = \"_blank\";\r\n\r\n if (author.link) props.href = author.link;\r\n if (author.id) props.onClick = () => {BDV2.LayerStack.popLayer(); BDV2.openDM(author.id);};\r\n }\r\n title[authorIndex] = React.createElement(author.link || author.id ? \"a\" : \"span\", props, author.name);\r\n }\r\n return title.flat();\r\n }\r\n\r\n makeLink(title, url) {\r\n const props = {className: \"bda-link bda-link-website\", target: \"_blank\"};\r\n if (typeof(url) == \"string\") props.href = url;\r\n if (typeof(url) == \"function\") props.onClick = (event) => {event.preventDefault(); event.stopPropagation(); url();};\r\n return BDV2.react.createElement(\"a\", props, title);\r\n }\r\n\r\n makeButton(title, children, action) {\r\n return
\r\n {children}
\r\n ;\r\n }\r\n\r\n componentWillUnmount(){\r\n this.unmounted = true\r\n }\r\n\r\n get links() {\r\n const links = [];\r\n const addon = this.props.addon;\r\n if (addon.website) links.push(this.makeLink(\"Website\", addon.website));\r\n if (addon.source) links.push(this.makeLink(\"Source\", addon.source));\r\n if (addon.invite) {\r\n links.push(this.makeLink(\"Support Server\", () => {\r\n const tester = /\\.gg\\/(.*)$/;\r\n let code = addon.invite;\r\n if (tester.test(code)) code = code.match(tester)[1];\r\n BDV2.LayerStack.popLayer();\r\n BDV2.InviteActions.acceptInviteAndTransitionToInviteChannel(code);\r\n }));\r\n }\r\n if (addon.donate) links.push(this.makeLink(\"Donate\", addon.donate));\r\n if (addon.patreon) links.push(this.makeLink(\"Patreon\", addon.patreon));\r\n return links;\r\n }\r\n\r\n get footer() {\r\n const links = this.links;\r\n return (links.length || this.hasSettings) && BDV2.react.createElement(\"div\", {className: \"bd-card-footer bda-footer\"},\r\n BDV2.react.createElement(\"span\", {className: \"bd-addon-links bda-links\"},\r\n ...(links.map((element, index) => index < links.length - 1 ? [element, \" | \"] : element).flat())\r\n ),\r\n this.hasSettings && BDV2.react.createElement(\"button\", {onClick: this.showSettings, className: \"bd-button bda-settings-button\", disabled: !this.state.checked}, \"Settings\")\r\n );\r\n }\r\n\r\n onChange() {\r\n this.props.toggle && this.props.toggle(this.name);\r\n this.setState({checked: !this.state.checked});\r\n }\r\n\r\n edit() {this.props.edit(this.name);}\r\n delete() {this.props.remove(this.name);}\r\n reload() {this.props.reload(this.name);}\r\n\r\n get name() {return this.getString(this.props.addon.plugin ? this.props.addon.plugin.getName() : this.props.addon.name);}\r\n get author() {return this.getString(this.props.addon.plugin ? this.props.addon.plugin.getAuthor() : this.props.addon.author);}\r\n get description() {return this.getString(this.props.addon.plugin ? this.props.addon.plugin.getDescription() : this.props.addon.description);}\r\n get version() {return this.getString(this.props.addon.plugin ? this.props.addon.plugin.getVersion() : this.props.addon.version);}\r\n\r\n render() {\r\n if (this.state.settings) return this.settingsComponent;\r\n const {authorId, authorLink} = this.props.addon;\r\n\r\n const style = {}\r\n if(settingsCookie[\"fork-ps-6\"]){\r\n if(!this.isScanning){\r\n this.isScanning = true\r\n processFile(resolve(this.props.addon.filename.endsWith(\".plugin.js\") ? contentManager.pluginsFolder : contentManager.themesFolder, this.props.addon.filename), (result) => {\r\n if(this.unmounted)return\r\n \r\n this.setState({\r\n isTrusted: result.suspect ? \"suspect\" : true\r\n })\r\n }, () => {})\r\n }else{\r\n if(this.state.isTrusted === true){\r\n style.borderColor = \"#4087ed\"\r\n }\r\n if(this.state.isTrusted === \"suspect\"){\r\n style.borderColor = \"rgb(240, 71, 71)\"\r\n }\r\n }\r\n }\r\n \r\n return BDV2.react.createElement(\"div\", {className: \"bd-card bd-addon-card settings-closed ui-switch-item\", style},\r\n BDV2.react.createElement(\"div\", {className: \"bd-addon-header bda-header\"},\r\n BDV2.react.createElement(\"div\", {className: \"bd-card-title bda-header-title\"}, this.buildTitle(this.name, this.version, {name: this.author, id: authorId, link: authorLink})),\r\n BDV2.react.createElement(\"div\", {className: \"bd-addon-controls bda-controls\"},\r\n this.props.edit && this.makeButton(\"Edit\",
, this.edit),\r\n this.props.remove && this.makeButton(\"Delete\",
, this.delete),\r\n this.props.reload && this.makeButton(\"Reload\",
, this.reload),\r\n React.createElement(Switch, {onChange: this.onChange, checked: this.state.checked})\r\n )\r\n ),\r\n BDV2.react.createElement(\"div\", {className: \"bd-scroller-wrap bda-description-wrap scroller-wrap fade\"},\r\n BDV2.react.createElement(\"div\", {className: \"bd-scroller bd-addon-description bda-description scroller\"}, this.description)\r\n ),\r\n this.footer\r\n );\r\n }\r\n}\r\n\r\nconst originalRender = V2C_PluginCard.prototype.render;\r\nObject.defineProperty(V2C_PluginCard.prototype, \"render\", {\r\n enumerable: false,\r\n configurable: false,\r\n set: function() {console.warn(\"Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins\");},\r\n get: () => originalRender\r\n});","import BDV2 from \"../../modules/v2\";\r\n\r\nconst React = BDV2.React;\r\n\r\nexport default class DownArrow extends React.Component {\r\n render() {\r\n const size = this.props.size || \"16px\";\r\n return
;\r\n }\r\n}","import BDV2 from \"../../modules/v2\";\r\nimport Arrow from \"../icons/downarrow\";\r\n\r\nconst React = BDV2.React;\r\n\r\n\r\nexport default class Select extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {open: false, value: this.props.value || this.props.options[0].value};\r\n this.dropdown = React.createRef();\r\n this.onChange = this.onChange.bind(this);\r\n this.showMenu = this.showMenu.bind(this);\r\n this.hideMenu = this.hideMenu.bind(this);\r\n }\r\n\r\n showMenu(event) {\r\n event.preventDefault();\r\n this.setState({open: true}, () => {\r\n document.addEventListener(\"click\", this.hideMenu);\r\n });\r\n }\r\n\r\n hideMenu() {\r\n this.setState({open: false}, () => {\r\n document.removeEventListener(\"click\", this.hideMenu);\r\n });\r\n }\r\n\r\n onChange(value) {\r\n this.setState({value});\r\n if (this.props.onChange) this.props.onChange(value);\r\n }\r\n\r\n get selected() {return this.props.options.find(o => o.value == this.state.value);}\r\n\r\n get options() {\r\n const selected = this.selected;\r\n return
\r\n {this.props.options.map(opt => \r\n
{opt.label}
\r\n )}\r\n
;\r\n }\r\n\r\n render() {\r\n const style = this.props.style == \"transparent\" ? \" bd-select-transparent\" : \"\";\r\n const isOpen = this.state.open ? \" menu-open\" : \"\";\r\n return
\r\n
{this.selected.label}
\r\n
\r\n {this.state.open && this.options}\r\n
;\r\n }\r\n}\r\n\r\n// return
\r\n//
\r\n//
\r\n//
\r\n//
{this.selected.label}
\r\n//
\r\n//
\r\n//
\r\n// {this.state.open && this.options}\r\n//
;","import BDV2 from \"../../modules/v2\";\r\n\r\nconst React = BDV2.React;\r\n\r\nexport default class Search extends React.Component {\r\n render() {\r\n const size = this.props.size || \"16px\";\r\n return
;\r\n }\r\n}","import BDV2 from \"../../modules/v2\";\r\nimport SearchIcon from \"../icons/search\";\r\n\r\nconst React = BDV2.React;\r\n\r\nexport default class Search extends React.Component {\r\n constructor(props){\r\n super(props)\r\n this.state = {\r\n focused: false\r\n }\r\n }\r\n render() {\r\n const className = [\"bd-search-wrapper\"]\r\n if(this.state.focused)className.push(\"focused\")\r\n return
\r\n {\r\n this.setState({focused: true})\r\n }} onBlur={() => {\r\n this.setState({focused: false})\r\n }}/>\r\n \r\n
;\r\n }\r\n}","import ErrorBoundary from \"./errorBoundary\";\r\nimport ContentColumn from \"./contentColumn\";\r\nimport ReloadIcon from \"./reloadIcon\";\r\nimport AddonCard from \"./addoncard\";\r\nimport Dropdown from \"./components/dropdown\";\r\nimport Search from \"./components/search\";\r\n\r\nimport {settingsCookie, pluginCookie, themeCookie, bdplugins, bdthemes} from \"../0globals\";\r\nimport ContentManager from \"../modules/contentManager\";\r\nimport BDV2 from \"../modules/v2\";\r\nimport pluginModule from \"../modules/pluginModule\";\r\nimport themeModule from \"../modules/themeModule\";\r\nimport WebpackModules from \"../modules/webpackModules\";\r\nimport BdApi from \"../modules/bdApi\";\r\nimport Utils from \"../modules/utils\";\r\nimport TooltipWrap from \"./tooltipWrap\";\r\nimport bdEvents from \"../modules/bdEvents\";\r\nimport EmulatedTooltip from \"./tooltip\";\r\n\r\nconst Tooltip = WebpackModules.findByDisplayName(\"Tooltip\");\r\n\r\nconst React = BDV2.react;\r\n\r\nexport default class CardList extends BDV2.reactComponent {\r\n constructor(props) {\r\n super(props);\r\n this.state = {sort: \"name\", ascending: true, query: \"\"};\r\n this.isPlugins = this.props.type == \"plugins\";\r\n this.cookie = this.isPlugins ? pluginCookie : themeCookie;\r\n this.manager = this.isPlugins ? pluginModule : themeModule;\r\n\r\n this.sort = this.sort.bind(this);\r\n this.reverse = this.reverse.bind(this);\r\n this.search = this.search.bind(this);\r\n\r\n this.onAddonChanges = function(){\r\n this.forceUpdate()\r\n }\r\n this.onAddonChanges = this.onAddonChanges.bind(this)\r\n }\r\n\r\n componentDidMount(){\r\n const type = (this.isPlugins ? \"plugin\" : \"theme\") + \"-\"\r\n bdEvents.on(`${type}loaded`, this.onAddonChanges)\r\n bdEvents.on(`${type}unloaded`, this.onAddonChanges)\r\n bdEvents.on(`${type}reloaded`, this.onAddonChanges)\r\n }\r\n\r\n componentWillUnmount(){\r\n const type = (this.isPlugins ? \"plugin\" : \"theme\") + \"-\"\r\n bdEvents.off(`${type}loaded`, this.onAddonChanges)\r\n bdEvents.off(`${type}unloaded`, this.onAddonChanges)\r\n bdEvents.off(`${type}reloaded`, this.onAddonChanges)\r\n }\r\n\r\n openFolder() {\r\n const shell = require(\"electron\").shell;\r\n const open = shell.openPath || shell.openItem;\r\n open(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder);\r\n }\r\n\r\n edit(name) {\r\n console.log(name);\r\n this.manager.edit(name);\r\n }\r\n\r\n async delete(name) {\r\n const shouldDelete = await this.confirmDelete(name);\r\n if (!shouldDelete) return;\r\n this.manager.delete(name);\r\n }\r\n\r\n confirmDelete(name) {\r\n return new Promise(resolve => {\r\n BdApi.showConfirmationModal(\"Are You Sure?\", `Are you sure you want to delete ${name}?`, {\r\n danger: true,\r\n confirmText: \"Delete\",\r\n onConfirm: () => {resolve(true);},\r\n onCancel: () => {resolve(false);}\r\n });\r\n });\r\n }\r\n\r\n get sortOptions() {\r\n return [\r\n {label: \"Name\", value: \"name\"},\r\n {label: \"Author\", value: \"author\"},\r\n {label: \"Version\", value: \"version\"},\r\n {label: \"Recently Added\", value: \"added\"},\r\n {label: \"Last Modified\", value: \"modified\"},\r\n {label: \"File Size\", value: \"size\"},\r\n ];\r\n }\r\n\r\n get directions() {\r\n return [\r\n {label: \"Ascending\", value: true},\r\n {label: \"Descending\", value: false}\r\n ];\r\n }\r\n\r\n reverse(value) {\r\n this.setState({ascending: value});\r\n }\r\n\r\n sort(value) {\r\n this.setState({sort: value});\r\n }\r\n\r\n search(event) {\r\n this.setState({query: event.target.value.toLocaleLowerCase()});\r\n }\r\n\r\n getProps(addon) {\r\n return {\r\n key: this.getName(addon),\r\n enabled: this.cookie[this.getName(addon)],\r\n toggle: this.manager.toggle.bind(this.manager),\r\n edit: settingsCookie[\"fork-ps-7\"] ? this.edit.bind(this) : null,\r\n remove: this.delete.bind(this),\r\n addon: addon,\r\n hash: addon.hash\r\n };\r\n }\r\n\r\n getString(value) {\r\n if (!value) return \"???\";\r\n return typeof value == \"string\" ? value : value.toString();\r\n }\r\n\r\n get list(){\r\n return this.props.type === \"plugins\" ? Object.values(bdplugins) : Object.values(bdthemes);\r\n }\r\n\r\n getAddons() {\r\n const sortedAddons = this.list.sort((a, b) => {\r\n const cap = this.state.sort.charAt(0).toUpperCase() + this.state.sort.slice(1);\r\n const first = a.plugin && a.plugin[`get${cap}`] ? this.getString(a.plugin[`get${cap}`]()) : this.getString(a[this.state.sort]);\r\n const second = b.plugin && b.plugin[`get${cap}`] ? this.getString(b.plugin[`get${cap}`]()) : this.getString(b[this.state.sort]);\r\n if (typeof(first) == \"string\") return first.toLocaleLowerCase().localeCompare(second.toLocaleLowerCase());\r\n if (first > second) return 1;\r\n if (second > first) return -1;\r\n return 0;\r\n });\r\n if (!this.state.ascending) sortedAddons.reverse();\r\n const rendered = [];\r\n for (let a = 0; a < sortedAddons.length; a++) {\r\n const addon = sortedAddons[a];\r\n if (this.state.query) {\r\n let matches = null;\r\n const name = this.getName(addon);\r\n const author = this.getAuthor(addon);\r\n const description = this.getDescription(addon);\r\n const version = this.getVersion(addon);\r\n if (name) matches = name.toLocaleLowerCase().includes(this.state.query);\r\n if (author) matches = matches || author.toLocaleLowerCase().includes(this.state.query);\r\n if (description) matches = matches || description.toLocaleLowerCase().includes(this.state.query);\r\n if (version) matches = matches || version.toLocaleLowerCase().includes(this.state.query);\r\n if (!matches) continue;\r\n }\r\n const props = this.getProps(addon);\r\n rendered.push(
);\r\n }\r\n return rendered;\r\n }\r\n\r\n getName(addon) {return this.getString(addon.plugin ? addon.plugin.getName() : addon.name);}\r\n getAuthor(addon) {return this.getString(addon.plugin ? addon.plugin.getAuthor() : addon.author);}\r\n getDescription(addon) {return this.getString(addon.plugin ? addon.plugin.getDescription() : addon.description);}\r\n getVersion(addon) {return this.getString(addon.plugin ? addon.plugin.getVersion() : addon.version);}\r\n\r\n renderCheckUpdates(){\r\n if(!window.ZeresPluginLibrary)return null\r\n if(!window.PluginUpdates)return null\r\n if(typeof window.PluginUpdates.checkAll !== \"function\")return null\r\n if(!this.isPlugins)return null\r\n\r\n let tooltipIsShowing = false\r\n let tooltip\r\n return
\r\n {\r\n tooltipIsShowing = false\r\n tooltip.hide()\r\n }}>\r\n {\r\n try{\r\n Utils.showToast(\"Plugin update check in progress.\", {type: \"info\"})\r\n window.PluginUpdates.checkAll()\r\n .then(() => {\r\n Utils.showToast(\"Plugin update check complete.\", {type: \"success\"})\r\n }).catch(err => {\r\n console.error(err)\r\n Utils.showToast(\"An error occured while checking update.\", {type: \"error\"})\r\n })\r\n }catch(e){\r\n console.error(e)\r\n Utils.showToast(\"An error occured while checking update.\", {type: \"error\"})\r\n }\r\n }} wrapper={false} disabled={false} onRightClick={() => {\r\n if(!this.refs.checkUpdateButton)return\r\n if (!window.PluginUpdates || !window.PluginUpdates.plugins) return;\r\n if(tooltipIsShowing)return\r\n tooltip = new EmulatedTooltip(this.refs.checkUpdateButton.refs.original.refs.button, Object.values(window.PluginUpdates.plugins).map(p => p.name).join(\", \"), {\r\n side: \"bottom\",\r\n attachEvents: false\r\n })\r\n tooltip.show()\r\n tooltipIsShowing = true\r\n }}>\r\n Check for Updates\r\n \r\n \r\n \r\n }\r\n\r\n render() {\r\n const refreshIcon =
\r\n {(props) => \r\n {\r\n if (this.isPlugins) pluginModule.updatePluginList();\r\n else themeModule.updateThemeList();\r\n this.forceUpdate();\r\n }} />\r\n };\r\n const addonCards = this.getAddons();\r\n\r\n return
\r\n \r\n Open {this.isPlugins ? \"Plugin\" : \"Theme\"} Folder\r\n \r\n {this.renderCheckUpdates()}\r\n {!settingsCookie[\"fork-ps-5\"] && refreshIcon}\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n {addonCards}
\r\n \r\n }\r\n}\r\n\r\nconst originalRender = CardList.prototype.render;\r\nObject.defineProperty(CardList.prototype, \"render\", {\r\n enumerable: false,\r\n configurable: false,\r\n set: function() {console.warn(\"Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins\");},\r\n get: () => originalRender\r\n});","import {settingsRPC, defaultRPC} from \"../0globals\";\r\n\r\nconst dispatcher = BDModules.get(m=>m.Dispatcher&&m.default&&m.default.dispatch)[0].default\r\nconst ActionTypes = BDModules.get(m=>m.ActionTypes)[0].ActionTypes\r\n\r\nconst socketId = \"lightcord-spoof-socket\"\r\nconst pid = process.pid\r\n\r\nexport default new class CustomRichPresence {\r\n constructor(){\r\n this.enabled = false\r\n\r\n this.game = settingsRPC\r\n }\r\n \r\n get formatedGame(){\r\n if(!this.game)return null\r\n if(this.enabled === false)return null\r\n let game = {\r\n name: this.game.name || defaultRPC.name,\r\n application_id: this.game.application_id || defaultRPC.application_id,\r\n details: this.game.details || undefined,\r\n state: this.game.state || undefined,\r\n timestamps: this.game[\"timestamps.start\"] ? {\r\n start: this.game[\"timestamps.start\"]\r\n } : undefined,\r\n assets: this.game[\"assets.large\"] ? {\r\n large_image: this.game[\"assets.large\"],\r\n small_image: this.game[\"assets.small\"] || undefined\r\n } : undefined\r\n }\r\n return game\r\n }\r\n\r\n sendGame(){\r\n dispatcher.dispatch({\r\n type: ActionTypes.LOCAL_ACTIVITY_UPDATE,\r\n socketId,\r\n pid,\r\n activity: this.formatedGame\r\n }) \r\n }\r\n\r\n enable() {\r\n if(this.enabled)return\r\n this.enabled = true\r\n console.log(\"Enabling custom RichPresence\")\r\n\r\n this.set(settingsRPC || Object.create(defaultRPC))\r\n\r\n this.sendGame()\r\n }\r\n\r\n disable() {\r\n if(!this.enabled)return\r\n this.enabled = false\r\n console.log(\"Disabling custom RichPresence\")\r\n\r\n this.sendGame()\r\n }\r\n\r\n async fetchAssets(applicationId){\r\n let assets = await BDModules.get(e => e.getAssets)[0].getAssets(applicationId)\r\n if(assets.undefined && typeof assets.undefined === \"number\"){\r\n throw new Error(\"Unknown Application\")\r\n }\r\n return assets\r\n }\r\n\r\n set(activity){\r\n this.game = activity\r\n\r\n this.sendGame()\r\n }\r\n}","import BDV2 from \"../modules/v2\";\r\nimport V2C_SettingsTitle from \"./settingsTitle\";\r\nimport V2C_SettingsGroup from \"./settingsGroup\";\r\nimport dataStore from \"../modules/dataStore\";\r\nimport { defaultRPC, settingsRPC } from \"../0globals\";\r\nimport CustomRichPresence from \"../modules/CustomRichPresence\"\r\nimport { remote } from \"electron\";\r\nimport MarginTop from \"./margintop\";\r\nimport Utils from \"../modules/utils\";\r\n\r\nconst React = BDV2.React;\r\n\r\nlet V2C_PresenceSettingsModules\r\nexport default class V2C_PresenceSettings extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n data: dataStore.getSettingGroup(\"rpc\") || defaultRPC,\r\n assets: []\r\n }\r\n\r\n this.preview = null\r\n this.isfetching = false\r\n if(this.state.data.application_id){\r\n this.fetchAssets()\r\n }\r\n\r\n this.assetComponents = new Set()\r\n }\r\n\r\n updateWhenFetched(comp){\r\n this.assetComponents.add(comp)\r\n }\r\n\r\n /**\r\n * \r\n * @param {InputText} setting \r\n */\r\n onChange(setting, value){\r\n let defaultSetting = RPCProps.find(e => e.id === setting.props.id)\r\n\r\n this.setState({\r\n data: Object.assign(settingsRPC, this.state.data, {\r\n [defaultSetting.id]: !!value ? value : null\r\n }),\r\n assets: this.state.assets\r\n })\r\n if(setting.props.id === \"application_id\"){\r\n this.fetchAssets()\r\n }\r\n\r\n dataStore.setSettingGroup(\"rpc\", settingsRPC);\r\n this.preview.forceUpdate()\r\n CustomRichPresence.set(settingsRPC)\r\n }\r\n\r\n fetchAssets(){\r\n if(this.isfetching === true){\r\n let app = this.state.data.application_id\r\n setTimeout(() => {\r\n if(this.state.data.application_id !== app){\r\n return\r\n }\r\n this.fetchAssets()\r\n }, 5000);\r\n }\r\n if(!this.state.data.application_id){\r\n this.setState({\r\n data: this.state.data,\r\n assets: []\r\n })\r\n this.forceUpdate()\r\n this.assetComponents.forEach(e => e.forceUpdate())\r\n return\r\n }\r\n this.isfetching = true\r\n CustomRichPresence.fetchAssets(this.state.data.application_id)\r\n .then(assets => {\r\n this.isfetching = false\r\n this.setState({\r\n data: this.state.data,\r\n assets: Object.keys(assets).map(k => {\r\n let asset = assets[k]\r\n return {\r\n id: asset.id,\r\n name: asset.name,\r\n type: asset.type\r\n }\r\n })\r\n })\r\n this.forceUpdate()\r\n this.assetComponents.forEach(e => e.forceUpdate())\r\n }).catch(() => {\r\n this.isfetching = false\r\n this.setState({\r\n data: this.state.data,\r\n assets: []\r\n })\r\n this.forceUpdate()\r\n this.assetComponents.forEach(e => e.forceUpdate())\r\n })\r\n }\r\n\r\n updatePreview(data){\r\n this.setState({\r\n data\r\n })\r\n }\r\n\r\n get modules(){\r\n return V2C_PresenceSettingsModules || (V2C_PresenceSettingsModules = [\r\n BDModules.get(e => e.marginBottom20)[0]\r\n ])\r\n }\r\n\r\n render() {\r\n let [\r\n marginModule\r\n ] = this.modules\r\n return [\r\n
,\r\n ,\r\n ,\r\n \r\n {/** options */}\r\n {this.optionsComponents}\r\n
,\r\n \r\n \r\n \r\n {/** preview */}\r\n \r\n
,\r\n ,\r\n ,\r\n \r\n ]\r\n }\r\n\r\n get optionsComponents(){\r\n return this._optionsComponents || (this._optionsComponents = RPCProps.map(e => {\r\n if(e.type === \"text\"){\r\n return \r\n }else if(e.type === \"number\"){\r\n let array = []/*\r\n if(e.id === \"timestamps.start\"){\r\n array.unshift( {\r\n DiscordNative.clipboard.copy(Date.now()+\"\")\r\n }} />)\r\n }*/\r\n return array\r\n }else if(e.type === \"choice\"){\r\n if([\"assets.small\", \"assets.large\"].includes(e.id)){\r\n return {\r\n return {\r\n value: \"asset-\"+e.id,\r\n label: e.name\r\n }\r\n }))}/>\r\n }else{\r\n return \"Unknown choice.\"\r\n }\r\n }\r\n }))\r\n }\r\n}\r\nconst RPCProps = [\r\n {\r\n title: \"Application ID\",\r\n id: \"application_id\",\r\n type: \"number\",\r\n placeholder: \"711416957718757418\"\r\n },\r\n {\r\n title: \"Name\",\r\n id: \"name\",\r\n type: \"text\",\r\n placeholder: \"Lightcord\"\r\n },\r\n {\r\n title: \"Details\",\r\n id: \"details\",\r\n type: \"text\",\r\n placeholder: \"Browsing Discord\"\r\n },\r\n {\r\n title: \"State\",\r\n id: \"state\",\r\n type: \"text\",\r\n placeholder: \"Lightcord Client\"\r\n },\r\n {\r\n title: \"Timestamp Start\",\r\n id: \"timestamps.start\",\r\n type: \"number\",\r\n get placeholder(){\r\n return Date.now()\r\n }\r\n },\r\n {\r\n title: \"LargeAsset\",\r\n id: \"assets.large\",\r\n type: \"choice\"\r\n },\r\n {\r\n title: \"SmallAsset\",\r\n id: \"assets.small\",\r\n type: \"choice\"\r\n },\r\n]\r\n\r\nlet inputTextModules\r\nclass InputText extends React.PureComponent {\r\n get modules(){\r\n if(inputTextModules && inputTextModules[0])return inputTextModules\r\n return inputTextModules = [\r\n BDModules.get(e => e.removeKeybind)[0],\r\n BDModules.get(e => e.marginBottom20)[0],\r\n BDModules.get(e => e.defaultMarginh5)[0],\r\n BDModules.get(e => e.colorStandard)[0],\r\n BDModules.get(e => e.size32)[0],\r\n BDModules.get(e => e._horizontal)[0],\r\n BDModules.get(e => e.inputMini)[0],\r\n BDModules.get(e => e.size16 && e.size20)[0],\r\n ]\r\n }\r\n\r\n constructor(props){\r\n super(props)\r\n let setting = this.props.setting\r\n this.state = {\r\n data: this.props.manager.state.data[setting.id]\r\n }\r\n\r\n this.input = {\r\n this.setState({\r\n data: value\r\n })\r\n if(!this.lastEdited || this.lastEdited < Date.now() - 500){\r\n this.props.manager.onChange(this, value)\r\n this.lastEdited = Date.now()\r\n }else if(!this.isTiming){\r\n this.isTiming = setTimeout(() => {\r\n this.props.manager.onChange(this, this.state.data)\r\n this.isTiming = null\r\n this.lastEdited = Date.now()\r\n }, 500);\r\n }\r\n }} type=\"text\"/>\r\n }\r\n\r\n render(){\r\n let setting = this.props.setting\r\n\r\n let [\r\n rowModule,\r\n marginModule,\r\n marginModule2,\r\n colorModule,\r\n sizeModule,\r\n flexModule,\r\n inputModule,\r\n sizeModule2,\r\n ] = this.modules\r\n\r\n return (\r\n
\r\n
\r\n {setting.title}\r\n
\r\n {this.input}\r\n \r\n
\r\n
)\r\n }\r\n}\r\n\r\nlet InputNumberModules\r\nclass InputNumber extends React.PureComponent {\r\n get modules(){\r\n return InputNumberModules || (InputNumberModules = [\r\n BDModules.get(e => e.removeKeybind)[0],\r\n BDModules.get(e => e.marginBottom20)[0],\r\n BDModules.get(e => e.defaultMarginh5)[0],\r\n BDModules.get(e => e.colorStandard)[0],\r\n BDModules.get(e => e.size32)[0],\r\n BDModules.get(e => e._horizontal)[0],\r\n BDModules.get(e => e.inputMini)[0],\r\n BDModules.get(e => e.size16 && e.size20)[0],\r\n BDModules.get(e => e.colorTransparent)[0],\r\n ])\r\n }\r\n\r\n constructor(props){\r\n super(props)\r\n let setting = this.props.setting\r\n this.state = {\r\n data: this.props.manager.state.data[setting.id]\r\n }\r\n\r\n this.input = {\r\n value = value.replace(/[^\\d]+/g, \"\")\r\n if(value == this.state.data){\r\n input.setValue(value)\r\n return\r\n }\r\n\r\n if(!this.lastEdited || this.lastEdited < Date.now() - 500){\r\n this.props.manager.onChange(this, value)\r\n this.lastEdited = Date.now()\r\n }else if(!this.isTiming){\r\n this.isTiming = setTimeout(() => {\r\n this.props.manager.onChange(this, this.state.data)\r\n this.isTiming = null\r\n this.lastEdited = Date.now()\r\n }, 500);\r\n }\r\n this.setState({\r\n data: value\r\n })\r\n }} type=\"text\"/>\r\n }\r\n\r\n render(){\r\n let setting = this.props.setting\r\n\r\n let [\r\n rowModule,\r\n marginModule,\r\n marginModule2,\r\n colorModule,\r\n sizeModule,\r\n flexModule,\r\n ] = this.modules\r\n\r\n\r\n return (\r\n
\r\n
\r\n {setting.title}\r\n
\r\n {this.input}\r\n {setting.id === \"timestamps.start\" ? \r\n {\r\n DiscordNative.clipboard.copy(Date.now()+\"\")\r\n }} color=\"brand\">Copy current timestamp : null}\r\n \r\n
\r\n
)\r\n }\r\n}\r\n\r\nlet InputChoiceModules\r\nclass InputChoice extends React.PureComponent {\r\n constructor(props){\r\n super(props)\r\n let setting = this.props.setting\r\n this.state = {\r\n data: this.props.manager.state.data[setting.id] ? \"asset-\"+this.props.manager.state.data[setting.id] : \"none\"\r\n }\r\n this.props.manager.updateWhenFetched(this)\r\n }\r\n\r\n onChange(data){\r\n let value = data.value\r\n\r\n if(!this.lastEdited || this.lastEdited < Date.now() - 500){\r\n this.props.manager.onChange(this, value === \"none\" ? null : value.replace(\"asset-\", \"\"))\r\n this.lastEdited = Date.now()\r\n }else if(!this.isTiming){\r\n this.isTiming = setTimeout(() => {\r\n this.props.manager.onChange(this, this.state.data === \"none\" ? null : this.state.data.replace(\"asset-\", \"\"))\r\n this.isTiming = null\r\n this.lastEdited = Date.now()\r\n }, 500);\r\n }\r\n this.setState({\r\n data: value\r\n })\r\n this.forceUpdate()\r\n }\r\n \r\n get modules(){\r\n return InputChoiceModules || (InputChoiceModules = [\r\n BDModules.get(e => e.removeKeybind)[0],\r\n BDModules.get(e => e.marginBottom20)[0],\r\n BDModules.get(e => e.defaultMarginh5)[0],\r\n BDModules.get(e => e.colorStandard)[0],\r\n BDModules.get(e => e.size32)[0],\r\n BDModules.get(e => e._horizontal)[0]\r\n ])\r\n }\r\n\r\n render(){\r\n let setting = this.props.setting\r\n\r\n let [\r\n rowModule,\r\n marginModule,\r\n marginModule2,\r\n colorModule,\r\n sizeModule,\r\n flexModule\r\n ] = this.modules\r\n \r\n let options = this.props.manager.state.assets.map(e => {\r\n return {\r\n value: \"asset-\"+e.id,\r\n label: e.name\r\n }\r\n })\r\n\r\n options.unshift({\r\n value: \"none\",\r\n label: \"No assets\"\r\n })\r\n\r\n return (\r\n
\r\n
\r\n {setting.title}\r\n
\r\n \r\n {/*\r\n
\r\n
)\r\n }\r\n}\r\n\r\nlet DividerModules = []\r\nclass Divider extends React.PureComponent {\r\n get modules(){\r\n return DividerModules&&DividerModules[0] ? DividerModules : (DividerModules = [\r\n BDModules.get(e => e.divider && Object.keys(e).length === 1)[0],\r\n BDModules.get(e => e.dividerDefault)[0]\r\n ])\r\n }\r\n\r\n render(){\r\n let [\r\n divider,\r\n dividerDefault\r\n ] = this.modules\r\n\r\n return \r\n }\r\n}\r\n\r\nclass DiscordButton extends React.Component {\r\n render(){\r\n let rowModule = BDModules.get(e => e.removeKeybind)[0]\r\n let marginModule = BDModules.get(e => e.marginBottom20)[0]\r\n let flexModule = BDModules.get(e => e._horizontal)[0]\r\n\r\n return (\r\n
\r\n \r\n {this.props.title}\r\n \r\n
\r\n
)\r\n }\r\n}\r\n\r\nclass RpcPreview extends React.Component {\r\n constructor(props = {}){\r\n super(props)\r\n this.state = {\r\n active: \"profile\"\r\n }\r\n this.tabs = []\r\n\r\n this.props.settings.preview = this\r\n }\r\n\r\n changeTab(tab){\r\n let ancientTab = this.state.active\r\n if(ancientTab === tab.props.id)return\r\n\r\n this.tabs.forEach(e => {\r\n e.setActive(false)\r\n })\r\n tab.setActive(true)\r\n this.setState({\r\n active: tab.props.id\r\n })\r\n }\r\n\r\n render(){\r\n return (\r\n
\r\n \r\n \r\n
\r\n
\r\n
)\r\n } \r\n\r\n isActive(tab){\r\n return this.state.active === tab\r\n }\r\n\r\n get preview(){\r\n if(this.state.active === \"profile\")return Profile\r\n return Popout\r\n }\r\n}\r\n\r\nclass Tab extends React.Component {\r\n constructor(props){\r\n super(props)\r\n\r\n this.state = {\r\n active: props.preview.isActive(props.id)\r\n }\r\n props.preview.tabs.push(this)\r\n }\r\n\r\n setActive(isActive){\r\n this.setState({\r\n active: !!isActive\r\n })\r\n }\r\n\r\n render(){\r\n let className = `lc-navItem`\r\n if(this.state.active){\r\n className += ` lc-navItemActive`\r\n }else{\r\n className += ` lc-navItemInactive`\r\n }\r\n return ({\r\n this.props.preview.changeTab(this)\r\n }}>\r\n {this.props.title}\r\n
)\r\n }\r\n}\r\n\r\nlet emptyClasses\r\nclass PresenceErrorCatcher extends React.Component {\r\n componentDidCatch(err, errInfo){\r\n console.error(err, errInfo)\r\n this.setState({\r\n error: true\r\n })\r\n }\r\n render(){\r\n if(!this.state){\r\n this.state = {\r\n error: false\r\n }\r\n }\r\n if(!this.state.error){\r\n try{\r\n const preview = new this.props.preview(this.props.props)\r\n preview.setState(this.props.state)\r\n return preview.render()\r\n }catch(err){\r\n console.error(err)\r\n this.state.error = true\r\n return this.render()\r\n }\r\n }else{\r\n emptyClasses = emptyClasses || BDV2.WebpackModules.find(e => e.emptyStateImage && e.emptyState)\r\n if(!emptyClasses){\r\n Utils.showToast(\"An error occured. Please check the console for more informations.\")\r\n return null\r\n }\r\n return \r\n }\r\n }\r\n}\r\n\r\nlet popoutModules\r\nlet UserPopoutComponent\r\nlet PopoutProps\r\nclass Popout extends React.Component {\r\n get modules(){\r\n return popoutModules || (popoutModules = [\r\n BDV2.WebpackModules.find(e => e.default && e.default.displayName === \"UserPopout\"),\r\n BDV2.WebpackModules.find(e => e.default && e.default.getCurrentUser)\r\n ])\r\n }\r\n\r\n getComponent(){\r\n let [\r\n UserPopout,\r\n userModule\r\n ] = this.modules\r\n\r\n const user = userModule.default.getCurrentUser()\r\n return React.createElement(() => {\r\n let render1 = UserPopout.default({\r\n userId: user.id, \r\n guildId: null, \r\n channelId: null, \r\n disableUserProfileLink: true\r\n })\r\n UserPopoutComponent = render1.type\r\n PopoutProps = render1.props\r\n return this.render()\r\n }, null)\r\n }\r\n\r\n render(){\r\n if(!UserPopoutComponent)return this.getComponent()\r\n let [\r\n _UserPopout,\r\n userModule\r\n ] = this.modules\r\n\r\n const user = userModule.default.getCurrentUser()\r\n\r\n let data = Object.assign({}, defaultRPC, this.props.preview.props.settings.state.data)\r\n const activity = (function(){\r\n if(!this.game)return null\r\n let game = {\r\n name: this.game.name || defaultRPC.name,\r\n application_id: this.game.application_id || defaultRPC.application_id,\r\n details: this.game.details || undefined,\r\n state: this.game.state || undefined,\r\n timestamps: this.game[\"timestamps.start\"] ? {\r\n start: this.game[\"timestamps.start\"]\r\n } : undefined,\r\n assets: this.game[\"assets.large\"] ? {\r\n large_image: this.game[\"assets.large\"],\r\n small_image: this.game[\"assets.small\"] || undefined\r\n } : undefined,\r\n type: 0\r\n }\r\n return game\r\n }).call({\r\n game: data\r\n })\r\n\r\n const popout = new UserPopoutComponent(Object.assign({}, PopoutProps, {\r\n activity: activity,\r\n userId: user.id\r\n })).render().props.children // bypass tracking\r\n\r\n // remove the stop propagation shit.\r\n const container = \r\n\r\n return \r\n {container}\r\n
\r\n }\r\n}\r\n\r\nlet profileModules\r\nlet UserProfileComponent\r\nlet ProfileProps\r\nlet connectedProfileStore\r\nclass Profile extends React.Component {\r\n get modules(){\r\n return profileModules || (profileModules = [\r\n BDV2.WebpackModules.find(e => e.default && e.default.displayName === \"UserProfile\"),\r\n BDV2.WebpackModules.find(e => e.default && e.default.getCurrentUser)\r\n ])\r\n }\r\n\r\n render(){\r\n let [\r\n UserProfile,\r\n userModule\r\n ] = this.modules\r\n\r\n const user = userModule.default.getCurrentUser()\r\n if(!UserProfileComponent){\r\n const render1 = new UserProfile.default({\r\n user: user\r\n }).render()\r\n connectedProfileStore = render1.type\r\n const render2 = new render1.type(render1.props).render()\r\n const render3 = render2.type.render(render2.props, null)\r\n const render4 = new render3.type(render3.props).render()\r\n UserProfileComponent = render4.type\r\n }\r\n if(!UserProfileComponent)throw new Error(`Couldn't find the UserProfileComponent component.`)\r\n\r\n let data = Object.assign({}, defaultRPC, this.props.preview.props.settings.state.data)\r\n const activity = (function(){\r\n if(!this.game)return null\r\n let game = {\r\n name: this.game.name || defaultRPC.name,\r\n application_id: this.game.application_id || defaultRPC.application_id,\r\n details: this.game.details || undefined,\r\n state: this.game.state || undefined,\r\n timestamps: this.game[\"timestamps.start\"] ? {\r\n start: this.game[\"timestamps.start\"]\r\n } : undefined,\r\n assets: this.game[\"assets.large\"] ? {\r\n large_image: this.game[\"assets.large\"],\r\n small_image: this.game[\"assets.small\"] || undefined\r\n } : undefined,\r\n type: 0\r\n }\r\n return game\r\n }).call({\r\n game: data\r\n })\r\n\r\n ProfileProps = new connectedProfileStore({\r\n user: user,\r\n close: () => {}\r\n }).render().props\r\n const profile = new UserProfileComponent(Object.assign({}, ProfileProps, {\r\n activity: activity\r\n })).render().props.children // bypass tracking\r\n\r\n profile.props.style = {\r\n width: \"auto\"\r\n }\r\n\r\n return \r\n {profile}\r\n
\r\n }\r\n}","import BDV2 from \"../modules/v2\";\r\nimport V2C_SettingsTitle from \"./settingsTitle\";\r\n\r\n/**\r\n * @type {typeof import(\"react\")}\r\n */\r\nconst React = BDV2.React;\r\n\r\nlet marginModule2 = BDModules.get(e => e.defaultMarginh5)[0]\r\nlet colorModule = BDModules.get(e => e.colorStandard)[0]\r\nlet sizeModule = BDModules.get(e => e.size32)[0]\r\nlet scrollbarModule1 = BDModules.get(e => e.scrollbarGhostHairline)[0]\r\nconst GuildModule = BDModules.get(e => e.default && e.default.getGuilds)[0].default\r\nconst relationShipModule = BDModules.get(e => e.default && e.default.getRelationships)[0].default\r\nconst sessionModule = BDModules.get(e => e.default && e.default.getSessions)[0].default\r\nconst userModule = BDModules.get(e => e.default && e.default.getCurrentUser)[0].default\r\n\r\nexport default class V2C_AccountInfos extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n if(!marginModule2)marginModule2 = BDModules.get(e => e.defaultMarginh5)[0]\r\n if(!colorModule)colorModule = BDModules.get(e => e.colorStandard)[0]\r\n if(!sizeModule)sizeModule = BDModules.get(e => e.size32)[0]\r\n return [\r\n ,\r\n \r\n
\r\n Profile\r\n
\r\n \r\n \r\n Statistics\r\n
\r\n \r\n \r\n Connected Sessions\r\n
\r\n \r\n ,\r\n e.marginBottom20)[0].marginBottom20}>
\r\n ]\r\n }\r\n\r\n getSessionValue(){\r\n const sessionsRaw = sessionModule.getSessions()\r\n const sessions = Object.keys(sessionsRaw).filter(e => e !== \"all\").map(e => sessionsRaw[e])\r\n\r\n if(sessions.length === 0)return \"- No session detected. Please try in a few seconds\"\r\n \r\n return sessions.map(e => {\r\n return `+ id: ${e.sessionId}\r\n+ os: ${e.clientInfo.os[0].toUpperCase()+e.clientInfo.os.slice(1)}\r\n+ client: ${e.clientInfo.client}\r\n+ status: ${e.status}\r\n+ Activities: ${e.activities.length}`\r\n }).join(\"\\n\"+\"-\".repeat(38)+\"\\n\")\r\n }\r\n\r\n getProfileValue(){\r\n const user = userModule.getCurrentUser()\r\n /**\r\n * @type {Date}\r\n */\r\n const createdAt = user.createdAt\r\n\r\n let avatarURL = user.avatarURL\r\n if(user.avatar && user.avatar.startsWith(\"a_\")){\r\n avatarURL = user.getAvatarURL(\"gif\")\r\n }\r\n\r\n if(avatarURL.startsWith(\"/\")){\r\n avatarURL = \"https://discord.com\"+avatarURL\r\n }\r\n if(avatarURL.endsWith(\"?size=128\")){\r\n avatarURL = avatarURL.replace(\"?size=128\", \"?size=4096\")\r\n }\r\n\r\n return `+ Username: ${user.username}\r\n+ Discriminator: ${user.discriminator}\r\n+ Tag: ${user.tag}\r\n+ ID: ${user.id}\r\n+ Avatar: ${user.avatar}\r\n+ Avatar URL: ${avatarURL}\r\n+ Creation Date: ${(createdAt.getDate()).toString().padStart(2, \"0\")}/${(createdAt.getMonth()+1).toString().padStart(2, \"0\")}/${(createdAt.getFullYear()).toString().padStart(2, \"0\")} ${createdAt.getHours().toString().padStart(2, \"0\")}h ${createdAt.getMinutes().toString().padStart(2, \"0\")}min ${createdAt.getSeconds()}s\r\n+ Flags: ${user.flags}\r\n+ Has Nitro: ${user.hasPremiumSubscription ? \"Yes\" : \"No\"}\r\n- Email: ${user.email}\r\n- 2FA: ${user.mfaEnabled ? \"Yes\" : \"No\"}\r\n- Has Been On Mobile: ${user.mobile ? \"Yes\" : \"No\"}\r\n- Phone: ${user.phone || \"None\"}\r\n- Verified: ${user.verified}\r\n- Can See NSFW Channels: ${user.nsfwAllowed}`;\r\n }\r\n\r\n getStatistics(){\r\n\r\n const guilds = Object.values(GuildModule.getGuilds())\r\n const relations = Object.keys(relationShipModule.getRelationships())\r\n const friends = relations.filter(e => relationShipModule.isFriend(e))\r\n const blocked = relations.filter(e => relationShipModule.isBlocked(e))\r\n\r\n return `+ Server Count: ${guilds.length} servers\r\n+ Relations: ${relations.length} relations\r\n+ Friends Count: ${friends.length} friends\r\n- Blocked Users Count: ${blocked.length} blocked users`\r\n }\r\n}\r\n\r\n\r\nlet hightlightJS = BDModules.get(e => e.highlight)[0]\r\nlet messageModule1 = BDModules.get(e => e.markup)[0]\r\nlet messageModule2 = BDModules.get(e => e.messageContent)[0]\r\n\r\nclass CodeContent extends React.Component {\r\n render(){\r\n if(!messageModule1)messageModule1 = BDModules.get(e => e.markup)[0]\r\n if(!messageModule2)messageModule2 = BDModules.get(e => e.messageContent)[0]\r\n if(!scrollbarModule1)scrollbarModule1 = BDModules.get(e => e.scrollbarGhostHairline)[0]\r\n if(!hightlightJS)hightlightJS = BDModules.get(e => e.listLanguages)[0]\r\n return (\r\n
\r\n \r\n\r\n
\r\n
\r\n
e.marginBottom8)[0].marginBottom8}>
\r\n
)\r\n }\r\n}","import Utils from \"./utils\"\r\n\r\nconst dispatcher = window.Lightcord.DiscordModules.dispatcher\r\nconst ChannelModule = BDModules.get(e => e.default && e.default.getChannel && e.default.hasChannel)[0].default\r\nlet relationShipModule = BDModules.get(e => e.default && e.default.addRelationship)[0]\r\nlet DMModule = BDModules.get(e => e.default && e.default.closePrivateChannel)[0]\r\n\r\nconst blocked = {}\r\n\r\nlet userModule = BDModules.get(e => e.default && e.default.getCurrentUser)[0]\r\nfunction getCurrentUser(){\r\n if(userModule)return userModule.default.getCurrentUser()\r\n return null\r\n}\r\n\r\nexport default new class AntiBotDM {\r\n constructor(){\r\n this.antiDM = this.antiDM.bind(this)\r\n this.enabled = false\r\n }\r\n\r\n enable(){\r\n if(this.enabled)return\r\n this.enabled = true\r\n\r\n dispatcher.subscribe(\"MESSAGE_CREATE\", this.antiDM)\r\n }\r\n\r\n disable(){\r\n if(!this.enabled)return\r\n this.enabled = false\r\n\r\n dispatcher.unsubscribe(\"MESSAGE_CREATE\", this.antiDM)\r\n }\r\n\r\n antiDM(ev){\r\n if(!ev.message.author.bot)return\r\n if(ev.message.author.id === getCurrentUser().id)\r\n if(ev.message.guild_id)return\r\n\r\n const channel = ChannelModule.getChannel(ev.message.channel_id)\r\n if(!channel)return // might be broken\r\n\r\n if(channel.type !== 1)return\r\n\r\n if(blocked[ev.message.author.id])return // If the user unblock the bot, Don't block it again.\r\n\r\n if(scanMessage(ev.message)){\r\n blocked[ev.message.author.id] = true\r\n Utils.showToast(`[AdBlock]: Blocked ${ev.message.author.username}#${ev.message.author.discriminator}`, {\r\n \"type\": \"warning\"\r\n })\r\n if(!relationShipModule)relationShipModule = BDModules.get(e => e.default && e.default.addRelationship)[0]\r\n relationShipModule.default.addRelationship(ev.message.author.id, {\r\n location: \"ContextMenu\"\r\n }, 2)\r\n if(!DMModule)DMModule = BDModules.get(e => e.default && e.default.closePrivateChannel)[0]\r\n DMModule.default.closePrivateChannel(channel.id, false)\r\n }\r\n }\r\n}\r\n\r\nfunction scanMessage(message){\r\n if(/(discord\\.gg|discord\\.com\\/invite\\/|discordapp\\.com\\/invite\\/)/g.test(message.content))return true\r\n if(EmbedsContains(message, \"discord.gg/\") || EmbedsContains(message, \"discord.com/invite/\") || EmbedsContains(message, \"discordapp.com/invite/\"))return true\r\n\r\n return false\r\n}\r\nfunction EmbedsContains(message, search){\r\n let embeds = message.embeds || []\r\n if(embeds.length === 0)return false\r\n return embeds.map(embed => {\r\n if(embed.type !== \"rich\")return false\r\n if((embed.title || \"\").includes(search))return true\r\n if((embed.description || \"\").includes(search))return true\r\n if(((embed.footer || \"\") && embed.footer.text || \"\").includes(search))return true\r\n if((embed.fields || []).map(e => {\r\n return e.value.includes(search) || e.name.includes(search)\r\n }).includes(true))return true\r\n return false\r\n\r\n }).includes(true)\r\n}","/**\r\n * Credits to @hellbound1337 on github for the css\r\n */\r\n\r\nimport DOMTools from \"./domtools\"\r\nimport Utils from \"./utils\"\r\n\r\nlet selectors\r\nconst removeDa = Utils.removeDa\r\nfunction getSelectors(){\r\n let standardSidebarView = BDModules.get(e => e.standardSidebarView)[0]\r\n if(!standardSidebarView)return null\r\n let defaultClassName = removeDa(standardSidebarView.standardSidebarView)\r\n let selects = []\r\n let userSettingsAccount = BDModules.get(e => e.userSettingsAccount)[0]\r\n const children = BDModules.get(e => typeof e.children === \"string\")[0]\r\n selects.push(`#app-mount .${defaultClassName} .payment-info .${removeDa(BDModules.get(e => e.description && typeof e.description === \"string\" && e.description.includes(\"formText\"))[0].description)}`)\r\n selects.push(`#app-mount .${defaultClassName} .${removeDa(BDModules.get(e => e.paymentSourceRow)[0].paymentSourceRow)} .${removeDa(BDModules.get(e => e.subText && e.descriptionWrapper)[0].subText)}`)\r\n if(userSettingsAccount){\r\n selects.push(`#app-mount .${defaultClassName} .${removeDa(userSettingsAccount.userSettingsAccount)} div:nth-child(2)>div:nth-child(2)>.${removeDa(BDModules.get(e => e.viewBody)[0].viewBody)}`)\r\n selects.push(`.${removeDa(userSettingsAccount.userSettingsSecurity)} .${removeDa(children.children)} > div:nth-child(2)`)\r\n }\r\n console.log(selects)\r\n return selects\r\n}\r\n\r\nexport default new class BlurPrivate {\r\n constructor(){\r\n this.enabled = false\r\n }\r\n\r\n enable(){\r\n if(this.enabled)return\r\n this.enabled = true\r\n selectors = selectors || getSelectors()\r\n\r\n if(!selectors)console.error(new Error(\"Couldn't find selectors to blur personnal informations.\"))\r\n DOMTools.addStyle(\"blurPrivate\", `\r\n${selectors.join(\", \")} {\r\n transition: all 150ms cubic-bezier(.55,.085,.68,.53);\r\n filter: blur(4px);\r\n opacity: .8;\r\n}\r\n\r\n${selectors.map(e => e+\":hover\").join(\", \")} {\r\n transition: all 150ms cubic-bezier(.55,.09,.68,.53);\r\n filter: none;\r\n opacity: 1;\r\n}`)\r\n }\r\n\r\n disable(){\r\n if(!this.enabled)return\r\n this.enabled = false\r\n DOMTools.removeStyle(\"blurPrivate\")\r\n }\r\n}","export default new class DisableTyping {\r\n constructor(){\r\n window.Lightcord.Api.ensureExported(e => e.default && e.default.startTyping)\r\n .then(typingModule => {\r\n let self = this\r\n const startTyping = typingModule.default.startTyping\r\n typingModule.default.startTyping = function(){\r\n if(self.disabled)return startTyping.call(this, ...arguments)\r\n }\r\n const stopTyping = typingModule.default.stopTyping\r\n typingModule.default.stopTyping = function(){\r\n if(self.disabled)return stopTyping.call(this, ...arguments)\r\n }\r\n this.disabled = true\r\n })\r\n window.Lightcord.BetterDiscord.DisableTyping = this\r\n }\r\n\r\n disable(){\r\n this.disabled = true\r\n }\r\n\r\n enable(){\r\n this.disabled = false\r\n }\r\n}","// Good luck to read my code, Even me can't read it properly.\r\n\r\nimport { stat } from \"fs\"\r\nimport { uuidv4 } from \"../modules/distant\"\r\nimport webpackModules from \"../modules/webpackModules\"\r\nimport { remote } from \"electron\"\r\nimport MarginTop from \"./margintop\"\r\n\r\nlet formModule\r\nexport default class ApiPreview extends React.PureComponent {\r\n constructor(){\r\n super(...arguments)\r\n this.state = {\r\n states: []\r\n }\r\n }\r\n\r\n render(){\r\n if(!formModule)formModule = webpackModules.find(e => e.FormSection)\r\n /** \r\n * @type {Function[]}\r\n */\r\n const allComponents = [...new Set(Object.keys(window.Lightcord.Api.Components).map(e => {\r\n return Object.keys(window.Lightcord.Api.Components[e]).map(k => window.Lightcord.Api.Components[e][k])\r\n }).flat())]\r\n return [\r\n \r\n \r\n These components are here for the plugin devs. They can quickly embed any component below with this panel.\r\n \r\n All these components have error handling. If you want none, add `.original` after the component path.\r\n We do not recommend modifying these component with plugins. Only do this if you know what you are doing.\r\n \r\n \r\n {\r\n remote.shell.openExternal(\"https://lightcord.deroku.xyz/LightcordApi/docs\")\r\n }} wrapper={false}>\r\n Documentation\r\n \r\n ,\r\n allComponents.map(comp => {\r\n const compName = comp.displayName || comp.name\r\n const compPath = `Lightcord.Api.Components.${Object.keys(window.Lightcord.Api.Components).find(e => window.Lightcord.Api.Components[e][compName])}.${compName}`\r\n return \r\n })\r\n ]\r\n }\r\n\r\n get renders(){\r\n\r\n }\r\n}\r\n\r\nclass ComponentPreview extends React.Component {\r\n constructor(props){\r\n super(props)\r\n this.state = {\r\n tab: \"preview\",\r\n elem: props.comp,\r\n options: {}\r\n }\r\n }\r\n\r\n render(){\r\n const comp = this.props.comp\r\n let AllPreviews = []\r\n if(comp.AllPreviews)AllPreviews = comp.AllPreviews\r\n let state = this.state\r\n let getProps = () => {\r\n let final = {}\r\n AllPreviews.forEach(category => {\r\n final[Object.keys(category[0])[0]] = category[0][Object.keys(category[0])[0]]\r\n })\r\n Object.keys(state.options).forEach(key => {\r\n final[key] = AllPreviews.find(e => e.find(e => e[key]))[state.options[key]][key]\r\n })\r\n return final\r\n }\r\n let renderPreview = () => {\r\n return \r\n
\r\n {React.createElement(comp, getProps())}\r\n
\r\n
\r\n }\r\n let renderCode = () => {\r\n return \r\n
\r\n \r\n JSX\r\n \r\n \r\n {React.createElement(() => {\r\n return \r\n })}\r\n \r\n \r\n React\r\n \r\n \r\n {React.createElement(() => {\r\n return \r\n })}\r\n \r\n
\r\n
\r\n }\r\n let getStrForProp = (value, compPath, lang) => {\r\n if(typeof value === \"string\"){\r\n return value\r\n }else if(typeof value === \"boolean\"){\r\n return String(value)\r\n }else if(typeof value === \"function\"){\r\n return value.toString()\r\n }else if(typeof value === \"object\"){\r\n if(value && value.$$typeof && (value.$$typeof === Symbol.for(\"react.element\") || value.$$typeof === 0xeac7)){\r\n if(compPath === \"Lightcord.Api.Components.general.Tabs\"){\r\n if(lang === \"react\"){\r\n return `React.createElement(\"div\", {style: {\r\nmarginTop: \"20px\", marginBottom: \"20px\"\r\n}},\r\nReact.createElement(\"div\", {style: {\r\nbackgroundColor: \"var(--background-secondary)\",\r\npadding: \"30px 30px\",\r\nborderRadius: \"8px\"\r\n}, className: \"lc-tab-box-shadow\" },\r\nReact.createElement(Lightcord.Api.Components.general.Title, null, \"Preview tabs\")\r\n)\r\n)`\r\n }else if(lang === \"jsx\"){\r\n return `\r\n
\r\n Preview tabs\r\n
\r\n
`\r\n }\r\n }\r\n return \"Your components here.\"\r\n }\r\n return JSON.stringify(value, null, \" \")\r\n }else if(typeof value === \"number\"){\r\n return String(value)\r\n }\r\n return String(value)\r\n }\r\n let generateCode = function(lang){ // code formatting is hard\r\n const compName = comp.displayName || comp.name\r\n let categories = Object.keys(window.Lightcord.Api.Components)\r\n const compCategory = categories.find(e => window.Lightcord.Api.Components[e][compName])\r\n const compPath = `Lightcord.Api.Components.${compCategory}.${compName}`\r\n const props = getProps()\r\n\r\n if(lang === \"jsx\"){\r\n let propStrings = []\r\n let childrenProp = null\r\n Object.keys(props).forEach(key => {\r\n if(key == \"children\"){\r\n childrenProp = getStrForProp(props[key], compPath, lang)\r\n }else{\r\n let str = key+\"=\"\r\n if(typeof props[key] === \"string\"){\r\n str += JSON.stringify(props[key])\r\n }else{\r\n str += `{${getStrForProp(props[key], compPath, lang)}}`\r\n }\r\n propStrings.push(str)\r\n }\r\n })\r\n let openTag\r\n if(childrenProp){\r\n openTag = `<${compPath} ${propStrings.join(\" \")}>`\r\n let closeTag = `${compPath}>`\r\n return `${openTag}\\n ${childrenProp}\\n${closeTag}`\r\n }else{\r\n openTag = `<${compPath} ${propStrings.join(\" \")}/>`\r\n return openTag\r\n }\r\n }else if(lang === \"react\"){\r\n let children = props.children || null\r\n delete props.children\r\n if(children && children.$$typeof && (children.$$typeof === Symbol.for(\"react.element\") || children.$$typeof === 0xeac7)){\r\n children = getStrForProp(children, compPath, lang)\r\n }\r\n let propStrings = []\r\n Object.keys(props).forEach(key => {\r\n let visibleKey = /[^\\w\\d_]/g.test(key) ? JSON.stringify(key) : key\r\n let str = visibleKey+\": \"\r\n if(typeof props[key] === \"string\"){\r\n str += JSON.stringify(props[key])\r\n }else{\r\n str += getStrForProp(props[key], compPath, lang).split(\"\\n\").map((str, i) => {\r\n if(i === 0)return str\r\n return \" \" + str\r\n }).join(\"\\n\")\r\n }\r\n propStrings.push(str)\r\n })\r\n let propObject = \"{\"\r\n if(propStrings.length){\r\n propStrings.forEach((str, i) => {\r\n let isLast = i === propStrings.length - 1\r\n let isFirst = i === 0\r\n if(!isFirst){\r\n propObject += \",\"\r\n }\r\n propObject += \"\\n \"\r\n propObject += str\r\n if(isLast){\r\n propObject +=\"\\n}\"\r\n }\r\n })\r\n }else{\r\n propObject += \"}\"\r\n }\r\n let childrenData = typeof children === \"string\" && children.startsWith(\"React.createElement\") ? children : JSON.stringify(children)\r\n return `React.createElement(${compPath}, ${propObject}, ${childrenData})`\r\n }\r\n }\r\n let help = comp.help || {}\r\n let info = help.info ? \r\n {help.info}\r\n : null\r\n let warn = help.warn ? \r\n {help.warn}\r\n : null\r\n let danger = help.danger ? \r\n {help.danger}\r\n : null\r\n let error = help.error ? \r\n {help.error}\r\n : null\r\n let success = help.success ? \r\n {help.success}\r\n : null\r\n return (\r\n
\r\n {comp.displayName || comp.name}\r\n \r\n {info}\r\n {success}\r\n {warn}\r\n {error}\r\n {danger}\r\n {AllPreviews.map(category => {\r\n if(category[0].onClick)return null\r\n if(category[0].text)return null\r\n if(category[0].children)return null\r\n if(category.length === 1)return null\r\n \r\n let key = Object.keys(category[0])[0]\r\n return [\r\n
\r\n {key}\r\n ,\r\n
{\r\n return {\r\n value: \"opt-\"+index,\r\n label: JSON.stringify(e[Object.keys(e)[0]])\r\n }\r\n })} value={\"opt-\"+(state.options[key] || \"0\")} onChange={(value) => {\r\n this.setState({\r\n options: Object.assign({}, state.options, {\r\n [key]: (value.value || \"0\").replace(\"opt-\", \"\")\r\n })\r\n })\r\n }} searchable={true}/>,\r\n \r\n ]\r\n })}\r\n {\r\n this.setState({\r\n tab\r\n })\r\n }}/>\r\n )\r\n }\r\n}","{/* */}\r\n\r\nimport BDV2 from \"../../modules/v2\";\r\n\r\nconst React = BDV2.React;\r\n\r\nexport default class History extends React.Component {\r\n render() {\r\n const size = this.props.size || \"18px\";\r\n return ;\r\n }\r\n}","import { themeCookie } from \"../0globals\"\r\nimport bdEvents from \"./bdEvents\"\r\nimport DOM from \"./domtools\"\r\n\r\nexport default new class popoutWindow {\r\n constructor(){\r\n /**\r\n * @type {Map}\r\n */\r\n this.windows = new Map()\r\n this.enabled = false\r\n this.init()\r\n }\r\n\r\n async init(){\r\n let popoutModule = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getWindow)\r\n window.Lightcord.DiscordModules.dispatcher.subscribe(\"POPOUT_WINDOW_OPEN\", (ev) => {\r\n setImmediate(() => {\r\n /**\r\n * @type {Window}\r\n */\r\n const window = popoutModule.default.getWindow(ev.key)\r\n this.windows.set(ev.key, window)\r\n\r\n let classList = window.document.body.classList\r\n classList.add(\"window-popout\")\r\n classList.add(\"lightcord\")\r\n classList.add(\"lightcord\")\r\n\r\n this.update(ev.key)\r\n })\r\n })\r\n window.Lightcord.DiscordModules.dispatcher.subscribe(\"POPOUT_WINDOW_CLOSE\", (ev) => {\r\n setImmediate(() => {\r\n this.windows.delete(ev.key)\r\n })\r\n })\r\n bdEvents.on(\"theme-enabled\", () => {\r\n this.update()\r\n })\r\n bdEvents.on(\"theme-disabled\", () => {\r\n this.update()\r\n })\r\n bdEvents.on(\"theme-reloaded\", () => {\r\n this.update()\r\n })\r\n bdEvents.on(\"theme-unloaded\", () => {\r\n this.update()\r\n })\r\n bdEvents.on(\"theme-loaded\", () => {\r\n this.update()\r\n })\r\n }\r\n\r\n enable(){\r\n this.enabled = true\r\n this.update()\r\n }\r\n\r\n disable(){\r\n this.enabled = false\r\n this.update()\r\n }\r\n\r\n update(key){\r\n if(!this.windows.size)return\r\n if(!this.enabled){\r\n return this.removeThemes(key)\r\n }else{\r\n return this.applyThemes(key)\r\n }\r\n }\r\n\r\n removeThemes(key){\r\n if(this.enabled)return\r\n if(key){\r\n let window = this.windows.get(key)\r\n if(!window)return\r\n let document = window.document\r\n\r\n for(let style of document.querySelectorAll(\"style[data-lightcord-theme=true]\")){\r\n style.remove()\r\n }\r\n }else{\r\n for(let key of this.windows.keys()){\r\n this.removeThemes(key)\r\n }\r\n }\r\n }\r\n\r\n applyThemes(key){\r\n if(!this.enabled)return\r\n if(key){\r\n let window = this.windows.get(key)\r\n if(!window)return\r\n let document = window.document\r\n\r\n for(let style of document.querySelectorAll(\"style[data-lightcord-theme=true]\")){\r\n style.setAttribute(\"will-remove\", \"true\")\r\n }\r\n\r\n Object.keys(bdthemes)\r\n .forEach(themeName => {\r\n if(!themeCookie[themeName])return // theme disabled\r\n const theme = bdthemes[themeName]\r\n if(!theme)return //:shrug:\r\n\r\n let existing = document.querySelector(\"style[data-lightcord-theme=true]#\"+DOM.escapeID(theme.id))\r\n if(existing){\r\n existing.innerHTML = unescape(theme.css)\r\n existing.removeAttribute(\"will-remove\")\r\n }else{\r\n const style = document.createElement(\"style\")\r\n style.id = DOM.escapeID(theme.id)\r\n style.innerHTML = unescape(theme.css)\r\n style.setAttribute(\"data-lightcord-theme\", \"true\")\r\n document.head.append(style)\r\n }\r\n })\r\n\r\n for(let style of document.querySelectorAll(\"style[will-remove=true]\")){\r\n style.remove()\r\n }\r\n }else{\r\n for(let key of this.windows.keys()){\r\n this.applyThemes(key)\r\n }\r\n }\r\n }\r\n}","import {settings, settingsCookie, settingsRPC, lightcordSettings} from \"../0globals\";\r\nimport DataStore from \"./dataStore\";\r\nimport V2_SettingsPanel_Sidebar from \"./settingsPanelSidebar\";\r\nimport Utils from \"./utils\";\r\nimport BDV2 from \"./v2\";\r\nimport ContentManager from \"./contentManager\";\r\nimport coloredText from \"./coloredText\";\r\nimport tfHour from \"./24hour\";\r\nimport DOM from \"./domtools\";\r\n\r\nimport publicServersModule from \"./publicServers\";\r\nimport voiceMode from \"./voiceMode\";\r\nimport ClassNormalizer from \"./classNormalizer\";\r\nimport dMode from \"./devMode\";\r\n\r\nimport SectionedSettingsPanel from \"../ui/sectionedSettingsPanel\";\r\nimport CssEditor from \"../ui/cssEditor\";\r\nimport CardList from \"../ui/addonlist\";\r\nimport V2C_PresenceSettings from \"../ui/presenceSettings\";\r\nimport CustomRichPresence from \"./CustomRichPresence\";\r\nimport V2C_AccountInfos from \"../ui/AccountInfos\";\r\nimport { remote } from \"electron\";\r\nimport AntiAdDM from \"./AntiAdDM\";\r\nimport blurPrivate from \"./blurPrivate\";\r\nimport disableTyping from \"./disableTyping\";\r\nimport ApiPreview from \"../ui/ApiPreview\";\r\nimport Switch from \"../ui/switch\";\r\nimport MarginTop from \"../ui/margintop\";\r\nimport webpackModules from \"./webpackModules\";\r\nimport tooltipWrap from \"../ui/tooltipWrap\";\r\nimport History from \"../ui/icons/history\";\r\nimport core from \"./core\";\r\nimport popoutWindow from \"./popoutWindow\";\r\n\r\nclass BDSidebarHeader extends React.PureComponent {\r\n render(){\r\n let sidebarComponents = webpackModules.find(e => e.Separator && e.Header && e.Item)\r\n\r\n const changelogButton = React.createElement(tooltipWrap, {color: \"black\", side: \"top\", text: \"Changelog\"}, \r\n React.createElement(\"span\", {style: {float: \"right\", cursor: \"pointer\"}, className: \"bd-changelog-button\", onClick: () => {Utils.showChangelogModal(bbdChangelog);}},\r\n React.createElement(History, {className: \"bd-icon\", size: \"16px\"})\r\n )\r\n );\r\n let rendered = new sidebarComponents.Header({\r\n children: React.createElement(\"span\", null, \"Bandaged BD\", changelogButton),\r\n className: \"ui-tab-bar-header\"\r\n })\r\n return rendered\r\n }\r\n}\r\n\r\nlet isClearingCache = false\r\n\r\nexport default new class V2_SettingsPanel {\r\n\r\n constructor() {\r\n this.onChange = this.onChange.bind(this);\r\n this.updateSettings = this.updateSettings.bind(this);\r\n this.sidebar = new V2_SettingsPanel_Sidebar();\r\n\r\n this.registerComponents()\r\n }\r\n\r\n registerComponents(){\r\n /** Lightcord */\r\n this.sidebar.register(\"lightcord\", makeComponent(this.lightcordComponent.bind(this)))\r\n this.sidebar.register(\"status\", makeComponent(this.PresenceComponent.bind(this)))\r\n this.sidebar.register(\"accountinfo\", makeComponent(this.AccountInfosComponent.bind(this)))\r\n this.sidebar.register(\"lcapipreview\", makeComponent(this.ApiPreviewComponent.bind(this)))\r\n\r\n /* Bandaged BD */\r\n this.sidebar.register(\"BDChangelogTitle\", makeComponent(() => {\r\n return new BDSidebarHeader().render()\r\n }))\r\n this.sidebar.register(\"core\", makeComponent(this.coreComponent.bind(this)))\r\n this.sidebar.register(\"customcss\", makeComponent(this.customCssComponent.bind(this)))\r\n this.sidebar.register(\"plugins\", makeComponent(this.renderAddonPane(\"plugins\")))\r\n this.sidebar.register(\"themes\", makeComponent(this.renderAddonPane(\"themes\")))\r\n }\r\n \r\n get coreSettings() {\r\n const settings = this.getSettings(\"core\");\r\n const categories = [...new Set(settings.map(s => s.category))];\r\n const sections = categories.map(c => {return {title: c, settings: settings.filter(s => s.category == c)};});\r\n return sections;\r\n }\r\n\r\n get lightcordSettings() {\r\n const settings = this.getSettings(\"lightcord\");\r\n const categories = [...new Set(settings.map(s => s.category))];\r\n const sections = categories.map(c => {return {title: c, settings: settings.filter(s => s.category == c)};});\r\n return sections;\r\n }\r\n\r\n get PresenceSettings() {\r\n return this.getSettings(\"status\")\r\n }\r\n\r\n getSettings(category) {\r\n return Object.keys(settings).reduce((arr, key) => {\r\n const setting = settings[key];\r\n if (setting.cat === category && setting.implemented && !setting.hidden) {\r\n setting.text = key;\r\n arr.push(setting);\r\n }\r\n return arr;\r\n }, []);\r\n }\r\n\r\n\r\n onChange(id, checked, sidebar) {\r\n this.updateSettings(id, checked, sidebar);\r\n }\r\n\r\n updateSettings(id, enabled, sidebar) {\r\n if(![\"lightcord-8\", \"no_window_bound\", \"enable_glasstron\", \"lightcord-10\"].includes(id))settingsCookie[id] = enabled;\r\n\r\n if (id == \"bda-gs-2\") {\r\n if (enabled) DOM.addClass(document.body, \"bd-minimal\");\r\n else DOM.removeClass(document.body, \"bd-minimal\");\r\n }\r\n\r\n if (id == \"bda-gs-3\") {\r\n if (enabled) DOM.addClass(document.body, \"bd-minimal-chan\");\r\n else DOM.removeClass(document.body, \"bd-minimal-chan\");\r\n }\r\n\r\n if (id == \"bda-gs-1\") {\r\n if (enabled) publicServersModule.addButton();\r\n else publicServersModule.removeButton();\r\n }\r\n\r\n if (id == \"bda-gs-4\") {\r\n if (enabled) voiceMode.start();\r\n else voiceMode.stop();\r\n }\r\n\r\n if (id == \"bda-gs-5\") {\r\n if (enabled) DOM.addClass(DOM.query(\"#app-mount\"), \"bda-dark\");\r\n else DOM.removeClass(DOM.query(\"#app-mount\"), \"bda-dark\");\r\n }\r\n\r\n if (enabled && id == \"bda-gs-6\") tfHour.inject24Hour();\r\n\r\n if (id == \"bda-gs-7\") {\r\n if (enabled) coloredText.injectColoredText();\r\n else coloredText.removeColoredText();\r\n }\r\n\r\n if (id == \"fork-ps-4\") {\r\n if (enabled) ClassNormalizer.start();\r\n else ClassNormalizer.stop();\r\n }\r\n\r\n if (id == \"fork-ps-5\") {\r\n if (enabled) {\r\n ContentManager.watchContent(\"plugin\");\r\n ContentManager.watchContent(\"theme\");\r\n }\r\n else {\r\n ContentManager.unwatchContent(\"plugin\");\r\n ContentManager.unwatchContent(\"theme\");\r\n }\r\n }\r\n\r\n if (id == \"fork-wp-1\") {\r\n Utils.setWindowPreference(\"transparent\", enabled);\r\n if (enabled) Utils.setWindowPreference(\"backgroundColor\", null);\r\n else Utils.setWindowPreference(\"backgroundColor\", \"#2f3136\");\r\n }\r\n\r\n\r\n if (id == \"bda-gs-8\") {\r\n if (enabled) dMode.startDebugListener();\r\n else dMode.stopDebugListener();\r\n }\r\n\r\n if (id == \"fork-dm-1\") {\r\n if (enabled) dMode.startCopySelector();\r\n else dMode.stopCopySelector();\r\n }\r\n\r\n if (id === \"lightcord-1\") {\r\n if (enabled) window.Lightcord.Settings.devMode = true\r\n else window.Lightcord.Settings.devMode = false\r\n sidebar.forceUpdate()\r\n }\r\n if (id === \"lightcord-2\") {\r\n if (enabled) window.Lightcord.Settings.callRingingBeat = true\r\n else window.Lightcord.Settings.callRingingBeat = false\r\n }\r\n if (id === \"lightcord-presence-1\") {\r\n if (enabled) {\r\n CustomRichPresence.enable()\r\n const settingsStore = BDModules.get(e => e.default && typeof e.default === \"object\" && \"showCurrentGame\" in e.default)[0]\r\n if(settingsStore && !settingsStore.default.showCurrentGame){\r\n BDModules.get(e => e.default && e.default.updateRemoteSettings)[0].default.updateRemoteSettings({\r\n showCurrentGame: true\r\n })\r\n }\r\n }\r\n else CustomRichPresence.disable()\r\n }\r\n if (id === \"lightcord-3\") {\r\n if (enabled) remote.getCurrentWindow().setAlwaysOnTop(true)\r\n else remote.getCurrentWindow().setAlwaysOnTop(false)\r\n }\r\n if (id === \"lightcord-4\") {\r\n if(enabled){\r\n AntiAdDM.enable()\r\n }else{\r\n AntiAdDM.disable()\r\n }\r\n }\r\n if (id === \"lightcord-6\") {\r\n if(enabled){\r\n blurPrivate.enable()\r\n }else{\r\n blurPrivate.disable()\r\n }\r\n }\r\n if (id === \"lightcord-7\") {\r\n if(enabled){\r\n disableTyping.enable()\r\n }else{\r\n disableTyping.disable()\r\n }\r\n }\r\n if (id === \"lightcord-8\"){\r\n let appSettings = remote.getGlobal(\"appSettings\")\r\n appSettings.set(\"isTabs\", enabled)\r\n appSettings.save()\r\n remote.app.relaunch()\r\n remote.app.exit()\r\n }\r\n if (id === \"lightcord-9\") {\r\n popoutWindow[enabled ? \"enable\" : \"disable\"]()\r\n }\r\n if (id === \"lightcord-10\"){\r\n core.methods.NotificationsUseShim(enabled)\r\n return\r\n }\r\n if (id === \"no_window_bound\"){\r\n let appSettings = remote.getGlobal(\"appSettings\")\r\n appSettings.set(\"NO_WINDOWS_BOUND\", enabled)\r\n\r\n appSettings.delete(\"IS_MAXIMIZED\")\r\n appSettings.delete(\"IS_MINIMIZED\") \r\n appSettings.delete(\"WINDOW_BOUNDS\")\r\n \r\n appSettings.save()\r\n remote.app.relaunch()\r\n remote.app.exit()\r\n }\r\n if (id === \"enable_glasstron\"){\r\n let appSettings = remote.getGlobal(\"appSettings\")\r\n appSettings.set(\"GLASSTRON\", enabled)\r\n appSettings.save()\r\n remote.app.relaunch()\r\n remote.app.exit()\r\n }\r\n\r\n this.saveSettings();\r\n }\r\n\r\n async initializeSettings() {\r\n if (settingsCookie[\"bda-gs-2\"]) DOM.addClass(document.body, \"bd-minimal\");\r\n if (settingsCookie[\"bda-gs-3\"]) DOM.addClass(document.body, \"bd-minimal-chan\");\r\n if (settingsCookie[\"bda-gs-1\"]) publicServersModule.addButton();\r\n if (settingsCookie[\"bda-gs-4\"]) voiceMode.start();\r\n if (settingsCookie[\"bda-gs-5\"]) DOM.addClass(DOM.query(\"#app-mount\"), \"bda-dark\");\r\n if (settingsCookie[\"bda-gs-6\"]) tfHour.inject24Hour();\r\n if (settingsCookie[\"bda-gs-7\"]) coloredText.injectColoredText();\r\n if (settingsCookie[\"fork-ps-4\"]) ClassNormalizer.start();\r\n if (settingsCookie[\"lightcord-1\"]) window.Lightcord.Settings.devMode = true\r\n if (settingsCookie[\"lightcord-2\"]) window.Lightcord.Settings.callRingingBeat = true\r\n if (settingsCookie[\"lightcord-presence-1\"]) CustomRichPresence.enable()\r\n if (settingsCookie[\"lightcord-3\"]) remote.getCurrentWindow().setAlwaysOnTop(true)\r\n if (settingsCookie[\"lightcord-4\"]) AntiAdDM.enable()\r\n if (settingsCookie[\"lightcord-6\"]) blurPrivate.enable()\r\n if (settingsCookie[\"lightcord-7\"]) disableTyping.enable()\r\n if (settingsCookie[\"lightcord-9\"]) popoutWindow.enable()\r\n\r\n if (settingsCookie[\"fork-ps-5\"]) {\r\n ContentManager.watchContent(\"plugin\");\r\n ContentManager.watchContent(\"theme\");\r\n }\r\n\r\n if (settingsCookie[\"bda-gs-8\"]) dMode.startDebugListener();\r\n if (settingsCookie[\"fork-dm-1\"]) dMode.startCopySelector();\r\n\r\n this.saveSettings();\r\n }\r\n\r\n saveSettings() {\r\n DataStore.setSettingGroup(\"settings\", settingsCookie);\r\n DataStore.setSettingGroup(\"rpc\", settingsRPC);\r\n DataStore.setSettingGroup(\"lightcord-settings\", lightcordSettings);\r\n }\r\n\r\n loadSettings() {\r\n Object.assign(settingsCookie, DataStore.getSettingGroup(\"settings\"));\r\n Object.assign(settingsRPC, DataStore.getSettingGroup(\"rpc\"));\r\n console.log(lightcordSettings, DataStore.getSettingGroup(\"lightcord-settings\"))\r\n Object.assign(lightcordSettings, DataStore.getSettingGroup(\"lightcord-settings\"));\r\n }\r\n\r\n renderSidebar(sidebar) {\r\n return this.sidebar.render(sidebar);\r\n }\r\n\r\n coreComponent() {\r\n return BDV2.react.createElement(SectionedSettingsPanel, {key: \"cspanel\", onChange: this.onChange, sections: this.coreSettings})\r\n }\r\n\r\n lightcordComponent(sidebar, forceUpdate) {\r\n let appSettings = remote.getGlobal(\"appSettings\")\r\n return [\r\n this.lightcordSettings.map((section, i) => {\r\n return [\r\n (i === 0 ? null : BDV2.react.createElement(MarginTop)),\r\n BDV2.react.createElement(\"h2\", {className: \"ui-form-title h2 margin-reset margin-bottom-20\"}, section.title),\r\n section.settings.map(setting => {\r\n let isChecked = settingsCookie[setting.id]\r\n if(setting.id === \"lightcord-8\")isChecked = appSettings.get(\"isTabs\", false);\r\n if(setting.id === \"no_window_bound\")isChecked = appSettings.get(\"NO_WINDOWS_BOUND\", false)\r\n if(setting.id === \"enable_glasstron\")isChecked = appSettings.get(\"GLASSTRON\", true)\r\n if(setting.id === \"lightcord-10\")isChecked = !appSettings.get(\"DEFAULT_NOTIFICATIONS\", true)\r\n let returnValue = BDV2.react.createElement(Switch, {id: setting.id, key: setting.id, data: setting, checked: isChecked, onChange: (id, checked) => {\r\n this.onChange(id, checked, sidebar);\r\n }})\r\n if(setting.id == \"lightcord-8\" && isChecked){\r\n return [\r\n returnValue,\r\n React.createElement(Lightcord.Api.Components.inputs.Button, {\r\n color: \"green\",\r\n look: \"outlined\",\r\n size: \"small\",\r\n hoverColor: \"brand\",\r\n onClick: () => {\r\n DiscordNative.ipc.send(\"NEW_TAB\")\r\n },\r\n wrapper: false,\r\n disabled: false\r\n }, \"Open a new Tab\")\r\n ]\r\n }\r\n return returnValue\r\n })\r\n ]\r\n }), \r\n BDV2.react.createElement(window.Lightcord.Api.Components.inputs.Button, {\r\n color: \"yellow\",\r\n look: \"ghost\",\r\n size: \"medium\",\r\n hoverColor: \"red\",\r\n onClick(){\r\n console.log(\"Should relaunch\")\r\n remote.app.relaunch({\r\n args: remote.process.argv.slice(1).concat([\"--disable-betterdiscord\"])\r\n })\r\n remote.app.quit()\r\n },\r\n wrapper: true\r\n }, \"Relaunch without BetterDiscord\"),\r\n React.createElement(Lightcord.Api.Components.inputs.Button, {\r\n color: \"yellow\",\r\n look: \"ghost\",\r\n size: \"medium\",\r\n hoverColor: \"red\",\r\n onClick: () => {\r\n if(isClearingCache)return\r\n isClearingCache = true\r\n Utils.showToast(\"Clearing cache...\", {\r\n type: \"info\"\r\n })\r\n forceUpdate()\r\n remote.getCurrentWebContents().session.clearCache()\r\n .then(() => {\r\n Utils.showToast(\"Cache is cleared !\", {\r\n type: \"success\"\r\n })\r\n isClearingCache = false\r\n forceUpdate()\r\n }).catch(err => {\r\n console.error(err)\r\n Utils.showToast(\"An error occured. Check console for more informations.\", {\r\n type: \"error\"\r\n })\r\n isClearingCache = false\r\n forceUpdate()\r\n })\r\n },\r\n wrapper: true,\r\n disabled: isClearingCache\r\n }, \"Clear cache\")\r\n ]\r\n }\r\n\r\n PresenceComponent() {\r\n return BDV2.react.createElement(V2C_PresenceSettings, {\r\n key: \"lppannel\",\r\n onChange: this.onChange, \r\n settings: this.PresenceSettings\r\n })\r\n }\r\n\r\n AccountInfosComponent() {\r\n return BDV2.react.createElement(V2C_AccountInfos, {\r\n key: \"lapannel\"\r\n })\r\n }\r\n\r\n ApiPreviewComponent() {\r\n return BDV2.react.createElement(ApiPreview, {\r\n key: \"lapipannel\"\r\n })\r\n }\r\n\r\n customCssComponent() {\r\n return BDV2.react.createElement(CssEditor, {key: \"csseditor\"})\r\n }\r\n\r\n renderAddonPane(type) {\r\n // I know this shouldn't be here, but when it isn't,\r\n // React refuses to change the button when going\r\n // between plugins and themes page... something\r\n // to debug later.\r\n class ContentList extends BDV2.react.Component {\r\n constructor(props) {\r\n super(props);\r\n this.prefix = this.props.type.replace(\"s\", \"\");\r\n }\r\n \r\n onChange() {\r\n this.props.onChange(this.props.type);\r\n }\r\n \r\n render() {return this.props.children;}\r\n }\r\n const originalRender = ContentList.prototype.render;\r\n Object.defineProperty(ContentList.prototype, \"render\", {\r\n enumerable: false,\r\n configurable: false,\r\n set: function() {console.warn(\"Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins\");},\r\n get: () => originalRender\r\n });\r\n return function(){\r\n return BDV2.react.createElement(ContentList, {type}, BDV2.react.createElement(CardList, {type}))\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * No need to export settingsPanel on window\r\n */\r\n\r\nfunction makeComponent(children){\r\n class SettingComponent extends React.Component {\r\n render(){\r\n return children(sidebar, () => this.forceUpdate())\r\n }\r\n }\r\n let sidebar\r\n return (s) => {\r\n sidebar = s\r\n return SettingComponent\r\n }\r\n}","import BDV2 from \"../modules/v2\";\r\n\r\nexport default class BDLogo extends BDV2.reactComponent {\r\n render() {\r\n return BDV2.react.createElement(\r\n \"svg\",\r\n {height: \"100%\", width: this.props.size || \"16px\", className: \"bd-logo \" + this.props.className, style: {fillRule: \"evenodd\", clipRule: \"evenodd\", strokeLinecap: \"round\", strokeLinejoin: \"round\"}, viewBox: \"0 0 2000 2000\"},\r\n BDV2.react.createElement(\"metadata\", null),\r\n BDV2.react.createElement(\"defs\", null,\r\n BDV2.react.createElement(\"filter\", {id: \"shadow1\"}, BDV2.react.createElement(\"feDropShadow\", {\"dx\": \"20\", \"dy\": \"0\", \"stdDeviation\": \"20\", \"flood-color\": \"rgba(0,0,0,0.35)\"})),\r\n BDV2.react.createElement(\"filter\", {id: \"shadow2\"}, BDV2.react.createElement(\"feDropShadow\", {\"dx\": \"15\", \"dy\": \"0\", \"stdDeviation\": \"20\", \"flood-color\": \"rgba(255,255,255,0.15)\"})),\r\n BDV2.react.createElement(\"filter\", {id: \"shadow3\"}, BDV2.react.createElement(\"feDropShadow\", {\"dx\": \"10\", \"dy\": \"0\", \"stdDeviation\": \"20\", \"flood-color\": \"rgba(0,0,0,0.35)\"}))\r\n ),\r\n BDV2.react.createElement(\"g\", null,\r\n BDV2.react.createElement(\"path\", {style: {filter: \"url(#shadow3)\"}, d: \"M1195.44+135.442L1195.44+135.442L997.6+136.442C1024.2+149.742+1170.34+163.542+1193.64+179.742C1264.34+228.842+1319.74+291.242+1358.24+365.042C1398.14+441.642+1419.74+530.642+1422.54+629.642L1422.54+630.842L1422.54+632.042C1422.54+773.142+1422.54+1228.14+1422.54+1369.14L1422.54+1370.34L1422.54+1371.54C1419.84+1470.54+1398.24+1559.54+1358.24+1636.14C1319.74+1709.94+1264.44+1772.34+1193.64+1821.44C1171.04+1837.14+1025.7+1850.54+1000+1863.54L1193.54+1864.54C1539.74+1866.44+1864.54+1693.34+1864.54+1296.64L1864.54+716.942C1866.44+312.442+1541.64+135.442+1195.44+135.442Z\", fill: \"#171717\", opacity: \"1\"}),\r\n BDV2.react.createElement(\"path\", {style: {filter: \"url(#shadow2)\"}, d: \"M1695.54+631.442C1685.84+278.042+1409.34+135.442+1052.94+135.442L361.74+136.442L803.74+490.442L1060.74+490.442C1335.24+490.442+1335.24+835.342+1060.74+835.342L1060.74+1164.84C1150.22+1164.84+1210.53+1201.48+1241.68+1250.87C1306.07+1353+1245.76+1509.64+1060.74+1509.64L361.74+1863.54L1052.94+1864.54C1409.24+1864.54+1685.74+1721.94+1695.54+1368.54C1695.54+1205.94+1651.04+1084.44+1572.64+999.942C1651.04+915.542+1695.54+794.042+1695.54+631.442Z\", fill: \"#3E82E5\", opacity: \"1\"}),\r\n BDV2.react.createElement(\"path\", {style: {filter: \"url(#shadow1)\"}, d: \"M1469.25+631.442C1459.55+278.042+1183.05+135.442+826.65+135.442L135.45+135.442L135.45+1004C135.45+1004+135.427+1255.21+355.626+1255.21C575.825+1255.21+575.848+1004+575.848+1004L577.45+490.442L834.45+490.442C1108.95+490.442+1108.95+835.342+834.45+835.342L664.65+835.342L664.65+1164.84L834.45+1164.84C923.932+1164.84+984.244+1201.48+1015.39+1250.87C1079.78+1353+1019.47+1509.64+834.45+1509.64L135.45+1509.64L135.45+1864.54L826.65+1864.54C1182.95+1864.54+1459.45+1721.94+1469.25+1368.54C1469.25+1205.94+1424.75+1084.44+1346.35+999.942C1424.75+915.542+1469.25+794.042+1469.25+631.442Z\", fill: \"#FFFFFF\", opacity: \"1\"})\r\n )\r\n );\r\n }\r\n}","export default class LightcordLogo extends React.Component {\r\n render(){\r\n const props = this.props\r\n return (\r\n \r\n )\r\n }\r\n}","import BDV2 from \"./v2\";\r\nimport Utils from \"./utils\";\r\n\r\nconst Constants = {\r\n EmojiRegex: //g\r\n}\r\n\r\nlet CustomEmojiModule = BDModules.get(e => e.CustomEmoji)[0]\r\nlet EmojiModuleApi = BDModules.get(e => e.default && e.default.getCustomEmojiById)[0]\r\nlet AutocompleteModule = BDModules.get(e => e.default && e.default.displayName === \"Autocomplete\")[0]\r\nlet AutoCompletionTemplates = BDModules.get(e => e.getAutocompleteOptions)[0]\r\nlet EmojiModuleQuery = BDModules.get(e => e.default && e.default.queryEmojiResults)[0]\r\nlet Messages = BDModules.get(e => e.default && e.default.Messages && e.default.Messages.EMOJI_MATCHING)[0]\r\nlet guildModule = BDModules.get(e => e.default && e.default.getGuild && e.default.getGuilds && !e.default.isFetching)[0]\r\nlet emojiSearch = BDModules.get(e => e.default && e.default.getDisambiguatedEmojiContext)\r\n\r\nexport default new class EmojiModule {\r\n constructor(){\r\n this.init().catch(err => Utils.err(\"EmojiModule\", \"An error occured\", err)) // better logging\r\n }\r\n\r\n async init(){\r\n /** Emoji AutoComplete */\r\n if(!AutocompleteModule)AutocompleteModule = await window.Lightcord.Api.ensureExported(e => e.default && e.default.displayName === \"Autocomplete\")\r\n if(!AutoCompletionTemplates)AutoCompletionTemplates = await window.Lightcord.Api.ensureExported(e => e.getAutocompleteOptions)\r\n if(!EmojiModuleQuery)EmojiModuleQuery = await window.Lightcord.Api.ensureExported(e => e.default && e.default.queryEmojiResults)\r\n if(!Messages)Messages = await window.Lightcord.Api.ensureExported(e => e.default && e.default.Messages && e.default.Messages.EMOJI_MATCHING)\r\n if(!guildModule)guildModule = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getGuild && e.default.getGuilds && !e.default.isFetching)\r\n if(!emojiSearch)emojiSearch = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getDisambiguatedEmojiContext)\r\n\r\n if(AutocompleteModule && AutoCompletionTemplates && EmojiModuleQuery && Messages && guildModule && emojiSearch){\r\n console.log(`Patching getAutocompleteOptions of AutoCompletionTemplates`, AutoCompletionTemplates)\r\n const getAutocompleteOptions = AutoCompletionTemplates.getAutocompleteOptions\r\n AutoCompletionTemplates.getAutocompleteOptions = function(e, t, n, r, a){\r\n const value = getAutocompleteOptions.call(this, ...arguments)\r\n value.LIGHTCORD_EMOJIS = {\r\n matches(arg1, arg2){\r\n let condition = arg2.length > 1 && \".\" === arg1\r\n setEmojiUsable(condition)\r\n return condition\r\n },\r\n queryResults(t){\r\n let results = EmojiModuleQuery.default.queryEmojiResults(t, e)\r\n return results\r\n },\r\n renderResults(e, t, n, r, a){\r\n return D(e, t, a.emojis, n, r, Messages.default.Messages.EMOJI_MATCHING, Messages.default.Messages.EMOJI, AutocompleteModule.default.Emoji, (function(e) {\r\n return {\r\n emoji: e,\r\n key: e.id || e.uniqueName || e.name,\r\n sentinel: \".\",\r\n guild: null != e.guildId ? guildModule.default.getGuild(e.guildId) : null\r\n }\r\n }), (function(e) {\r\n return \".\" + e + \".\"\r\n }))\r\n },\r\n getPlainText(id, guild){\r\n var emojis = guild.emojis;\r\n if (null == emojis || null == emojis[id]) return \"\";\r\n var emoji = emojis[id],\r\n isAnimated = emoji.animated ? \"a\" : \"\";\r\n return emoji.managed || null == emoji.id ? \".\" + emoji.name + \".\" : \"<\" + isAnimated + \".\" + (emoji.originalName || emoji.name) + \".\" + emoji.id + \">\"\r\n },\r\n getRawText(id, guild){\r\n var emojis = guild.emojis;\r\n if (null == emojis || null == emojis[id]) return \"\";\r\n var emoji = emojis[id],\r\n isAnimated = emoji.animated ? \"a\" : \"\";\r\n return emoji.managed || null == emoji.id ? \".\" + emoji.name + \".\" : \"<\" + isAnimated + \".\" + (emoji.originalName || emoji.name) + \".\" + emoji.id + \">\"\r\n }\r\n }\r\n return value\r\n }\r\n }else{\r\n console.error(new Error(\"Couldn't start autocompletion of Lightcord's emojis.\"))\r\n }\r\n\r\n /** Emoji display */\r\n while (!BDV2.MessageComponent) await new Promise(resolve => setTimeout(resolve, 100));\r\n\r\n if (!this.cancelEmojiRender){ // TODO: Proper emoji formatting / rendering\r\n this.cancelEmoteRender = Utils.monkeyPatch(BDV2.MessageComponent, \"default\", {before: (data) => {\r\n const message = Utils.getNestedProp(data.methodArguments[0], \"childrenMessageContent.props.message\")\r\n if(!message)return\r\n const content = Utils.getNestedProp(data.methodArguments[0], \"childrenMessageContent.props.content\")\r\n if(!content || !content.length)return\r\n \r\n /**\r\n * @type {{\r\n * raw: string,\r\n * name: string,\r\n * id: string,\r\n * animated: boolean\r\n * }[]}\r\n */\r\n let emojis = []\r\n \r\n const newContent = []\r\n for(let node of content){\r\n if (typeof(node) !== \"string\") {\r\n newContent.push(node)\r\n continue\r\n };\r\n let parsed;\r\n let hasParsed = false\r\n \r\n do {\r\n parsed = Constants.EmojiRegex.exec(node);\r\n if (parsed) {\r\n hasParsed = true\r\n if(!EmojiModuleApi)EmojiModuleApi = BDModules.get(e => e.default && e.default.getCustomEmojiById)[0]\r\n const emoji = EmojiModuleApi.default.getCustomEmojiById(parsed[2])\r\n if(emoji){\r\n emojis.push({\r\n animated: emoji.animated,\r\n name: emoji.name,\r\n id: emoji.id,\r\n raw: parsed[0]\r\n })\r\n }else{\r\n emojis.push({\r\n animated: parsed[0].startsWith(\" {\r\n if(!word)return \"\"\r\n const emoji = emojis.find(e => e.raw == word)\r\n if(!emoji)return word\r\n if(!CustomEmojiModule)CustomEmojiModule = BDModules.get(e => e.CustomEmoji)[0]\r\n return React.createElement(CustomEmojiModule.CustomEmoji, {\r\n emoji: {\r\n name: `.${emoji.name}.`,\r\n emojiId: emoji.id,\r\n animated: emoji.animated,\r\n jumboable: arr.length === 1 && content.length === 1\r\n }\r\n })\r\n }).reduce((previous, current) => {\r\n if(previous.length === 0)return [current]\r\n if(typeof current === \"string\"){\r\n if(typeof previous[previous.length - 1] === \"string\"){\r\n previous[previous.length - 1] += ` ${current}`\r\n return previous\r\n }\r\n previous.push(\" \"+current)\r\n return previous\r\n }\r\n previous.push(\" \", current)\r\n return previous\r\n }, [])\r\n newContent.push(...words)\r\n }else{\r\n newContent.push(node)\r\n }\r\n }\r\n while(data.methodArguments[0].childrenMessageContent.props.content[0]){\r\n data.methodArguments[0].childrenMessageContent.props.content.shift()\r\n }\r\n while(newContent[0]){\r\n data.methodArguments[0].childrenMessageContent.props.content.push(newContent.shift())\r\n }\r\n }});\r\n }/*\r\n let userModule\r\n window.Lightcord.Api.ensureExported(e => e.default && e.default.displayName === \"EmojiPickerListRow\")\r\n .then(EmojiPickerListRow => {\r\n let classs = EmojiPickerListRow.default\r\n EmojiPickerListRow.default = class EmojiPickerListRow extends React.Component {\r\n constructor(props){\r\n super(props)\r\n }\r\n\r\n render(){\r\n if(!userModule)userModule = BDModules.get(e => e.default && e.default.getCurrentUser)[0]\r\n if(!userModule)return React.createElement(classs, this.props)\r\n let user = userModule.default.getCurrentUser()\r\n if(!user.hasPremiumSubscription)return React.createElement(classs, this.props)\r\n\r\n return React.createElement(classs, Object.assign({}, this.props, {\r\n emojiDescriptors: this.props.emojiDescriptors.map(e => {\r\n e.isDisabled = false\r\n })\r\n })) \r\n }\r\n }\r\n EmojiPickerListRow.default.displayName = \"EmojiPickerListRow\"\r\n })*/\r\n }\r\n\r\n disable(){\r\n if (!this.cancelEmoteRender) return;\r\n this.cancelEmoteRender();\r\n this.cancelEmoteRender = null;\r\n }\r\n\r\n start(){\r\n \r\n }\r\n}\r\n\r\nfunction D(e, t, n, r, o, i, s, u, l, c) {\r\n if (null == n || 0 === n.length) return null;\r\n var d = n.map((function(e, n) {\r\n return React.createElement(u, Object.assign({\r\n onClick: o,\r\n onHover: r,\r\n selected: t === n,\r\n index: n\r\n }, l(e, n)))\r\n }));\r\n return [R(i, s, e, c), d]\r\n}\r\n\r\nfunction R(e, t, n, r) {\r\n var a = (n.length > 0 ? e.format({\r\n prefix: r(n)\r\n }) : t)\r\n if(Array.isArray(a)){\r\n a.unshift(React.createElement(\"strong\", {}, \"[Lightcord] \"))\r\n }else{\r\n a = \"[LIGHTCORD] \"+a\r\n }\r\n return React.createElement(AutocompleteModule.default.Title, {\r\n title: a\r\n }, a)\r\n}\r\nR.displayName = \"renderHeader\";\r\n\r\nlet EmojiFilterModule = BDModules.get(e => e.default && e.default.isEmojiDisabled)[0]\r\nlet isEmojiDisabled = EmojiFilterModule && EmojiFilterModule.default.isEmojiDisabled\r\nlet isUsable = false\r\nlet hasPatched = false\r\n\r\nfunction setEmojiUsable(usable){\r\n isUsable = usable\r\n if(hasPatched)return\r\n if(!EmojiFilterModule)EmojiFilterModule = BDModules.get(e => e.default && e.default.isEmojiDisabled)[0]\r\n if(!EmojiFilterModule)return\r\n if(!isEmojiDisabled)isEmojiDisabled = EmojiFilterModule.default.isEmojiDisabled\r\n\r\n hasPatched = true\r\n EmojiFilterModule.default.isEmojiDisabled = function(emoji){\r\n if(isUsable){\r\n if(emoji.surrogates || emoji.diversity)return true\r\n return false\r\n }\r\n return isEmojiDisabled.call(this, ...arguments)\r\n }\r\n}","import {bdConfig, minSupportedVersion, bbdVersion, settingsCookie, bdpluginErrors, bdthemeErrors, bbdChangelog, defaultCookie, currentDiscordVersion, defaultRPC, settingsRPC, lightcordSettings} from \"../0globals\";\r\nimport Utils from \"./utils\";\r\n\r\nimport BDV2 from \"./v2\";\r\nimport settingsPanel from \"./settingsPanel\";\r\nimport pluginModule from \"./pluginModule\";\r\nimport themeModule from \"./themeModule\";\r\nimport DataStore from \"./dataStore\";\r\nimport WebpackModules from \"./webpackModules\";\r\nimport DOM from \"./domtools\";\r\n\r\nimport BDLogo from \"../ui/bdLogo\";\r\nimport TooltipWrap from \"../ui/tooltipWrap\";\r\nimport LightcordLogo from \"../svg/lightcord\";\r\nimport PluginCertifier from \"./pluginCertifier\";\r\nimport distant, { uuidv4 } from \"./distant\";\r\nimport EmojiModule from \"./emojiModule\"\r\nimport {remote as electron} from \"electron\"\r\nimport v2 from \"./v2\";\r\nimport contentManager from \"./contentManager\";\r\n\r\nlet methods\r\nfunction Core() {}\r\n\r\n\r\nCore.prototype.setConfig = function(config) {\r\n if (this.hasStarted) return;\r\n Object.assign(bdConfig, config);\r\n};\r\n\r\nObject.defineProperty(Core.prototype, \"methods\", {\r\n get(){\r\n return methods\r\n }\r\n})\r\n\r\nCore.prototype.setMethods = function(m) {\r\n if (this.hasStarted) return;\r\n methods = m\r\n};\r\n\r\nCore.prototype.init = async function() {\r\n if (this.hasStarted) return;\r\n this.hasStarted = true;\r\n\r\n if (!Array.prototype.flat) {\r\n Utils.alert(\"Not Supported\", \"BetterDiscord v\" + bbdVersion + \" does not support this old version (\" + currentDiscordVersion + \") of Discord. Please update your Discord installation before proceeding.\");\r\n return;\r\n }\r\n\r\n if (bdConfig.version < minSupportedVersion) {\r\n Utils.alert(\"Not Supported\", \"BetterDiscord v\" + bdConfig.version + \" (your version)\" + \" is not supported by the latest js (\" + bbdVersion + \").
Please download the latest version from GitHub\");\r\n return;\r\n }\r\n\r\n if (window.ED) {\r\n Utils.alert(\"Not Supported\", \"BandagedBD does not work with EnhancedDiscord. Please uninstall one of them.\");\r\n return;\r\n }\r\n\r\n if (window.WebSocket && window.WebSocket.name && window.WebSocket.name.includes(\"Patched\")) {\r\n Utils.alert(\"Not Supported\", \"BandagedBD does not work with Powercord. Please uninstall one of them.\");\r\n return;\r\n }\r\n\r\n Utils.suppressErrors(this.patchAttributes.bind(this), \"LC Plugin Certifier Patch\")();\r\n\r\n Utils.log(\"Startup\", \"Initializing Settings\");\r\n this.initSettings();\r\n\r\n await this.checkForGuilds();\r\n BDV2.initialize();\r\n Utils.log(\"Startup\", \"Updating Settings\");\r\n settingsPanel.initializeSettings();\r\n\r\n Utils.log(\"Startup\", \"Loading Addons Cache\")\r\n await contentManager.loadAddonCertifierCache()\r\n\r\n Utils.log(\"Startup\", \"Loading Plugins\");\r\n await pluginModule.loadPlugins();\r\n\r\n Utils.log(\"Startup\", \"Loading Themes\");\r\n await themeModule.loadThemes();\r\n\r\n DOM.addStyle(\"customcss\", Buffer.from(DataStore.getBDData(\"bdcustomcss\"), \"base64\").toString(\"utf8\"));\r\n\r\n window.addEventListener(\"beforeunload\", function() {\r\n if (settingsCookie[\"bda-dc-0\"]) document.querySelector(\".btn.btn-disconnect\").click();\r\n });\r\n\r\n PluginCertifier.start()\r\n\r\n Utils.log(\"Startup\", \"Removing Loading Icon\");\r\n if (document.getElementsByClassName(\"bd-loaderv2\").length) document.getElementsByClassName(\"bd-loaderv2\")[0].remove();\r\n Utils.log(\"Startup\", \"Initializing Main Observer\");\r\n this.initObserver();\r\n\r\n // Show loading errors\r\n if (settingsCookie[\"fork-ps-1\"]) {\r\n Utils.log(\"Startup\", \"Collecting Startup Errors\");\r\n Utils.showContentErrors({plugins: bdpluginErrors, themes: bdthemeErrors});\r\n }\r\n\r\n const previousVersion = DataStore.getBDData(\"version\");\r\n if (bbdVersion > previousVersion) {\r\n if (bbdChangelog) this.showChangelogModal(bbdChangelog);\r\n DataStore.setBDData(\"version\", bbdVersion);\r\n }\r\n\r\n EmojiModule.start()\r\n\r\n Utils.suppressErrors(this.patchSocial.bind(this), \"BD Social Patch\")();\r\n Utils.suppressErrors(this.patchGuildPills.bind(this), \"BD Guild Pills Patch\")();\r\n Utils.suppressErrors(this.patchGuildListItems.bind(this), \"BD Guild List Items Patch\")();\r\n Utils.suppressErrors(this.patchGuildSeparator.bind(this), \"BD Guild Separator Patch\")();\r\n Utils.suppressErrors(this.patchMessageHeader.bind(this), \"BD Badge Chat Patch\")();\r\n Utils.suppressErrors(this.patchMemberList.bind(this), \"BD Badge Member List Patch\")();\r\n Utils.suppressErrors(this.patchAttachment.bind(this), \"LC Plugin Certifier Patch\")();\r\n\r\n if(bdConfig.haveInstalledDefault){\r\n let alert = Utils.alert(\"First Installation\", \"As it is the first time you install Lightcord, We added two default themes and one default plugin in your plugin/theme folder. Check it in the Plugin/Theme settings.\")\r\n await new Promise((resolve) => {\r\n alert.onClose(resolve)\r\n })\r\n }\r\n const logo = document.querySelector(\"#app-mount > div.typeWindows-1za-n7.withFrame-haYltI.titleBar-AC4pGV.horizontalReverse-3tRjY7.flex-1O1GKY.directionRowReverse-m8IjIq.justifyStart-2NDFzi.alignStretch-DpGPf3.da-typeWindows.da-withFrame.da-titleBar.da-horizontalReverse.da-flex.da-directionRowReverse.da-justifyStart.da-alignStretch > div.wordmarkWindows-1v0lYD.wordmark-2iDDfm.da-wordmarkWindows.da-wordmark\")\r\n if(logo){\r\n logo.style.top = \"3px\"\r\n logo.innerHTML = ``\r\n }\r\n};\r\n\r\nCore.prototype.patchAttributes = async function() {\r\n let attribsPatchs = []\r\n this.cancelPatchAttributes = function() {\r\n attribsPatchs.forEach(e => e())\r\n }\r\n\r\n while(!v2.MessageComponent)await new Promise(resolve => setTimeout(resolve, 100))\r\n \r\n // TODO: try to patch correctly the user popout on a next update\r\n const Anchor = WebpackModules.find(m => m.displayName == \"Anchor\");\r\n window.Lightcord.Api.ensureExported(e => e.default && e.default.displayName === \"DiscordTag\")\r\n .then(DiscordTag => {\r\n let DiscordTagComp = DiscordTag.default\r\n DiscordTag.default = function(props){\r\n let returnValue = DiscordTagComp(props)\r\n\r\n let id = uuidv4()\r\n\r\n let badgeDiv = BDV2.React.createElement(\"div\", {\r\n style: {\r\n display: \"inline\",\r\n marginTop: \"5px\"\r\n }\r\n }, BDV2.React.createElement(\"span\", {\r\n id: \"badges-\"+id,\r\n key: \"badges-\"+id,\r\n style: {\r\n display: \"inherit\"\r\n }\r\n }))\r\n\r\n let children = [returnValue]\r\n\r\n if (props.user.id === \"249746236008169473\") { // Rauenzi: BandagedBD Developer\r\n children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"BandagedBD Developer\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-chat-badge\", href: \"https://github.com/rauenzi/BetterDiscordApp\", title: \"BandagedBD\", target: \"_blank\"},\r\n BDV2.React.createElement(BDLogo, {size: \"16px\", className: \"bd-logo\"})\r\n )\r\n )\r\n );\r\n } else if (props.user.id === \"696481194443014174\" || props.user.id === \"696003456611385396\"){ // Not Thomiz: Lightcord Developer, Phorcys: Lightcord Developer\r\n children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"Lightcord Developer\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-chat-badge\", href: \"https://github.com/Lightcord/Lightcord\", title: \"Lightcord\", target: \"_blank\"},\r\n BDV2.React.createElement(LightcordLogo, {size: \"16px\", className: \"bd-logo\"})\r\n )\r\n )\r\n );\r\n }\r\n\r\n children.push(badgeDiv)\r\n let div = BDV2.React.createElement(\"div\", {\r\n style: {\r\n display: \"block\"\r\n }\r\n }, children)\r\n applyBadges(id, props.user, false)\r\n\r\n return div\r\n }\r\n })\r\n\r\n attribsPatchs.push(Utils.monkeyPatch(v2.MessageComponent, \"default\", {after: (data) => {\r\n if(data.methodArguments[0].childrenMessageContent.props.message){ // this can be a blocked message (not opened)\r\n data.returnValue.props[\"data-message-id\"] = data.methodArguments[0].childrenMessageContent.props.message.id\r\n }\r\n }}))\r\n /*\r\n attribsPatchs.push(Utils.monkeyPatch(v2.MessageComponent, \"default\", {after: (data) => {\r\n data.returnValue.props[\"message-id\"] = data.methodArguments[0].childrenMessageContent.props.message.id\r\n }}))*/\r\n}\r\n\r\nCore.prototype.checkForGuilds = function() {\r\n let timesChecked = 0;\r\n return new Promise(resolve => {\r\n const checkForGuilds = function() {\r\n const wrapper = BDV2.guildClasses.wrapper.split(\" \")[0];\r\n if (document.querySelectorAll(`.${wrapper}`).length > 0) timesChecked++;\r\n const guild = BDV2.guildClasses.listItem.split(\" \")[0];\r\n const blob = BDV2.guildClasses.blobContainer.split(\" \")[0];\r\n if (document.querySelectorAll(`.${wrapper} .${guild} .${blob}`).length > 0) return resolve(bdConfig.deferLoaded = true);\r\n else if (timesChecked >= 50) return resolve(bdConfig.deferLoaded = true);\r\n setTimeout(checkForGuilds, 100);\r\n };\r\n if (document.readyState != \"loading\") setTimeout(checkForGuilds, 100);\r\n document.addEventListener(\"DOMContentLoaded\", () => {setTimeout(checkForGuilds, 100);});\r\n });\r\n};\r\n\r\nCore.prototype.injectExternals = async function() {\r\n // No externals\r\n};\r\n\r\nCore.prototype.initSettings = function () {\r\n DataStore.initialize();\r\n if(!DataStore.getSettingGroup(\"lightcord-settings\")){\r\n for(let key in lightcordSettings){\r\n delete lightcordSettings[key]\r\n }\r\n }\r\n if(!DataStore.getSettingGroup(\"rpc\")){\r\n Object.assign(settingsRPC, defaultRPC);\r\n }\r\n if(!DataStore.getSettingGroup(\"settings\")){\r\n Object.assign(settingsCookie, defaultCookie);\r\n settingsPanel.saveSettings();\r\n } else {\r\n settingsPanel.loadSettings();\r\n for (const setting in defaultCookie) {\r\n if (settingsCookie[setting] == undefined) {\r\n settingsCookie[setting] = defaultCookie[setting];\r\n settingsPanel.saveSettings();\r\n }\r\n }\r\n }\r\n window.Lightcord.Api.ensureExported(e => e.default && e.default.prototype && e.default.prototype.getPredicateSections)\r\n .then(settingModule => {\r\n\r\n let getPredicateSections = settingModule.default.prototype.getPredicateSections\r\n settingModule.default.prototype.getPredicateSections = function(){\r\n let result = getPredicateSections.call(this, ...arguments)\r\n\r\n if(!result[1])return result\r\n if(result[1].section === \"My Account\"){ // user settings, not guild settings\r\n let poped = []\r\n \r\n poped.push(result.pop())\r\n poped.push(result.pop())\r\n poped.push(result.pop())\r\n poped.push(result.pop())\r\n\r\n result.push(...settingsPanel.renderSidebar(this))\r\n\r\n while(poped[0]){\r\n result.push(poped.pop())\r\n }\r\n }\r\n return result\r\n }\r\n })\r\n};\r\n\r\n\r\nlet classNameLayer\r\nlet classNameSocialLinks\r\nlet classNameModal\r\n\r\nCore.prototype.initObserver = function () {\r\n const mainObserver = new MutationObserver((mutations) => {\r\n for (let i = 0, mlen = mutations.length; i < mlen; i++) {\r\n const mutation = mutations[i];\r\n if (typeof pluginModule !== \"undefined\") pluginModule.rawObserver(mutation);\r\n\r\n // if there was nothing added, skip\r\n if (!mutation.addedNodes.length || !(mutation.addedNodes[0] instanceof Element)) continue;\r\n\r\n const node = mutation.addedNodes[0];\r\n\r\n if(!classNameLayer)classNameLayer = BDModules.get((e) => e.layer && typeof e.layer === \"string\" && e.animating)[0].layer\r\n if(!classNameSocialLinks)classNameSocialLinks = BDModules.get((e) => e.socialLinks && typeof e.socialLinks === \"string\")[0].socialLinks\r\n if(!classNameModal)classNameModal = BDModules.get((e) => e.modal && typeof e.modal === \"string\" && e.inner && typeof e.inner === \"string\" && !e.responsiveWidthMobile)[0].modal\r\n\r\n if (node.classList.contains(classNameLayer)) {\r\n if (node.getAttribute(\"aria-label\") === \"GUILD_SETTINGS\"){\r\n node.setAttribute(\"layer-id\", \"server-settings\");\r\n node.setAttribute(\"id\", \"server-settings\");\r\n }\r\n\r\n if (node.getElementsByClassName(classNameSocialLinks).length) {\r\n node.setAttribute(\"layer-id\", \"user-settings\");\r\n node.setAttribute(\"id\", \"user-settings\");\r\n }\r\n }\r\n\r\n if (node.parentElement == document.body && node.querySelector(\"#ace_settingsmenu\")) node.id = \"ace_settingsmenu_container\";\r\n\r\n // Emoji Picker\r\n //node.getElementsByClassName(\"emojiPicker-3m1S-j\").length && !node.querySelector(\".emojiPicker-3m1S-j\").parentElement.classList.contains(\"animatorLeft-1EQxU0\")\r\n //if (node.classList.contains(classNameLayer2) && node.getElementsByClassName(classNameEmojiPicker).length && !node.querySelector(\".\"+classNameEmojiPicker).parentElement.classList.contains(classNameAnimatorLeft)) quickEmoteMenu.obsCallback(node);\r\n\r\n }\r\n });\r\n\r\n mainObserver.observe(document, {\r\n childList: true,\r\n subtree: true\r\n });\r\n};\r\n\r\nCore.prototype.showChangelogModal = function(options = {}) {\r\n return Utils.showChangelogModal(options);\r\n};\r\n\r\nCore.prototype.alert = function(title, content) {\r\n return Utils.alert(title, content);\r\n};\r\n\r\nCore.prototype.patchSocial = function() {\r\n if (this.socialPatch) return;\r\n const TabBar = WebpackModules.find(m => m.displayName == \"TabBar\");\r\n const Anchor = WebpackModules.find(m => m.displayName == \"Anchor\");\r\n if (!TabBar) return;\r\n this.socialPatch = Utils.monkeyPatch(TabBar.prototype, \"render\", {after: (data) => {\r\n const children = data.returnValue.props.children;\r\n if (!children || !children.length || children.length < 3) return;\r\n if (children[children.length - 3].type.displayName !== \"Separator\") return;\r\n if (!children[children.length - 2].type.toString().includes(\"socialLinks\")) return;\r\n if (Anchor) {\r\n let socialModule1 = BDModules.get(e => e.socialLinks)[0]\r\n const original = children[children.length - 2].type;\r\n const newOne = function() {\r\n const returnVal = original(...arguments);\r\n returnVal.props.children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"Lightcord\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-social-link \"+socialModule1.link, href: \"https://github.com/Lightcord/Lightcord\", title: \"Lightcord\", target: \"_blank\"},\r\n BDV2.React.createElement(LightcordLogo, {size: \"16px\", className: \"bd-social-logo\"})\r\n )\r\n )\r\n );\r\n returnVal.props.children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"BandagedBD\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-social-link \"+socialModule1.link, href: \"https://github.com/rauenzi/BetterDiscordApp\", title: \"BandagedBD\", target: \"_blank\"},\r\n BDV2.React.createElement(BDLogo, {size: \"16px\", className: \"bd-social-logo\"})\r\n )\r\n )\r\n );\r\n return returnVal;\r\n };\r\n children[children.length - 2].type = newOne;\r\n }\r\n\r\n let [\r\n classNameColorMuted,\r\n sizes,\r\n classNameVersionHash\r\n ] = [\r\n BDModules.get(e => e.colorMuted)[0].colorMuted,\r\n BDModules.get(e => e.size32)[0],\r\n BDModules.get(e => e.versionHash)[0].versionHash\r\n ]\r\n\r\n const versionHash = `(${bdConfig.hash ? bdConfig.hash.substring(0, 7) : bdConfig.branch})`;\r\n const additional = [\r\n BDV2.react.createElement(\"div\", {className: `${classNameColorMuted} ${sizes.size12}`}, `Lightcord ${electron.getGlobal(\"BuildInfo\").version} `, BDV2.react.createElement(\"span\", {className: classNameVersionHash+\" da-versionHash\"}, `(${(electron.getGlobal(\"BuildInfo\").commit || \"Unknown\").slice(0, 7)})`)),\r\n BDV2.react.createElement(\"div\", {className: `${classNameColorMuted} ${sizes.size12}`}, `BBD ${bbdVersion} `, BDV2.react.createElement(\"span\", {className: classNameVersionHash+\" da-versionHash\"}, versionHash))\r\n ]\r\n \r\n\r\n const originalVersions = children[children.length - 1].type;\r\n children[children.length - 1].type = function() {\r\n const returnVal = originalVersions(...arguments);\r\n returnVal.props.children.splice(1, 0, additional);\r\n return returnVal;\r\n };\r\n }});\r\n};\r\n\r\nconst getGuildClasses = function() {\r\n const guildsWrapper = WebpackModules.findByProps(\"wrapper\", \"unreadMentionsBar\");\r\n const guilds = WebpackModules.findByProps(\"guildsError\", \"selected\");\r\n const pill = WebpackModules.findByProps(\"blobContainer\");\r\n return Object.assign({}, guildsWrapper, guilds, pill);\r\n};\r\n\r\nCore.prototype.patchGuildListItems = function() {\r\n if (this.guildListItemsPatch) return;\r\n const GuildClasses = getGuildClasses();\r\n const listItemClass = GuildClasses.listItem.split(\" \")[0];\r\n const blobClass = GuildClasses.blobContainer.split(\" \")[0];\r\n const reactInstance = BDV2.getInternalInstance(document.querySelector(`.${listItemClass} .${blobClass}`).parentElement);\r\n const GuildComponent = reactInstance.return.type;\r\n if (!GuildComponent) return;\r\n this.guildListItemsPatch = Utils.monkeyPatch(GuildComponent.prototype, \"render\", {after: (data) => {\r\n if (data.returnValue && data.thisObject) {\r\n const returnValue = data.returnValue;\r\n const guildData = data.thisObject.props;\r\n let className = returnValue.props.className\r\n className += \" bd-guild\";\r\n if (guildData.unread) className += \" bd-unread\";\r\n if (guildData.selected) className += \" bd-selected\";\r\n if (guildData.audio) className += \" bd-audio\";\r\n if (guildData.video) className += \" bd-video\";\r\n if (guildData.badge) className += \" bd-badge\";\r\n if (guildData.animatable) className += \" bd-animatable\";\r\n returnValue.props.className = className\r\n return returnValue;\r\n }\r\n }});\r\n};\r\n\r\nCore.prototype.patchGuildPills = function() {\r\n if (this.guildPillPatch) return;\r\n const guildPill = WebpackModules.find(m => m.default && !m.default.displayName && m.default.toString && m.default.toString().includes(\"translate3d\"));\r\n if (!guildPill) return;\r\n this.guildPillPatch = Utils.monkeyPatch(guildPill, \"default\", {after: (data) => {\r\n const props = data.methodArguments[0];\r\n if (props.unread) data.returnValue.props.className += \" bd-unread\";\r\n if (props.selected) data.returnValue.props.className += \" bd-selected\";\r\n if (props.hovered) data.returnValue.props.className += \" bd-hovered\";\r\n return data.returnValue;\r\n }});\r\n};\r\n\r\nCore.prototype.patchGuildSeparator = function() {\r\n if (this.guildSeparatorPatch) return;\r\n const Guilds = WebpackModules.findByDisplayName(\"Guilds\");\r\n const guildComponents = WebpackModules.findByProps(\"renderListItem\");\r\n if (!guildComponents || !Guilds) return;\r\n const GuildSeparator = function() {\r\n const returnValue = guildComponents.Separator(...arguments);\r\n returnValue.props.className += \" bd-guild-separator\";\r\n return returnValue;\r\n };\r\n this.guildSeparatorPatch = Utils.monkeyPatch(Guilds.prototype, \"render\", {after: (data) => {\r\n data.returnValue.props.children[1].props.children[3].type = GuildSeparator;\r\n }});\r\n};\r\n\r\nCore.prototype.patchAttachment = function() {\r\n if (this.AttachmentPatch) return;\r\n const Attachment = BDModules.get(e => e.default && e.default.displayName === \"Attachment\")[0] // temporary\r\n const Anchor = WebpackModules.find(m => m.displayName == \"Anchor\");\r\n if (!Anchor || !Attachment || !Attachment.default) return;\r\n this.AttachmentPatch = Utils.monkeyPatch(Attachment, \"default\", {after: (data) => {\r\n if(!settingsCookie[\"fork-ps-6\"])return\r\n const attachment = data.methodArguments[0] || null\r\n const children = Utils.getNestedProp(data.returnValue, \"props.children\");\r\n\r\n if (!children || !attachment || !attachment.url)return\r\n if (!Array.isArray(children)) return;\r\n\r\n const id = uuidv4()\r\n children.push(BDV2.react.createElement(\"span\", {\r\n id: \"certified-\"+id\r\n }))\r\n PluginCertifier.patch(attachment, \"certified-\"+id)\r\n }})\r\n}\r\n\r\nCore.prototype.patchMessageHeader = function() {\r\n if (this.messageHeaderPatch) return;\r\n const MessageHeader = WebpackModules.findByProps(\"MessageTimestamp\");\r\n const Anchor = WebpackModules.find(m => m.displayName == \"Anchor\");\r\n if (!Anchor || !MessageHeader || !MessageHeader.default) return;\r\n this.messageHeaderPatch = Utils.monkeyPatch(MessageHeader, \"default\", {after: (data) => {\r\n const author = Utils.getNestedProp(data.methodArguments[0], \"message.author\");\r\n // const header = Utils.getNestedProp(data.returnValue, \"props.children.1.props\");\r\n const children = Utils.getNestedProp(data.returnValue, \"props.children.1.props.children.1.props.children\");\r\n if (!children || !author || !author.id)return\r\n // if (header && header.className) header.className += \" \"\r\n if (!Array.isArray(children)) return;\r\n if (author.id === \"249746236008169473\") { // Rauenzi: BandagedBD Developer\r\n children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"BandagedBD Developer\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-chat-badge\", href: \"https://github.com/rauenzi/BetterDiscordApp\", title: \"BandagedBD\", target: \"_blank\"},\r\n BDV2.React.createElement(BDLogo, {size: \"16px\", className: \"bd-logo\"})\r\n )\r\n )\r\n );\r\n } else if (author.id === \"696481194443014174\" || author.id === \"696003456611385396\"){ // Not Thomiz: Lightcord Developer, Phorcys: Lightcord Developer\r\n children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"Lightcord Developer\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-chat-badge\", href: \"https://github.com/Lightcord/Lightcord\", title: \"Lightcord\", target: \"_blank\"},\r\n BDV2.React.createElement(LightcordLogo, {size: \"16px\", className: \"bd-logo\"})\r\n )\r\n )\r\n );\r\n }\r\n const id = uuidv4()\r\n children.push(\r\n BDV2.React.createElement(\"div\", {\r\n id: \"badges-\"+id,\r\n style: {\r\n display: \"inline\"\r\n }\r\n })\r\n )\r\n applyBadges(id, author, true)\r\n }});\r\n};\r\n\r\nfunction applyBadges(id, user, chat){\r\n process.nextTick(() => {\r\n const div = document.getElementById(\"badges-\"+id)\r\n if(!div || div.childNodes.length > 0)return\r\n if(div.childNodes.length)return\r\n let blockDiv = document.createElement(\"div\")\r\n blockDiv.style.display = \"none\"\r\n div.appendChild(blockDiv)\r\n\r\n const Anchor = WebpackModules.find(m => m.displayName == \"Anchor\");\r\n\r\n distant.getBadges(user.id)\r\n .then(badges => {\r\n badges.forEach(badge => {\r\n const props = {\r\n svg: {\r\n size: \"16px\", \r\n className: \"bd-logo\",\r\n width: \"16px\", \r\n }\r\n }\r\n badge.scopes.forEach(scope => {\r\n if(scope === \"user\"){// require user\r\n props.user = user\r\n }\r\n }) \r\n if(!badge.href){\r\n props.Anchor = Anchor\r\n props.href = {\r\n className: chat ? \"bd-chat-badge\" : \"bd-member-badge\", \r\n title: badge.name, \r\n target: \"_blank\"\r\n }\r\n }\r\n const element = BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: badge.name},\r\n badge.href ? BDV2.react.createElement(Anchor, {\r\n href: badge.href,\r\n className: chat ? \"bd-chat-badge\" : \"bd-member-badge\", \r\n title: badge.name, \r\n target: \"_blank\"\r\n }, BDV2.React.createElement(badge.component, props)) : BDV2.React.createElement(badge.component, props)\r\n )\r\n const div2 = document.createElement(\"div\")\r\n BDV2.reactDom.render(element, div2)\r\n div2.childNodes.forEach(node => {\r\n div.appendChild(node)\r\n })\r\n })\r\n })\r\n })\r\n}\r\n\r\nCore.prototype.patchMemberList = function() {\r\n if (this.memberListPatch) return;\r\n const MemberListItem = WebpackModules.findByDisplayName(\"MemberListItem\");\r\n const Anchor = WebpackModules.find(m => m.displayName == \"Anchor\");\r\n if (!Anchor || !MemberListItem || !MemberListItem.prototype || !MemberListItem.prototype.renderDecorators) return;\r\n this.memberListPatch = Utils.monkeyPatch(MemberListItem.prototype, \"renderDecorators\", {after: (data) => {\r\n const user = Utils.getNestedProp(data.thisObject, \"props.user\");\r\n const children = Utils.getNestedProp(data.returnValue, \"props.children\");\r\n if (!children || !user || !user.id)return\r\n // if (header && header.className) header.className += \" \"\r\n if (!Array.isArray(children)) return;\r\n if (user.id === \"249746236008169473\") {\r\n children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"BandagedBD Developer\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-member-badge\", href: \"https://github.com/rauenzi/BetterDiscordApp\", title: \"BandagedBD\", target: \"_blank\"},\r\n BDV2.React.createElement(BDLogo, {size: \"16px\", className: \"bd-logo\"})\r\n )\r\n )\r\n );\r\n } else if (user.id === \"696481194443014174\" || user.id === \"696003456611385396\"){\r\n children.push(\r\n BDV2.React.createElement(TooltipWrap, {color: \"black\", side: \"top\", text: \"Lightcord Developer\"},\r\n BDV2.React.createElement(Anchor, {className: \"bd-member-badge\", href: \"https://github.com/Lightcord/Lightcord\", title: \"Lightcord\", target: \"_blank\"},\r\n BDV2.React.createElement(LightcordLogo, {size: \"16px\", className: \"bd-logo\"})\r\n )\r\n )\r\n );\r\n }\r\n const id = uuidv4()\r\n children.push(\r\n BDV2.React.createElement(\"div\", {id: \"badges-\"+id})\r\n )\r\n applyBadges(id, user, false)\r\n }});\r\n};\r\n\r\nCore.prototype.updateInjector = async function() {\r\n // There will never be an injection path, so we do not need the code below. \r\n // Insert comments so it will be erased when production.\r\n \r\n const injectionPath = DataStore.injectionPath;\r\n if (!injectionPath) return false;\r\n\r\n /*\r\n\r\n const fs = require(\"fs\");\r\n const path = require(\"path\");\r\n const rmrf = require(\"rimraf\");\r\n const yauzl = require(\"yauzl\");\r\n const mkdirp = require(\"mkdirp\");\r\n const request = require(\"request\");\r\n\r\n const parentPath = path.resolve(injectionPath, \"..\");\r\n const folderName = path.basename(injectionPath);\r\n const zipLink = \"https://github.com/rauenzi/BetterDiscordApp/archive/injector.zip\";\r\n const savedZip = path.resolve(parentPath, \"injector.zip\");\r\n const extractedFolder = path.resolve(parentPath, \"BetterDiscordApp-injector\");\r\n\r\n // Download the injector zip file\r\n Utils.log(\"InjectorUpdate\", \"Downloading \" + zipLink);\r\n let success = await new Promise(resolve => {\r\n request.get({url: zipLink, encoding: null}, async (error, response, body) => {\r\n if (error || response.statusCode !== 200) return resolve(false);\r\n // Save a backup in case someone has their own copy\r\n const alreadyExists = await new Promise(res => fs.exists(savedZip, res));\r\n if (alreadyExists) await new Promise(res => fs.rename(savedZip, `${savedZip}.bak${Math.round(performance.now())}`, res));\r\n\r\n Utils.log(\"InjectorUpdate\", \"Writing \" + savedZip);\r\n fs.writeFile(savedZip, body, err => resolve(!err));\r\n });\r\n });\r\n if (!success) return success;\r\n\r\n // Check and delete rename extraction\r\n const alreadyExists = await new Promise(res => fs.exists(extractedFolder, res));\r\n if (alreadyExists) await new Promise(res => fs.rename(extractedFolder, `${extractedFolder}.bak${Math.round(performance.now())}`, res));\r\n \r\n // Unzip the downloaded zip file\r\n const zipfile = await new Promise(r => yauzl.open(savedZip, {lazyEntries: true}, (err, zip) => r(zip)));\r\n zipfile.on(\"entry\", function(entry) {\r\n // Skip directories, they are handled with mkdirp\r\n if (entry.fileName.endsWith(\"/\")) return zipfile.readEntry();\r\n\r\n Utils.log(\"InjectorUpdate\", \"Extracting \" + entry.fileName);\r\n // Make any needed parent directories\r\n const fullPath = path.resolve(parentPath, entry.fileName);\r\n mkdirp.sync(path.dirname(fullPath));\r\n zipfile.openReadStream(entry, function(err, readStream) {\r\n if (err) return success = false;\r\n readStream.on(\"end\", function() {zipfile.readEntry();}); // Go to next file after this\r\n readStream.pipe(fs.createWriteStream(fullPath));\r\n });\r\n });\r\n zipfile.readEntry(); // Start reading\r\n\r\n // Wait for the final file to finish\r\n await new Promise(resolve => zipfile.once(\"end\", resolve));\r\n\r\n // Save a backup in case something goes wrong during final step\r\n const backupFolder = path.resolve(parentPath, `${folderName}.bak${Math.round(performance.now())}`);\r\n await new Promise(resolve => fs.rename(injectionPath, backupFolder, resolve));\r\n\r\n // Rename the extracted folder to what it should be\r\n Utils.log(\"InjectorUpdate\", `Renaming ${path.basename(extractedFolder)} to ${folderName}`);\r\n success = await new Promise(resolve => fs.rename(extractedFolder, injectionPath, err => resolve(!err)));\r\n if (!success) {\r\n Utils.err(\"InjectorUpdate\", \"Failed to rename the final directory\");\r\n return success;\r\n }\r\n\r\n // If rename had issues, delete what we tried to rename and restore backup\r\n if (!success) {\r\n Utils.err(\"InjectorUpdate\", \"Something went wrong... restoring backups.\");\r\n await new Promise(resolve => rmrf(extractedFolder, resolve));\r\n await new Promise(resolve => fs.rename(backupFolder, injectionPath, resolve));\r\n return success;\r\n }\r\n\r\n // If we've gotten to this point, everything should have gone smoothly.\r\n // Cleanup the backup folder then remove the zip\r\n await new Promise(resolve => rmrf(backupFolder, resolve));\r\n await new Promise(resolve => fs.unlink(savedZip, resolve));\r\n\r\n Utils.log(\"InjectorUpdate\", \"Injector Updated!\");\r\n return success;*/\r\n};\r\n\r\nexport default new Core();\r\n\r\n/**\r\n * Don't expose core - could be dangerous for now\r\n */","import {pluginCookie, themeCookie, bdplugins, bdthemes, settingsCookie, settings} from \"../0globals\";\r\nimport mainCore from \"./core\";\r\nimport Utils from \"./utils\";\r\nimport BDV2 from \"./v2\";\r\nimport DataStore from \"./dataStore\";\r\nimport pluginModule from \"./pluginModule\";\r\nimport themeModule from \"./themeModule\";\r\nimport settingsPanel from \"./settingsPanel\";\r\nimport DOM from \"./domtools\";\r\n\r\nconst BdApi = {\r\n get React() { return BDV2.React; },\r\n get ReactDOM() { return BDV2.ReactDom; },\r\n get ReactComponent() {return BDV2.ReactComponent;},\r\n get WindowConfigFile() {return Utils.WindowConfigFile;},\r\n get settings() {return settings;},\r\n get emotes() {return null}, // deprecated, deleted all emotes from betterdiscord.\r\n get screenWidth() { return Math.max(document.documentElement.clientWidth, window.innerWidth || 0); },\r\n get screenHeight() { return Math.max(document.documentElement.clientHeight, window.innerHeight || 0); }\r\n};\r\n\r\nBdApi.getAllWindowPreferences = function() {\r\n return Utils.getAllWindowPreferences();\r\n};\r\n\r\nBdApi.getWindowPreference = function(key) {\r\n return Utils.getWindowPreference(key);\r\n};\r\n\r\nBdApi.setWindowPreference = function(key, value) {\r\n return Utils.setWindowPreference(key, value);\r\n};\r\n\r\n//Inject CSS to document head\r\n//id = id of element\r\n//css = custom css\r\nBdApi.injectCSS = function (id, css) {\r\n DOM.addStyle(DOM.escapeID(id), css);\r\n};\r\n\r\n//Clear css/remove any element\r\n//id = id of element\r\nBdApi.clearCSS = function (id) {\r\n DOM.removeStyle(DOM.escapeID(id));\r\n};\r\n\r\n//Inject CSS to document head\r\n//id = id of element\r\n//css = custom css\r\nBdApi.linkJS = function (id, url) {\r\n DOM.addScript(DOM.escapeID(id), url);\r\n};\r\n\r\n//Clear css/remove any element\r\n//id = id of element\r\nBdApi.unlinkJS = function (id) {\r\n DOM.removeScript(DOM.escapeID(id));\r\n};\r\n\r\n//Get another plugin\r\n//name = name of plugin\r\nBdApi.getPlugin = function (name) {\r\n if (bdplugins.hasOwnProperty(name)) {\r\n return bdplugins[name].plugin;\r\n }\r\n return null;\r\n};\r\n\r\n//Get BetterDiscord Core\r\nBdApi.getCore = function () {\r\n Utils.warn(\"Deprecation Notice\", `BdApi.getCore() will be removed in future versions.`);\r\n return mainCore;\r\n};\r\n\r\n/**\r\n * Shows a generic but very customizable modal.\r\n * @param {string} title - title of the modal\r\n * @param {string} content - a string of text to display in the modal\r\n */\r\nBdApi.alert = function (title, content) {\r\n return Utils.showConfirmationModal(title, content, {cancelText: null});\r\n};\r\n\r\n/**\r\n * Shows a generic but very customizable confirmation modal with optional confirm and cancel callbacks.\r\n * @param {string} title - title of the modal\r\n * @param {(string|ReactElement|Array)} children - a single or mixed array of react elements and strings. Every string is wrapped in Discord's `Markdown` component so strings will show and render properly.\r\n * @param {object} [options] - options to modify the modal\r\n * @param {boolean} [options.danger=false] - whether the main button should be red or not\r\n * @param {string} [options.confirmText=Okay] - text for the confirmation/submit button\r\n * @param {string} [options.cancelText=Cancel] - text for the cancel button\r\n * @param {callable} [options.onConfirm=NOOP] - callback to occur when clicking the submit button\r\n * @param {callable} [options.onCancel=NOOP] - callback to occur when clicking the cancel button\r\n * @param {string} [options.key] - key used to identify the modal. If not provided, one is generated and returned\r\n * @returns {string} - the key used for this modal\r\n */\r\nBdApi.showConfirmationModal = function (title, content, options = {}) {\r\n return Utils.showConfirmationModal(title, content, options);\r\n};\r\n\r\n//Show toast alert\r\nBdApi.showToast = function(content, options = {}) {\r\n Utils.showToast(content, options);\r\n};\r\n\r\n// Finds module\r\nBdApi.findModule = function(filter) {\r\n return BDV2.WebpackModules.find(filter);\r\n};\r\n\r\n// Finds module\r\nBdApi.findAllModules = function(filter) {\r\n return BDV2.WebpackModules.findAll(filter);\r\n};\r\n\r\n// Finds module\r\nBdApi.findModuleByProps = function(...props) {\r\n return BDV2.WebpackModules.findByUniqueProperties(props);\r\n};\r\n\r\nBdApi.findModuleByPrototypes = function(...protos) {\r\n return BDV2.WebpackModules.findByPrototypes(protos);\r\n};\r\n\r\nBdApi.findModuleByDisplayName = function(name) {\r\n return BDV2.WebpackModules.findByDisplayName(name);\r\n};\r\n\r\n// Gets react instance\r\nBdApi.getInternalInstance = function(node) {\r\n if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined;\r\n if (node instanceof jQuery) node = node[0];\r\n return BDV2.getInternalInstance(node);\r\n};\r\n\r\n// Gets data\r\nBdApi.loadData = function(pluginName, key) {\r\n return DataStore.getPluginData(pluginName, key);\r\n};\r\n\r\nBdApi.getData = BdApi.loadData;\r\n\r\n// Sets data\r\nBdApi.saveData = function(pluginName, key, data) {\r\n return DataStore.setPluginData(pluginName, key, data);\r\n};\r\n\r\nBdApi.setData = BdApi.saveData;\r\n\r\n// Deletes data\r\nBdApi.deleteData = function(pluginName, key) {\r\n return DataStore.deletePluginData(pluginName, key);\r\n};\r\n\r\n// Patches other functions\r\nBdApi.monkeyPatch = function(what, methodName, options) {\r\n return Utils.monkeyPatch(what, methodName, options);\r\n};\r\n\r\n// Event when element is removed\r\nBdApi.onRemoved = function(node, callback) {\r\n return Utils.onRemoved(node, callback);\r\n};\r\n\r\n// Wraps function in try..catch\r\nBdApi.suppressErrors = function(method, message) {\r\n return Utils.suppressErrors(method, message);\r\n};\r\n\r\n// Tests for valid JSON\r\nBdApi.testJSON = function(data) {\r\n return Utils.testJSON(data);\r\n};\r\n\r\nBdApi.isPluginEnabled = function(name) {\r\n return !!pluginCookie[name];\r\n};\r\n\r\nBdApi.isThemeEnabled = function(name) {\r\n return !!themeCookie[name];\r\n};\r\n\r\nBdApi.isSettingEnabled = function(id) {\r\n return !!settingsCookie[id];\r\n};\r\n\r\nBdApi.enableSetting = function(id) {\r\n return settingsPanel.onChange(id, true);\r\n};\r\n\r\nBdApi.disableSetting = function(id) {\r\n return settingsPanel.onChange(id, false);\r\n};\r\n\r\nBdApi.toggleSetting = function(id) {\r\n return settingsPanel.onChange(id, !settingsCookie[id]);\r\n};\r\n\r\n// Gets data\r\nBdApi.getBDData = function(key) {\r\n return DataStore.getBDData(key);\r\n};\r\n\r\n// Sets data\r\nBdApi.setBDData = function(key, data) {\r\n return DataStore.setBDData(key, data);\r\n};\r\n\r\n\r\n\r\nconst makeAddonAPI = (cookie, list, manager) => new class AddonAPI {\r\n\r\n get folder() {return manager.folder;}\r\n\r\n isEnabled(name) {\r\n return !!cookie[name];\r\n }\r\n\r\n enable(name) {\r\n return manager.enable(name);\r\n }\r\n\r\n disable(name) {\r\n return manager.disable(name);\r\n }\r\n\r\n toggle(name) {\r\n if (cookie[name]) this.disable(name);\r\n else this.enable(name);\r\n }\r\n\r\n reload(name) {\r\n return manager.reload(name);\r\n }\r\n\r\n get(name) {\r\n if (list.hasOwnProperty(name)) {\r\n if (list[name].plugin) return list[name].plugin;\r\n return list[name];\r\n }\r\n return null;\r\n }\r\n\r\n getAll() {\r\n return Object.keys(list).map(k => this.get(k)).filter(a => a);\r\n }\r\n};\r\n\r\nBdApi.Plugins = makeAddonAPI(pluginCookie, bdplugins, pluginModule);\r\nBdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule);\r\n\r\nexport default BdApi;\r\n\r\nwindow.Lightcord.BetterDiscord.BdApi = BdApi","export default function() {\r\n const contentWindowGetter = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, \"contentWindow\").get;\r\n Object.defineProperty(HTMLIFrameElement.prototype, \"contentWindow\", {\r\n get: function () {\r\n const contentWindow = Reflect.apply(contentWindowGetter, this, arguments);\r\n return new Proxy(contentWindow, {\r\n getOwnPropertyDescriptor: function(obj, prop) {\r\n if (prop === \"localStorage\") return undefined;\r\n return Object.getOwnPropertyDescriptor(obj, prop);\r\n },\r\n get: function(obj, prop) {\r\n if (prop === \"localStorage\") return null;\r\n const val = obj[prop];\r\n if (typeof val === \"function\") return val.bind(obj);\r\n return val;\r\n }\r\n });\r\n }\r\n });\r\n\r\n // Prevent interception by patching Reflect.apply and Function.prototype.bind\r\n Object.defineProperty(Reflect, \"apply\", {value: Reflect.apply, writable: false, configurable: false});\r\n Object.defineProperty(Function.prototype, \"bind\", {value: Function.prototype.bind, writable: false, configurable: false});\r\n\r\n const oOpen = XMLHttpRequest.prototype.open;\r\n XMLHttpRequest.prototype.open = function() {\r\n const url = arguments[1];\r\n if (url.toLowerCase().includes(\"api/webhooks\")) return null;\r\n return Reflect.apply(oOpen, this, arguments);\r\n };\r\n}","import localStorageFix from \"./localStorageFix\";\r\nimport loadingIcon from \"./loadingIcon\";\r\nlocalStorageFix();\r\nloadingIcon();\r\n\r\nconst deprecateGlobal = (key, value) => {\r\n Object.defineProperty(window, key, {\r\n get() {\r\n Utils.warn(\"Deprecated Global\", `\"${key}\" will be removed in future versions. Please only use BdApi.`);\r\n return value;\r\n }\r\n }); \r\n};\r\n\r\n\r\nimport * as Globals from \"./0globals\";\r\n\r\nconst globalKeys = Object.keys(Globals);\r\nfor (const key of globalKeys) deprecateGlobal(key, Globals[key]);\r\n\r\n\r\nimport BdApi from \"./modules/bdApi\";\r\nimport BDV2 from \"./modules/v2\";\r\nimport pluginModule from \"./modules/pluginModule\";\r\nimport themeModule from \"./modules/themeModule\";\r\nimport Utils from \"./modules/utils\";\r\nimport BDEvents from \"./modules/bdEvents\";\r\nimport settingsPanel from \"./modules/settingsPanel\";\r\nimport DataStore from \"./modules/dataStore\";\r\nimport ContentManager from \"./modules/contentManager\";\r\nimport ClassNormalizer from \"./modules/classNormalizer\";\r\n\r\ndeprecateGlobal(\"BDV2\", BDV2);\r\ndeprecateGlobal(\"pluginModule\", pluginModule);\r\ndeprecateGlobal(\"themeModule\", themeModule);\r\ndeprecateGlobal(\"Utils\", Utils);\r\ndeprecateGlobal(\"BDEvents\", BDEvents);\r\ndeprecateGlobal(\"settingsPanel\", settingsPanel);\r\ndeprecateGlobal(\"DataStore\", DataStore);\r\ndeprecateGlobal(\"ContentManager\", ContentManager);\r\ndeprecateGlobal(\"ClassNormalizer\", ClassNormalizer);\r\n\r\nwindow.BdApi = BdApi;\r\n\r\nimport Core from \"./modules/core\";\r\ndeprecateGlobal(\"mainCore\", Core);\r\n\r\n// TODO: Change Init mode and stop using CoreWrapper.\r\nexport default class CoreWrapper {\r\n constructor(bdConfig, methods) {\r\n Core.setConfig(bdConfig);\r\n Core.setMethods(methods);\r\n }\r\n\r\n init() {\r\n // deprecateGlobal(\"mainCore\", this.mainCore);\r\n Core.init();\r\n }\r\n}","export default () => {\r\n const v2Loader = document.createElement(\"div\");\r\n v2Loader.className = \"bd-loaderv2\";\r\n v2Loader.title = \"BandagedBD is loading...\";\r\n document.body.appendChild(v2Loader);\r\n};"],"sourceRoot":""}