Lightcord/modules/discord_desktop_core/core/app/BetterDiscord/index.js

1292 lines
56 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const ModuleLoader = require("./loaders/modules")
const { EventEmitter } = require("events")
const Logger = require("./Logger")
const fs = require("fs")
const path = require("path")
const electron = require("electron")
const fetch = require("node-fetch").default
const uuid = require("uuid/v4")
const isPackaged = __filename.includes("app.asar")
const events = exports.events = new EventEmitter()
const logger = exports.logger = new Logger("Lightcord")
const appSettings = electron.remote.getGlobal("appSettings")
let hasInit = false
let tries = 0
const browserWindow = electron.remote.getCurrentWindow()
const UserAgent = electron.ipcRenderer.sendSync("LIGHTCORD_GET_USER_AGENT").replace(/lightcord\/[^ ]+/g, "discord/"+require("../discord_native/renderer/app").getVersion())
browserWindow.webContents.userAgent = UserAgent
exports.init = function(){
if(hasInit == true){
console.warn(new Error("Lightcord has already inited."))
return
}
formatLogger.log("The app is", isPackaged ? "packaged." : "not packaged.")
hasInit = true
let readyInterval = setInterval(()=>{
events.emit("debug", `[INIT] try ${tries++} loading Lightcord`)
try{
if(!global.webpackJsonp)return
if(!ModuleLoader.get(4))return
clearInterval(readyInterval)
privateInit()
.then(() => {
console.log("Finished loading Lightcord.")
})
}catch(e){
console.error(e)
}
}, 100)
}
let hasPrivateInit = false
async function privateInit(){
if(!hasInit)return
if(hasPrivateInit)return
hasPrivateInit = true
installReactDevtools()
let cached = require.cache[path.join(__dirname, "loaders", "modules.js")]
if(cached){
cached.exports = window.BDModules
}
//disabling sentry
ModuleLoader.get(e => e.getCurrentHub)[0].getCurrentHub().getClient().getOptions().enabled = false
// setting react in require cache
const React = ModuleLoader.get(e => !["Component", "PureComponent", "Children", "createElement", "cloneElement"].find(k => !e[k]))[0]
window.React = React
const ReactDOM = ModuleLoader.get(e => e.findDOMNode)[0]
window.ReactDOM = ReactDOM
//stop here if betterdiscord is disabled.
if(electron.remote.process.argv.includes("--disable-betterdiscord")){
let formComponents
let margins
class LightcordSettings extends React.Component {
render(){
if(!formComponents)formComponents = ModuleLoader.get(e => e.FormSection)[0]
if(!margins)margins = ModuleLoader.get(e => e.marginTop60)[0]
let button = require("./Button").default
return React.createElement("div", {}, [
React.createElement(formComponents.FormSection, {
className: "",
tag: "h2",
title: "Lightcord's Settings"
}, React.createElement(button, {
color: "yellow",
look: "ghost",
size: "medium",
hoverColor: "red",
onClick: () => {
console.log("Should relaunch")
electron.remote.app.relaunch({
args: electron.remote.process.argv.slice(1).filter(e => e !== "--disable-betterdiscord")
})
electron.remote.app.quit()
},
wrapper: true
}, "Relaunch with BetterDiscord"))
])
}
}
// fix notifications here
let dispatcher = ModuleLoader.get(m=>m.Dispatcher&&m.default&&m.default.dispatch)[0].default
dispatcher.subscribe("USER_SETTINGS_UPDATE", (data) => {
DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme)
})
let constants = ModuleLoader.get(m=>m.API_HOST)[0]
// add menu to re enable BetterDiscord
constants.UserSettingsSections = Object.freeze(Object.assign({}, constants.UserSettingsSections, {LIGHTCORD: "Lightcord"}))
ensureExported(e => e.default && e.default.prototype && e.default.prototype.getPredicateSections)
.then(settingModule => {
let getPredicateSections = settingModule.default.prototype.getPredicateSections
settingModule.default.prototype.getPredicateSections = function(){
let result = getPredicateSections.call(this, ...arguments)
if(result[1].section === "My Account"){ // user settings, not guild settings
let poped = []
poped.push(result.pop())
poped.push(result.pop())
poped.push(result.pop())
poped.push(result.pop())
result.push({
section: "HEADER",
label: "Lightcord"
}, {
section: constants.UserSettingsSections.LIGHTCORD,
label: "Lightcord",
element: LightcordSettings
}, {
section: "DIVIDER"
})
while(poped[0]){
result.push(poped.pop())
}
}
return result
}
})
return
}
let createSoundOriginal = ModuleLoader.get((e) => e.createSound)[0].createSound
ModuleLoader.get((e) => e.createSound)[0].createSound = function(sound){
let isCalling = sound === "call_ringing_beat" || sound === "call_ringing"
if(isCalling){
let returned = createSoundOriginal.call(this, ...arguments)
Object.defineProperty(returned, "name", {
get(){
return window.Lightcord.Settings.callRingingBeat ? "call_ringing_beat" : "call_ringing"
},
set(data){
console.log("Attempting to set call_ringing value. Canceling", data)
},
configurable: false
})
return returned
}else{
return createSoundOriginal(...arguments)
}
}
let constants = ModuleLoader.get(m=>m.API_HOST)[0]
let dispatcher = ModuleLoader.get(m=>m.Dispatcher&&m.default&&m.default.dispatch)[0].default
require(formatMinified(path.join(__dirname, "../../../../../BetterDiscordApp/dist/style{min}.css")))
require("./lightcord.css")
function getCurrentHypesquad(){
let user = ModuleLoader.get(e => e.default && e.default.getCurrentUser)[0].default.getCurrentUser()
if(!user)return undefined
if(user.hasFlag(constants.UserFlags.HYPESQUAD_ONLINE_HOUSE_1))return "1"
if(user.hasFlag(constants.UserFlags.HYPESQUAD_ONLINE_HOUSE_2))return "2"
if(user.hasFlag(constants.UserFlags.HYPESQUAD_ONLINE_HOUSE_3))return "3"
return undefined
}
window.$ = window.jQuery = require("./jquery.min.js")
require("./ace.js")
if(!fs.existsSync(BetterDiscordConfig.dataPath))fs.mkdirSync(BetterDiscordConfig.dataPath, {recursive: true})
let pluginPath = path.join(BetterDiscordConfig.dataPath, "plugins")
let themePath = path.join(BetterDiscordConfig.dataPath, "themes")
console.log(`Plugins: ${pluginPath}\nThemes: ${themePath}`)
if(!fs.existsSync(pluginPath)){
fs.mkdirSync(pluginPath, {recursive: true})
/** Downloads Util Plugins So the user don't have to install it manually */
/** ZeresPluginLibrary */
const ZeresPluginLibraryPath = path.join(pluginPath, "0PluginLibrary.plugin.js")
fetch("https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js")
.then(async res => {
if(res.status !== 200)return
const content = await res.buffer()
fs.writeFileSync(ZeresPluginLibraryPath, content)
})
BetterDiscordConfig.haveInstalledDefault = true // Inform User about what we just did
}
if(!fs.existsSync(themePath)){
fs.mkdirSync(themePath, {recursive: true})
/** Downloads Basic Themes to guide user and showcase features */
/** Discord Dark */
const DarkDiscordPath = path.join(themePath, "DarkDiscord.theme.css")
fetch("https://raw.githubusercontent.com/hellbound1337/dark-discord/master/DarkDiscord.theme.css")
.then(async res => {
if(res.status !== 200)return
const content = await res.buffer()
fs.writeFileSync(DarkDiscordPath, content)
})
/** Glasscord Example */
const GlasscordExamplePath = path.join(themePath, "glasscord_example.theme.css")
fetch("https://raw.githubusercontent.com/AryToNeX/Glasscord/master/extras/discord_example_theme/discord_example.theme.css")
.then(async res => {
if(res.status !== 200)return
const content = await res.buffer()
fs.writeFileSync(GlasscordExamplePath, content)
})
BetterDiscordConfig.haveInstalledDefault = true // Inform User about what we just did
}
// setting Discord Internal Developer Mode for developement and test purposes.
let developerModule = ModuleLoader.get(e => e.default && typeof e.default === "object" && ("isDeveloper" in e.default))[0]
if(developerModule){
Object.defineProperty(developerModule.default, "isDeveloper", {
get(){return !!window.Lightcord.Settings.devMode},
set(data){return !!window.Lightcord.Settings.devMode}
})
}
/**
* @type {typeof import("../../../../../DiscordJS").default}
*/
let DiscordJS
try{
DiscordJS = require("../../../../../DiscordJS").default
}catch(err){
console.error(err)
DiscordJS = null
}
/*let Authorization = appSettings.get("LIGHTCORD_AUTH", false)
let shouldShowPrompt = Authorization === false
if(typeof Authorization !== "string"){
Authorization = null
appSettings.set("LIGHTCORD_AUTH", null)
appSettings.save()
}*/
let cloneNullProto = (obj) => { // recreate object without __proto__
let o = Object.create(null)
Object.keys(obj).forEach(k => {
o[k] = obj[k]
})
return o
}
window.Lightcord = cloneNullProto({
DiscordModules: cloneNullProto({
dispatcher,
constants
}),
Settings: cloneNullProto({
devMode: false,
callRingingBeat: true
}),
Api: cloneNullProto({/*
get Authorization(){
return Authorization
},
set Authorization(data){
if(typeof data !== "string" && data !== null)return Authorization
appSettings.set("LIGHTCORD_AUTH", Authorization = data)
appSettings.save()
},*/
Authorization: null,
ensureExported,
cloneNullProto
}),
BetterDiscord: cloneNullProto({ // Global BetterDiscord's exported modules
})
})
dispatcher.subscribe("USER_SETTINGS_UPDATE", (data) => {
DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme)
})
require(formatMinified("lightcordapi/js/main{min}.js"))
/*
if(shouldShowPrompt){
let onConn = (ev) => {
console.log(`Showing auth window.`, ev)
shouldShowPrompt = false
dispatcher.unsubscribe(constants.ActionTypes.CONNECTION_OPEN || "CONNECTION_OPEN", onConn)
const options = {
width: 500,
height: 550,
backgroundColor: "#202225",
show: true,
resizable: false,
maximizable: false,
minimizable: false,
frame: false,
center: false,
webPreferences: {
nodeIntegration: false,
preload: path.join(__dirname, "auth", "preload.js"),
webviewTag: true
},
parent: electron.remote.getCurrentWindow()
};
options.x = Math.round(window.screenX + window.innerWidth / 2 - options.width / 2);
options.y = Math.round(window.screenY + window.innerHeight / 2 - options.height / 2);
const authWindow = new electron.remote.BrowserWindow(options)
authWindow.webContents.session.protocol.registerFileProtocol("lightcord", (req, callback) => {
const parsedURL = new URL("http://lightcord.xyz/"+req.url.split("://")[1])
let file
if(req.method !== "GET"){
file = "404.html"
}else{
if(parsedURL.pathname === "/index.html"){
file = "index.html"
}else if(parsedURL.pathname === "/index.css"){
file = "index.css"
}else if(parsedURL.pathname === "/login/callback"){
authWindow.close()
console.log(parsedURL.searchParams)
Authorization = parsedURL.searchParams.get("auth")
authWindow = null
return
}
}
if(!file){
file = "404.html"
}
callback(path.join(__dirname, "auth", file))
}, (err) => {
if(err)console.error(err)
})
electron.remote.getCurrentWindow().webContents.on("devtools-reload-page", () => {
electron.remote.protocol.unregisterProtocol("lightcord")
})
authWindow.on("close", () => {
electron.remote.protocol.unregisterProtocol("lightcord")
})
authWindow.loadURL("lightcord://index.html")
}
dispatcher.subscribe(constants.ActionTypes.CONNECTION_OPEN || "CONNECTION_OPEN", onConn)
}*/
const BetterDiscord = window.BetterDiscord = window.mainCore = new(require(formatMinified("../../../../../BetterDiscordApp/dist/index{min}.js")).default)(BetterDiscordConfig, require("./betterdiscord"))
const Utils = window.Lightcord.BetterDiscord.Utils
const DOMTools = window.Lightcord.BetterDiscord.DOM
let isBot = false
dispatcher.subscribe("LOGOUT", () => {
isBot = false
})
;(async function(){
const gatewayModule = await ensureExported(e => e.default && e.default.prototype && e.default.prototype._handleDispatch)
if(!gatewayModule)return
let _handleDispatch = gatewayModule.default.prototype._handleDispatch
gatewayModule.default.prototype._handleDispatch = function(data, event, props){
if(event === "READY"){
console.log(...arguments)
if(false){
dispatcher.dispatch({
type: "LOGOUT"
})
BdApi.showToast(data.user.username+"#"+data.user.discriminator+": This account is blacklisted from Lightcord.", {
type: "error",
timeout: 10000
})
appSettings.get("­", true)
appSettings.save()
return
}
isBot = data.user.bot
if(data.user.bot){
logger.log(`Logged in as a bot, spoofing user...`)
data.user.bot = false
data.user.premium = true
data.user.premium_type = 1
data.user.email = data.user.email || uuid()+"@lightcord.xyz" // filler email, not a real one
data.experiments = data.experiments || []
data.guild_experiments = data.guild_experiments || [];
data.connected_accounts = data.connected_accounts || [];
data.relationships = data.relationships || [];
data.notes = data.notes || {};
data.user_feed_settings = data.user_feed_settings || [];
data.analytics_tokens = data.analytics_tokens || [];
data.analytics_token = data.analytics_token || ""
data.private_channels = data.private_channels || [];
data.read_state = data.read_state || {
entries: [],
partial: false,
version: 19438
}
data.consents = data.consents || {
personalization: false
}
data.tutorial = data.tutorial || null
data.user_settings = Object.assign(data.user_settings || {}, {
afk_timeout: 600,
allow_accessibility_detection: false,
animate_emoji: true,
contact_sync_enabled: false,
convert_emoticons: true,
custom_status: null,
default_guilds_restricted: false,
detect_platform_accounts: false,
developer_mode: true,
disable_games_tab: true,
enable_tts_command: true,
explicit_content_filter: 0,
friend_source_flags: {
all: false,
mutual_friends: false,
mutual_guilds: false
},
gif_auto_play: true,
guild_folders: [],
guild_positions: [],
inline_attachment_media: true,
inline_embed_media: true,
message_display_compact: false,
native_phone_integration_enabled: false,
render_embeds: true,
render_reactions: true,
restricted_guilds: [],
show_current_game: false,
stream_notifications_enabled: false
}, data.user_settings || {})
data.user_guild_settings = data.user_guild_settings || {
entries: [],
version: 0,
partial: false
}
data.friend_suggestion_count = data.friend_suggestion_count || 0
data.presences = data.presences || []
browserWindow.webContents.userAgent = `DiscordBot (https://github.com/lightcord/lightcord, v${electron.remote.getGlobal("BuildInfo").version})`
}else{
browserWindow.webContents.userAgent = UserAgent
logger.log(`Logged in as an user. Skipping user spoofing.`)
}
}
let returnValue = _handleDispatch.call(this, ...arguments)
if(event === "READY" && DiscordJS){
try{
DiscordJS.client.emit("self.ready", data)
}catch(e){
console.error("[DiscordJS Error]", e)
}
}
return returnValue
}
dispatcher.subscribe("LOGOUT", () => {
isBot = false
})
function cancelGatewayPrototype(methodName){
if(gatewayModule.default.prototype[methodName]){
const original = gatewayModule.default.prototype[methodName]
gatewayModule.default.prototype[methodName] = function(){
if(!isBot)return original.call(this, ...arguments)
}
}else{
logger.warn(`Couldn't find ${methodName} on gateway.`)
}
}
cancelGatewayPrototype("updateGuildSubscriptions")
cancelGatewayPrototype("callConnect")
cancelGatewayPrototype("lobbyConnect")
cancelGatewayPrototype("lobbyDisconnect")
cancelGatewayPrototype("lobbyVoiceStatesUpdate")
cancelGatewayPrototype("streamCreate")
cancelGatewayPrototype("streamWatch")
cancelGatewayPrototype("streamPing")
cancelGatewayPrototype("streamDelete")
cancelGatewayPrototype("streamSetPaused")
const requestGuildMembers = gatewayModule.default.prototype.requestGuildMembers
gatewayModule.default.prototype.requestGuildMembers = function(){ // TODO: requestGuildMembers patch for bots.
/*if(!isBot)*/return requestGuildMembers.call(this, ...arguments)
console.log(arguments)
}
const hasUnreadModules = BDModules.get(e => e.default && e.default.hasUnread)
hasUnreadModules.forEach((mod) => {
const hasUnread = mod.default.hasUnread
mod.default.hasUnread = function(){
if(isBot)return false
return hasUnread.call(this, ...arguments)
}
for (const fName of ['ack']) {
console.log(fName, mod[fName])
if(!mod || !mod[fName]){
logger.warn("Couldn't find prop "+fName+" in ackmodule1")
continue
}
let original = mod[fName]
mod[fName] = function(){
if(!isBot)return original.call(this, ...arguments)
}
}
if(mod.getAckTimestamp){
let getAckTimestamp = mod.getAckTimestamp
mod.getAckTimestamp = function(){
if(!isBot)return getAckTimestamp.call(this, ...arguments)
return NaN
}
}
})
const ackModule = BDModules.get(e => e.ackCategory)[0]
if(ackModule){
for (const fName of ['ack', 'ackCategory', 'localAck', 'ackGuild']) {
console.log(fName, ackModule[fName])
if(!ackModule || !ackModule[fName]){
logger.warn("Couldn't find prop "+fName+" in ackmodule2")
continue
}
let original = ackModule[fName]
ackModule[fName] = function(){
if(!isBot)return original.call(this, ...arguments)
}
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const getTokenModule = ModuleLoader.get(e => e.default && e.default.getToken)[0]
if(getTokenModule){
const getToken = getTokenModule.default.getToken
getTokenModule.default.getToken = function(){
const token = getToken.call(this)
if(!token)return token
if(isBot)return token.startsWith("Bot ") ? token : "Bot " + token
return token
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const relationshipsModule = BDModules.get(e => e.default && e.default.fetchRelationships)[0]
if(relationshipsModule){
const fetchRelationships = relationshipsModule.default.fetchRelationships
relationshipsModule.default.fetchRelationships = function(){
if(!isBot)return fetchRelationships.call(this, ...arguments)
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.LOAD_RELATIONSHIPS_SUCCESS,
relationships: []
})
})
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const consentModule = BDModules.get(e => e.fetchConsents)[0]
if(consentModule){
const fetchConsents = consentModule.fetchConsents
consentModule.fetchConsents = function(){
if(!isBot)return fetchConsents.call(this, ...arguments)
setImmediate(()=>{
dispatcher.dispatch({
type: constants.ActionTypes.UPDATE_CONSENTS,
consents: {
personalization: false,
usage_statistics: false
}
})
})
}
const setConsents = consentModule.setConsents
consentModule.setConsents = function(){
if(!isBot)return setConsents.call(this, ...arguments)
return Promise.reject(new Error("Lightcord bot emulation cannot change this setting."))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const harvestModule = BDModules.get(e => e.getHarvestStatus)[0]
if(harvestModule){
const getHarvestStatus = harvestModule.getHarvestStatus
harvestModule.getHarvestStatus = function(){
if(!isBot)return getHarvestStatus.call(this, ...arguments)
return Promise.resolve({
requestingHarvest: false,
currentHarvestRequest: null
})
}
const requestHarvest = harvestModule.requestHarvest
harvestModule.requestHarvest = function(){
if(!isBot)return requestHarvest.call(this, ...arguments)
return Promise.reject()
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const harvestDisabledModule = BDModules.get(e => e.getSanitizedRestrictedGuilds)[0]
if(harvestDisabledModule){
const harvestDisabled = harvestDisabledModule.harvestDisabled
harvestDisabledModule.harvestDisabled = function(){
if(!isBot)return harvestDisabled.call(this, ...arguments)
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const settingModule = BDModules.get(e => e.default && e.default.updateRemoteSettings)[0]
if(settingModule){
const updateRemoteSettings = settingModule.default.updateRemoteSettings
settingModule.default.updateRemoteSettings = function(){
if(isBot)return Promise.resolve()
return updateRemoteSettings.call(this, ...arguments)
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const oauth2Module = BDModules.get(e => e.default && Object.keys(e.default).length === 2 && e.default.fetch && e.default.delete)[0]
if(oauth2Module){
const fetch = oauth2Module.default.fetch
oauth2Module.default.fetch = function(){
if(!isBot)return fetch.call(this, ...arguments)
setImmediate(()=>{
dispatcher.dispatch({
type: constants.ActionTypes.USER_AUTHORIZED_APPS_UPDATE,
apps: []
})
})
}
const deleteFunc = oauth2Module.delete
oauth2Module.delete = function(){
if(!isBot)return deleteFunc.call(this, ...arguments)
oauth2Module.fetch()
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const paymentModule = BDModules.get(e => e.fetchPaymentSources)[0]
if(paymentModule){
const fetchPaymentSources = paymentModule.fetchPaymentSources
paymentModule.fetchPaymentSources = function(){
if(!isBot)return fetchPaymentSources.call(this, ...arguments)
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.BILLING_PAYMENT_SOURCES_FETCH_START
})
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.BILLING_PAYMENT_SOURCES_FETCH_SUCCESS,
paymentSources: []
})
})
})
}
const fetchPayments = paymentModule.fetchPayments
paymentModule.fetchPayments = function(){
if(!isBot)return fetchPayments.call(this, ...arguments)
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.BILLING_PAYMENTS_FETCH_START
})
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.BILLING_PAYMENTS_FETCH_SUCCESS,
payments: []
})
})
})
}
const fetchSubscriptions = paymentModule.fetchSubscriptions
paymentModule.fetchSubscriptions = function(){
if(!isBot)return fetchSubscriptions.call(this, ...arguments)
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.BILLING_SUBSCRIPTION_FETCH_START
})
setImmediate(() => {
const subs = [
{
"id": "123456789",
"type": 1,
"created_at": "2020-06-00T00:00:00.000000",
"canceled_at": null,
"current_period_start": "2020-06-00:00:00.000000",
"current_period_end": "2100-06-00:00:00.000000",
"status": 1,
"payment_source_id": null,
"payment_gateway": null,
"payment_gateway_plan_id": "premium_year",
"plan_id": "511651860671627264",
"items": [
{
"id": "123456789",
"plan_id": "511651860671627264",
"quantity": 1
}
],
"currency": "usd"
}
]
resolve({
body: subs
})
dispatcher.dispatch({
type: constants.ActionTypes.BILLING_SUBSCRIPTION_FETCH_SUCCESS,
subscriptions: subs
})
})
})
let resolve
return new Promise((res) => (resolve = res))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const markServerReadShortcut = BDModules.get(e => e.MARK_SERVER_READ)[0]
if(markServerReadShortcut){
let action = markServerReadShortcut.MARK_SERVER_READ.action
markServerReadShortcut.MARK_SERVER_READ.action = function(){
if(isBot)return
return action.call(this, ...arguments)
}
markServerReadShortcut.default && markServerReadShortcut.default.MARK_SERVER_READ && (markServerReadShortcut.default.MARK_SERVER_READ.action = markServerReadShortcut.MARK_SERVER_READ.action)
}else{
logger.warn(new Error("Couldn't find module here"))
}
const applicationStatisticModule = BDModules.get(e => e.fetchActivityStatistics)[0]
if(applicationStatisticModule){
const fetchActivityStatistics = applicationStatisticModule.fetchActivityStatistics
applicationStatisticModule.fetchActivityStatistics = function(){
if(!isBot)return fetchActivityStatistics.call(this, ...arguments)
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.USER_ACTIVITY_STATISTICS_FETCH_SUCCESS,
statistics: []
})
})
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const subsInvoiceModule = BDModules.get(e => e.fetchSubscriptionInvoicePreview)[0]
if(subsInvoiceModule){
function adapt(data){
return {
id: data.id,
invoiceItems: data.invoice_items.map(function(e) {
return {
id: e.id,
subscriptionPlanId: e.subscription_plan_id,
subscriptionPlanPrice: e.subscription_plan_price,
amount: e.amount,
quantity: e.quantity,
discounts: e.discounts
}
}),
total: data.total,
subtotal: data.subtotal,
currency: data.currency,
tax: data.tax,
taxInclusive: data.tax_inclusive,
subscriptionPeriodStart: new Date(data.subscription_period_start),
subscriptionPeriodEnd: new Date(data.subscription_period_end)
}
}
const fetchSubscriptionInvoicePreview = subsInvoiceModule.fetchSubscriptionInvoicePreview
subsInvoiceModule.fetchSubscriptionInvoicePreview = function(){
if(!isBot)return fetchSubscriptionInvoicePreview.call(this, ...arguments)
const arg1 = arguments[0]
if(!arg1 || !arg1.subscriptionId || arg1.subscriptionId === "123456789"){
return new Promise((resolve, reject) => {
let data = adapt({
"id": "123456789",
"invoice_items": [{
"id": "123456789",
"amount": 0,
"discounts": [],
"subscription_plan_id": "511651860671627264",
"subscription_plan_price": 0,
"quantity": 1,
"proration": false
}],
"total": 100,
"subtotal": 100,
"currency": "usd",
"tax": 0,
"tax_inclusive": true,
"subscription_period_start": "2020-06-00:00:00.000000",
"subscription_period_end": "2100-06-00:00:00.000000"
})
console.log(data)
resolve(data)
})
}
return fetchSubscriptionInvoicePreview.call(this, ...arguments)
}
const useSubscriptionInvoice = subsInvoiceModule.useSubscriptionInvoice
subsInvoiceModule.useSubscriptionInvoice = function(){
if(!isBot)return useSubscriptionInvoice.call(this, ...arguments)
return useSubscriptionInvoice.call(this, Object.assign(arguments[0], {preventFetch: true}), ...Array.from(arguments).slice(1))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const subsModule = BDModules.get(e => e.fetchUserPremiumGuildSubscriptionSlots)[0]
if(subsModule){
const fetchUserPremiumGuildSubscriptionSlots = subsModule.fetchUserPremiumGuildSubscriptionSlots
subsModule.fetchUserPremiumGuildSubscriptionSlots = function(){
if(!isBot)return fetchUserPremiumGuildSubscriptionSlots.call(this, ...arguments)
setImmediate(()=>{
dispatcher.dispatch({
type: constants.ActionTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_SLOTS_FETCH_SUCCESS,
userPremiumGuildSubscriptionSlots: []
})
})
}
const fetchPremiumSubscriptionCooldown = subsModule.fetchPremiumSubscriptionCooldown
subsModule.fetchPremiumSubscriptionCooldown = function(){
if(!isBot)return fetchPremiumSubscriptionCooldown.call(this, ...arguments)
return new Promise((resolve, reject) => {
reject(new Error("Lightcord bot emulation cannot use Server Boosts"))
})
}
const fetchPremiumSubscriptions = subsModule.fetchPremiumSubscriptions
subsModule.fetchPremiumSubscriptions = function(){
if(!isBot)return fetchPremiumSubscriptions.call(this, ...arguments)
return new Promise((resolve, reject) => {
reject(new Error("Lightcord bot emulation cannot use Server Boosts"))
})
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const entitlementsModule = BDModules.get(e => e.fetchUserEntitlementsForApplication)[0]
if(entitlementsModule){
const fetchUserEntitlementsForApplication = entitlementsModule.fetchUserEntitlementsForApplication
entitlementsModule.fetchUserEntitlementsForApplication = function(){
if(!isBot)return fetchUserEntitlementsForApplication.call(this, ...arguments)
let resolve
setImmediate(()=>{
dispatcher.dispatch({
type: constants.ActionTypes.ENTITLEMENT_FETCH_APPLICATION_START,
applicationId: arguments[0]
})
setImmediate(()=>{
resolve([])
dispatcher.dispatch({
type: constants.ActionTypes.ENTITLEMENT_FETCH_APPLICATION_SUCCESS,
applicationId: arguments[0],
entitlements: []
})
})
})
return new Promise((res) => (resolve = res))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const giftModule1 = BDModules.get(e => e.fetchGiftableEntitlements)[0]
if(giftModule1){
const fetchGiftableEntitlements = giftModule1.fetchGiftableEntitlements
giftModule1.fetchGiftableEntitlements = function(){
if(!isBot)return fetchGiftableEntitlements.call(this, ...arguments)
dispatcher.dispatch({
type: constants.ActionTypes.ENTITLEMENTS_GIFTABLE_FETCH
})
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.ENTITLEMENTS_GIFTABLE_FETCH_SUCCESS,
entitlements: []
})
})
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const libraryModule = BDModules.get(e => e.fetchLibrary)[0]
if(libraryModule){
const fetchLibrary = libraryModule.fetchLibrary
libraryModule.fetchLibrary = function(){
if(!isBot)return fetchLibrary.call(this, ...arguments)
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.LIBRARY_FETCH_SUCCESS,
libraryApplications: []
})
})
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const hypesquadModule = BDModules.get(e => e.default && e.default.joinHypeSquadOnline)[0]
if(hypesquadModule){
const joinHypeSquadOnline = hypesquadModule.default.joinHypeSquadOnline
hypesquadModule.default.joinHypeSquadOnline = function(){
if(!isBot)return joinHypeSquadOnline.call(this, ...arguments)
return Promise.reject(new Error("Lightcord bot emulation cannot join hypesquad."))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const HouseSelectionModal = BDModules.get(e => e.default && e.default.displayName === "HouseSelectionModal")[0]
const RadioGroup = BDModules.get(e => e.default && e.default.displayName === "RadioGroup")[0]
if(HouseSelectionModal && RadioGroup){
const defaultFunc = HouseSelectionModal.default
HouseSelectionModal.default = function(){
let returnValue = new defaultFunc(...arguments)
let hypesquadValue = getCurrentHypesquad() || "3"
const renderHeaderCopy = returnValue.renderHeaderCopy
returnValue.renderHeaderCopy = function(){
return "Hypesquad"
}
const renderPrimaryAction = returnValue.renderPrimaryAction
returnValue.renderPrimaryAction = function(){
const renderValue = renderPrimaryAction.call(returnValue, ...arguments)
if(!returnValue.state.hasSubmittedHouse){
renderValue.props.children = "Submit"
}else{
renderValue.props.children = "Close"
}
if(!isBot){
renderValue.props.disabled = false
}else{
renderValue.props.disabled = true
}
const onClick = renderValue.props.onClick
renderValue.props.onClick = (ev) => {
if(!returnValue.state.hasSubmittedHouse){
returnValue.handleSubmitButtonClick.call(returnValue, ...arguments)
}else{
onClick.call(this, ...arguments)
}
}
return renderValue
}
const getSelectedHouseID = returnValue.getSelectedHouseID
returnValue.getSelectedHouseID = function(){
return "HOUSE_"+hypesquadValue
}
const renderContent = returnValue.renderContent
returnValue.renderContent = function(){
if(!isBot){
if(this.state.hasSubmittedHouse)return this.renderQuizResult();
let component = React.createElement(class RadioContainer extends React.PureComponent {
constructor(props){
super(props)
}
render(){
return React.createElement("div", {
style: {
margin: "0 auto",
width: "75%"
}
}, React.createElement(RadioGroup.default, {
disabled: false,
value: hypesquadValue,
options: [
{
value: "1",
name: "Bravery",
desc: "The Bravery house"
},
{
value: "2",
name: "Brillance",
desc: "The Brillance house"
},
{
value: "3",
name: "Balance",
desc: "The Balance house"
}
],
onChange: (ev) => {
hypesquadValue = ev.value
this.forceUpdate()
}
}))
}
}, {})
return component
}else{
let component = React.createElement(class BotWarning extends React.PureComponent {
constructor(props){
super(props)
}
render(){
return React.createElement("div", {
style: {
margin: "0 auto",
width: "75%"
}
}, [
React.createElement("h2", {
style: {
color: "var(--text-normal)"
}
}, "Bots cannot use Hypesquad.")
])
}
}, {})
return component
}
}
return returnValue
}
}else{
logger.warn(new Error("Couldn't find module here"), HouseSelectionModal, RadioGroup)
}
const mentionModule = BDModules.get(e => e.default && e.default.fetchRecentMentions)[0]
if(mentionModule){
const fetchRecentMentions = mentionModule.default.fetchRecentMentions
mentionModule.default.fetchRecentMentions = function(e, t, n, i, s){
if(!isBot)return fetchRecentMentions.call(this, ...arguments)
if(!n)n = null
dispatcher.dirtyDispatch({
type: constants.ActionTypes.LOAD_RECENT_MENTIONS,
guildId: n
})
setImmediate(() => {
dispatcher.dispatch({
type: constants.ActionTypes.LOAD_RECENT_MENTIONS_SUCCESS,
messages: [],
isAfter: null != e,
hasMoreAfter: false
})
})
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const templateModule = BDModules.get(e => e.default && e.default.loadTemplatesForGuild)[0]
if(templateModule){
const loadTemplatesForGuild = templateModule.default.loadTemplatesForGuild
templateModule.default.loadTemplatesForGuild = function(){
if(!isBot)return loadTemplatesForGuild.call(this, ...arguments)
return Promise.reject(new Error("Lightcord bot emulation cannot use Guild Templates"))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const searchModule = BDModules.get(e => e.default && e.default.prototype && e.default.prototype.retryLater)[0]
if(searchModule){
const fetch = searchModule.default.prototype.fetch
searchModule.default.prototype.fetch = function(e, t, n){
if(!isBot)return fetch.call(this, ...arguments)
n(new Error("Lightcord bot emulation cannot search in guild."))
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
const inviteModule = BDModules.get(e => e.default && e.default.acceptInvite)[0]
if(inviteModule){
const acceptInvite = inviteModule.default.acceptInvite
inviteModule.default.acceptInvite = function(code, location, extraOptions){
if(!isBot)return acceptInvite.call(this, ...arguments)
dispatcher.dispatch({
type: "INVITE_ACCEPT_FAILURE",
code
})
Utils.showToast("Lightcord Bot Emulation cannot join guilds.", {type: "error"})
return Promise.reject("Lightcord Bot Emulation cannot join guilds.")
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
})().catch(console.error.bind(console, `%c[Error Bot shit]`, "color:red"))
Utils.monkeyPatch(await ensureExported(e => e.default && e.default.displayName == "AuthBox"), "default", {after: (data) => {
const children = Utils.getNestedProp(data.returnValue, "props.children.props.children.props.children")
children.push(React.createElement(require("./tokenLogin").default, {}))
}})
let [
authBoxExpanded
] = [
BDModules.get(e => e.authBoxExpanded && typeof e.authBoxExpanded === "string")[0]
]
DOMTools.addStyle("tokenLoginPatch", `.${authBoxExpanded ? Utils.removeDa(authBoxExpanded.authBoxExpanded) : "authBoxExpanded-2jqaBe"} {
width: 900px;
}`)
await ensureGuildClasses()
BetterDiscord.init()
events.emit("ready")
}
function installReactDevtools(){
let reactDevToolsPath = "";
if (process.platform === "win32") reactDevToolsPath = path.resolve(process.env.LOCALAPPDATA, "Google/Chrome/User Data");
else if (process.platform === "linux") reactDevToolsPath = path.resolve(process.env.HOME, ".config/google-chrome");
else if (process.platform === "darwin") reactDevToolsPath = path.resolve(process.env.HOME, "Library/Application Support/Google/Chrome");
else reactDevToolsPath = path.resolve(process.env.HOME, ".config/chromium");
reactDevToolsPath = path.join(reactDevToolsPath, "Default", "Extensions", "fmkadmapgofadopljbjfkapdkoienihi")
if (fs.existsSync(reactDevToolsPath)) {
const versions = fs.readdirSync(reactDevToolsPath);
reactDevToolsPath = path.resolve(reactDevToolsPath, versions[versions.length - 1]);
}
if(fs.existsSync(reactDevToolsPath)){
const webContents = electron.remote.getCurrentWebContents()
const BrowserWindow = electron.remote.BrowserWindow
setImmediate(() => webContents.on("devtools-opened", devToolsListener));
if (webContents.isDevToolsOpened()) devToolsListener();
function devToolsListener(){
logger.log(`Installing React Devtools`)
BrowserWindow.removeDevToolsExtension("React Developer Tools");
const didInstall = BrowserWindow.addDevToolsExtension(reactDevToolsPath);
if (didInstall) logger.log("React DevTools", "Successfully installed react devtools.");
else logger.log("React DevTools", "Couldn't find react devtools.");
}
}else{
console.warn(new Error(`React Devtools could not be found.`))
}
}
require.extensions[".css"] = (m, filename) => {
let content = fs.readFileSync(filename, "binary")
let style = document.createElement("style")
style.id = btoa(filename)
style.innerHTML = content
document.head.appendChild(style)
m.exports = {
id: style.id,
remove(){
return style.remove()
}
}
return m.exports
}
let zlib = require("zlib")
let tmp = require("tmp")
require.extensions[".jsbr"] = (m, filename) => {
if(!zlib)zlib = require("zlib")
if(!tmp)tmp = require("tmp")
let tmpFile = tmp.fileSync()
fs.writeFileSync(tmpFile.name+".js", zlib.brotliDecompressSync(fs.readFileSync(filename)))
return require.extensions[".js"](m, tmpFile.name+".js")
}
require.extensions[".txt"] = (m, filename) => {
m.exports = fs.readFileSync(filename, "utf8")
return m.exports
}
const LightcordBDFolder = path.join(electron.remote.app.getPath("appData"), "Lightcord_BD")
const BetterDiscordConfig = window.BetterDiscordConfig = {
"branch": "lightcord",
dataPath: LightcordBDFolder+"/",
os: process.platform,
latestVersion: "0.3.4",
version: "0.3.4"
}
function ensureGuildClasses(){
return new Promise((resolve) => {
let classs = getGuildClasses()
if(classs && classs.wrapper)return resolve()
let intergay = setInterval(() => {
classs = getGuildClasses()
if(classs && classs.wrapper){
clearInterval(intergay)
resolve()
return
}
}, 200);
})
}
var ensureExported = global.ensureExported = function ensureExported(filter, maxTime = 500){
let tried = 0
return new Promise((resolve, reject) => {
let mod = ModuleLoader.get(filter)[0]
if(mod)return resolve(mod)
tried++
let interval = setInterval(() => {
if(tried > maxTime){
clearInterval(interval)
reject(new Error("Could not find the module with the given filter."))
return
}
mod = ModuleLoader.get(filter)[0]
if(mod){
clearInterval(interval)
resolve(mod)
return
}
tried++
}, 100);
})
}
let Notifications = require("./patchNotifications")
Notifications.useShim(!appSettings.get("DEFAULT_NOTIFICATIONS", true))
function getGuildClasses() {
const guildsWrapper = ModuleLoader.get(e => e.wrapper && e.unreadMentionsBar)[0];
const guilds = ModuleLoader.get(e => e.guildsError && e.selected)[0]
const pill = ModuleLoader.get(e => e.blobContainer)[0]
return Object.assign({}, guildsWrapper, guilds, pill);
}
const originalResolve = path.resolve
const originalJoin = path.join
const BetterDiscordFolder = function() {
if (process.env.injDir) return path.resolve(process.env.injDir);
switch (process.platform) {
case "win32":
return path.resolve(process.env.appdata, "BetterDiscord/");
case "darwin":
return path.resolve(process.env.HOME, "Library/Preferences/", "BetterDiscord/");
default:
return path.resolve(process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : process.env.HOME + "/.config", "BetterDiscord/");
}
}()
path.resolve = (...args) => { // Patching BetterDiscord folder by Lightcord's BetterDiscord folder
let resp = originalResolve.call(path, ...args)
if(resp.startsWith(BetterDiscordFolder))resp = resp.replace(BetterDiscordFolder, LightcordBDFolder)
return resp
}
path.join = (...args) => { // Patching BetterDiscord folder by Lightcord's BetterDiscord folder
let resp = originalJoin.call(path, ...args)
if(resp.startsWith(BetterDiscordFolder))resp = resp.replace(BetterDiscordFolder, LightcordBDFolder)
return resp
}
path.originalResolve = originalResolve
let blacklist
function isBlacklisted(id){
if(!blacklist)blacklist = require("./blacklist.txt").split(/[\n\r]+/g).map((line, index, lines) => {
let id = ""
let comment = ""
line.split("#").forEach((idOrComment, index, array) => {
idOrComment = idOrComment.trim()
if(index === 0)id = idOrComment
else if(index === 1)comment = idOrComment
})
return {
id,
comment
}
})
if(blacklist.find(e => e.id === id))return true
return false
}
const formatLogger = new Logger("RequireFormat")
function formatMinified(path){
let result = path.replace("{min}", isPackaged ? ".min": "")
return result
}
window.ohgodohfuck = function(){
let style=document.createElement("style");style.innerHTML=`html:after{content:"";position:absolute;top:0;left:0 ;width:100vw;height:100vh;background-image:url("https://media.giphy.com/media/l378vg4Pm9LGnmD6M/giphy.gif");background-size:cover;background-position:center;background-color:transparent !important;opacity:0.9;mix-blend-mode:hue;z-index:999999999999;pointer-events:none}@keyframes ohgodohfuck{from{transform:rotateZ(0deg)}to{transform:rotateZ(360deg)}}#app-mount{animation:ohgodohfuck 5s infinite alternate}`;document.body.append(style);setTimeout(()=>document.body.removeChild(style),5000);
}