mirror of https://github.com/GooseMod/GooseMod
Injector v3.0.0: Rewrite to use Parcel
parent
1e462ee71b
commit
990d0d21dd
@ -0,0 +1,2 @@
|
||||
.cache
|
||||
node_modules
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "injector",
|
||||
"version": "3.0.0",
|
||||
"description": "GooseMod injector",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "parcel build src/index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/GooseMod/Injector.git"
|
||||
},
|
||||
"keywords": [
|
||||
"goosemod",
|
||||
"discord"
|
||||
],
|
||||
"author": "GooseMod",
|
||||
"license": "GPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/GooseMod/Injector/issues"
|
||||
},
|
||||
"homepage": "https://github.com/GooseMod/Injector#readme",
|
||||
"dependencies": {
|
||||
"parcel-bundler": "^1.12.4"
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
globalThis.modules = {};
|
||||
globalThis.disabledModules = {};
|
||||
|
||||
console.log('pass 1');
|
||||
|
||||
import * as Logger from './util/logger';
|
||||
globalThis.logger = Logger;
|
||||
|
||||
import * as Hash from './util/hash';
|
||||
|
||||
globalThis.version = '3.0.0';
|
||||
|
||||
Hash.sha512('foobar').then((hash) => {
|
||||
globalThis.injectorHash = hash;
|
||||
globalThis.logger.debug('import.version.goosemod', `${globalThis.version} (${globalThis.injectorHash})`);
|
||||
});
|
||||
|
||||
console.log('pass 2');
|
||||
|
||||
if (window.DiscordNative !== undefined) globalThis.logger.debug('import.version.discord', `${DiscordNative.app.getReleaseChannel()} ${DiscordNative.app.getVersion()}`);
|
||||
|
||||
if (window.gmUntethered) {
|
||||
globalThis.untetheredVersion = window.gmUntethered.slice();
|
||||
|
||||
// delete window.gmUntethered;
|
||||
}
|
||||
|
||||
console.log('pass 3');
|
||||
|
||||
import WebpackModules from './util/discord/webpackModules';
|
||||
globalThis.webpackModules = WebpackModules;
|
||||
|
||||
import fixLocalStorage from './util/discord/fixLocalStorage';
|
||||
fixLocalStorage();
|
||||
|
||||
console.log('pass 4');
|
||||
|
||||
import showToast from './ui/toast';
|
||||
globalThis.showToast = showToast;
|
||||
|
||||
import easterEggs from './ui/easterEggs';
|
||||
globalThis.messageEasterEggs = easterEggs;
|
||||
|
||||
import confirmDialog from './ui/modals/confirm';
|
||||
globalThis.confirmDialog = confirmDialog;
|
||||
|
||||
globalThis.messageEasterEggs.interval = setInterval(globalThis.messageEasterEggs.check, 1000);
|
||||
|
||||
import { startLoadingScreen, stopLoadingScreen, updateLoadingScreen } from './ui/loading';
|
||||
Object.assign(globalThis, {
|
||||
startLoadingScreen,
|
||||
stopLoadingScreen,
|
||||
updateLoadingScreen
|
||||
});
|
||||
|
||||
console.log('pass 5');
|
||||
|
||||
import { removeModuleUI, isSettingsOpen, closeSettings, openSettings, openSettingItem, reopenSettings, injectInSettings, checkSettingsOpenInterval } from './ui/settings';
|
||||
Object.assign(globalThis, {
|
||||
removeModuleUI,
|
||||
isSettingsOpen,
|
||||
closeSettings,
|
||||
openSettings,
|
||||
openSettingItem,
|
||||
reopenSettings,
|
||||
injectInSettings,
|
||||
checkSettingsOpenInterval
|
||||
});
|
||||
|
||||
import cspBypasser from './util/discord/cspBypasser';
|
||||
globalThis.cspBypasser = cspBypasser;
|
||||
|
||||
globalThis.cspBypasser.init();
|
||||
|
||||
console.log('pass 6');
|
||||
|
||||
import { importModule, importModules, bindHandlers, getModuleFiles, importModulesFull } from './moduleManager';
|
||||
Object.assign(globalThis, {
|
||||
importModule,
|
||||
importModules,
|
||||
bindHandlers,
|
||||
getModuleFiles,
|
||||
importModulesFull
|
||||
});
|
||||
|
||||
import { saveModuleSettings, clearModuleSetting, clearSettings, loadSavedModuleSetting, loadSavedModuleSettings } from './moduleSettingsStore';
|
||||
Object.assign(globalThis, {
|
||||
saveModuleSettings,
|
||||
clearModuleSetting,
|
||||
clearSettings,
|
||||
loadSavedModuleSetting,
|
||||
loadSavedModuleSettings
|
||||
});
|
||||
|
||||
import moduleStoreAPI from './moduleStore';
|
||||
globalThis.moduleStoreAPI = moduleStoreAPI;
|
||||
|
||||
globalThis.saveInterval = setInterval(globalThis.saveModuleSettings, 3000);
|
||||
|
||||
globalThis.remove = () => {
|
||||
clearInterval(globalThis.messageEasterEggs.interval);
|
||||
clearInterval(globalThis.saveInterval);
|
||||
clearInterval(globalThis.injectInSettings);
|
||||
|
||||
globalThis.clearSettings();
|
||||
globalThis.moduleStoreAPI.jsCache.purgeCache();
|
||||
|
||||
globalThis.removed = true;
|
||||
|
||||
for (let p in globalThis.modules) {
|
||||
if (globalThis.modules.hasOwnProperty(p) && globalThis.modules[p].remove !== undefined) {
|
||||
globalThis.modules[p].remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
globalThis.startLoadingScreen();
|
||||
|
||||
globalThis.updateLoadingScreen('Getting module index from Module Store...');
|
||||
|
||||
await globalThis.moduleStoreAPI.updateModules();
|
||||
|
||||
globalThis.moduleStoreAPI.updateStoreSetting();
|
||||
|
||||
globalThis.initialImport = true;
|
||||
|
||||
let toInstallModules = Object.keys(JSON.parse(localStorage.getItem('goosemodModules')) || {});
|
||||
let toInstallIsDefault = false;
|
||||
|
||||
if (toInstallModules.length === 0) {
|
||||
toInstallIsDefault = true;
|
||||
toInstallModules = ['hardcodedColorFixer', 'draculaTheme', 'fucklytics', 'visualTweaks', 'wysiwygMessages', 'customSounds', 'devMode', 'twitchEmotes', 'noMessageDeletion'];
|
||||
}
|
||||
|
||||
toInstallModules = toInstallModules.filter((m) => globalThis.moduleStoreAPI.modules.find((x) => x.filename === m) !== undefined);
|
||||
|
||||
let themeModule = toInstallModules.find((x) => x.toLowerCase().includes('theme'));
|
||||
|
||||
if (themeModule) {
|
||||
toInstallModules.unshift(toInstallModules.splice(toInstallModules.indexOf(themeModule), 1)[0]);
|
||||
}
|
||||
|
||||
let hardcodedColorFixerModule = toInstallModules.find((x) => x === 'hardcodedColorFixer');
|
||||
|
||||
if (hardcodedColorFixerModule) {
|
||||
toInstallModules.unshift(toInstallModules.splice(toInstallModules.indexOf(hardcodedColorFixerModule), 1)[0]);
|
||||
}
|
||||
|
||||
globalThis.updateLoadingScreen(`Importing default modules from Module Store... (${toInstallIsDefault ? '(Default)' : '(Last Installed)'})`);
|
||||
|
||||
for (let m of toInstallModules) {
|
||||
globalThis.updateLoadingScreen(`${globalThis.moduleStoreAPI.modules.find((x) => x.filename === m).name} - ${toInstallModules.indexOf(m) + 1}/${toInstallModules.length}`)
|
||||
//globalThis.updateLoadingScreen(`Importing default modules from Module Store...<br><br>${globalThis.moduleStoreAPI.modules.find((x) => x.filename === m).name}<br>${toInstallModules.indexOf(m) + 1}/${toInstallModules.length}<br>${toInstallIsDefault ? '(Default)' : '(Last Installed)'}`);
|
||||
|
||||
await globalThis.moduleStoreAPI.importModule(m);
|
||||
}
|
||||
|
||||
delete globalThis.initialImport;
|
||||
|
||||
globalThis.updateLoadingScreen(`Loading saved module settings...`);
|
||||
|
||||
await globalThis.loadSavedModuleSettings();
|
||||
|
||||
globalThis.stopLoadingScreen();
|
||||
|
||||
if (globalThis.isSettingsOpen()) { // If settings are open, reopen to inject new GooseMod options
|
||||
globalThis.reopenSettings();
|
||||
} else {
|
||||
// Only open settings (when not already open) if new user
|
||||
if (!localStorage.getItem('goosemodModules')) {
|
||||
globalThis.openSettings();
|
||||
|
||||
await sleep(200);
|
||||
|
||||
globalThis.openSettingItem('Module Store');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,104 @@
|
||||
const ab2str = (buf) => { // ArrayBuffer (UTF-8) -> String
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buf));
|
||||
};
|
||||
|
||||
export const importModule = async (f) => {
|
||||
let field = f.filename.split('.').slice(0, -1).join('.'); // Get name of module via filename (taking away the file extension)
|
||||
|
||||
globalThis.logger.debug('import', `Importing module: "${field}"`);
|
||||
|
||||
let settingItem = globalThis.settings.items.find((x) => x[1] === 'Manage Modules');
|
||||
|
||||
if (globalThis.modules[field] !== undefined) {
|
||||
globalThis.logger.debug(`import.load.module.${field}`, 'Module already imported, removing then installing new version');
|
||||
|
||||
await globalThis.modules[field].remove();
|
||||
|
||||
settingItem[2].splice(settingItem[2].indexOf(settingItem[2].find((x) => x.text === `${globalThis.modules[field].name} (${globalThis.modules[field].version})`)), 1);
|
||||
}
|
||||
|
||||
if (typeof f.data === 'object') { // ArrayBuffer (UTF-8) -> String
|
||||
f.data = ab2str(f.data);
|
||||
}
|
||||
|
||||
globalThis.modules[field] = eval(f.data.replace(/\bthis\./g, 'globalThis.')); // Set globalThis.modules.<module_name> to the return value of the module (an object containing handlers)
|
||||
|
||||
globalThis.logger.debug(`import.load.module.${field}`, `Evaled module JS`);
|
||||
|
||||
globalThis.bindHandlers(globalThis.modules[field]); // Bind all handlers to module parent / returned object from module code
|
||||
|
||||
globalThis.logger.debug(`import.load.module.${field}`, `Binded handlers`);
|
||||
|
||||
await globalThis.modules[field].onImport(); // Run the module's onImport handler
|
||||
|
||||
globalThis.logger.debug(`import.load.module.${field}`, `Ran onImport()`);
|
||||
|
||||
let toggleObj = {
|
||||
type: 'text-and-danger-button',
|
||||
text: `${globalThis.modules[field].name} <span class="description-3_Ncsb">by</span> ${globalThis.modules[field].author} <span class="description-3_Ncsb">(v${globalThis.modules[field].version})</span>`,
|
||||
buttonText: 'Remove',
|
||||
subtext: globalThis.modules[field].description,
|
||||
onclick: (el) => {
|
||||
el.textContent = 'Removing...';
|
||||
|
||||
globalThis.removeModuleUI(field, 'Manage Modules');
|
||||
}
|
||||
};
|
||||
|
||||
settingItem[2].push(toggleObj);
|
||||
|
||||
globalThis.logger.debug(`import.load.module.${field}`, `Added to Modules setting page`);
|
||||
};
|
||||
|
||||
export const importModules = async (files) => {
|
||||
globalThis.logger.debug('import', 'Looping through files');
|
||||
|
||||
for (let f of files) {
|
||||
globalThis.importModule(f);
|
||||
}
|
||||
|
||||
globalThis.logger.debug('import', 'Imported all files');
|
||||
};
|
||||
|
||||
export const bindHandlers = (handlers) => {
|
||||
for (let p in handlers) {
|
||||
if (handlers.hasOwnProperty(p) && typeof handlers[p] === 'function') {
|
||||
handlers[p] = handlers[p].bind(this);
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
};
|
||||
|
||||
export const getModuleFiles = async () => { // Ask for module files (one by one due to Discord restraint) until no file is chosen
|
||||
globalThis.logger.debug('import.fileask', 'Asking for files');
|
||||
|
||||
let allFiles = [];
|
||||
|
||||
while (true) {
|
||||
let files = await DiscordNative.fileManager.openFiles(); // Ask for file (singular)
|
||||
|
||||
if (files.length === 0) { // If no file, stop asking for files
|
||||
break;
|
||||
}
|
||||
|
||||
allFiles.push(files[0]); // Add file to files array
|
||||
}
|
||||
|
||||
globalThis.logger.debug('import.fileask', 'Finished asking for files');
|
||||
|
||||
return allFiles;
|
||||
};
|
||||
|
||||
export const importModulesFull = async () => {
|
||||
if (window.DiscordNative === undefined) {
|
||||
alert('Not supported in browser');
|
||||
return [];
|
||||
}
|
||||
|
||||
let files = await globalThis.getModuleFiles();
|
||||
|
||||
await globalThis.importModules(files);
|
||||
|
||||
return files;
|
||||
};
|
@ -0,0 +1,54 @@
|
||||
export const saveModuleSettings = async () => {
|
||||
//globalThis.logger.debug('settings', 'Saving module settings...');
|
||||
|
||||
let settings = JSON.parse(localStorage.getItem('goosemodModules')) || {};
|
||||
|
||||
for (let p in globalThis.modules) {
|
||||
if (globalThis.modules.hasOwnProperty(p)) {
|
||||
settings[p] = await (globalThis.modules[p].getSettings || (async () => []))();
|
||||
}
|
||||
}
|
||||
|
||||
if (JSON.stringify(JSON.parse(localStorage.getItem('goosemodModules'))) !== JSON.stringify(settings)) {
|
||||
localStorage.setItem('goosemodModules', JSON.stringify(settings));
|
||||
|
||||
globalThis.showToast('Settings saved');
|
||||
}
|
||||
|
||||
//console.log(settings);
|
||||
};
|
||||
|
||||
export const clearModuleSetting = (moduleName) => {
|
||||
let settings = JSON.parse(localStorage.getItem('goosemodModules'));
|
||||
|
||||
delete settings[moduleName];
|
||||
|
||||
localStorage.setItem('goosemodModules', JSON.stringify(settings));
|
||||
};
|
||||
|
||||
export const clearSettings = () => {
|
||||
localStorage.removeItem('goosemodModules');
|
||||
};
|
||||
|
||||
export const loadSavedModuleSetting = async (moduleName) => {
|
||||
let settings = JSON.parse(localStorage.getItem('goosemodModules'));
|
||||
|
||||
await (globalThis.modules[moduleName].loadSettings || (async () => []))(settings[moduleName]);
|
||||
};
|
||||
|
||||
export const loadSavedModuleSettings = async () => {
|
||||
//globalThis.logger.debug('settings', 'Loading module settings...');
|
||||
|
||||
let settings = JSON.parse(localStorage.getItem('goosemodModules'));
|
||||
|
||||
if (!settings) return;
|
||||
|
||||
for (let p in globalThis.modules) {
|
||||
if (globalThis.modules.hasOwnProperty(p) && settings.hasOwnProperty(p)) {
|
||||
console.log(p, globalThis.modules[p].loadSettings, settings[p]);
|
||||
await (globalThis.modules[p].loadSettings || (async () => []))(settings[p]);
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
};
|
@ -0,0 +1,120 @@
|
||||
export default {
|
||||
modules: [],
|
||||
|
||||
apiBaseURL: 'https://goosemod-api.netlify.app',
|
||||
|
||||
jsCache: require('./jsCache'),
|
||||
|
||||
updateModules: async () => {
|
||||
globalThis.moduleStoreAPI.modules = (await globalThis.cspBypasser.json(`${globalThis.moduleStoreAPI.apiBaseURL}/modules.json`, false)).sort((a, b) => a.name.localeCompare(b.name));
|
||||
},
|
||||
|
||||
importModule: async (moduleName) => {
|
||||
const moduleInfo = globalThis.moduleStoreAPI.modules.find((x) => x.filename === moduleName);
|
||||
|
||||
const jsCode = await globalThis.moduleStoreAPI.jsCache.getJSForModule(moduleName);
|
||||
|
||||
await globalThis.importModule({
|
||||
filename: `${moduleInfo.filename}.js`,
|
||||
data: jsCode
|
||||
});
|
||||
|
||||
if (globalThis.modules[moduleName].onLoadingFinished !== undefined) {
|
||||
await globalThis.modules[moduleName].onLoadingFinished();
|
||||
}
|
||||
|
||||
let settingItem = globalThis.settings.items.find((x) => x[1] === 'Module Store');
|
||||
|
||||
let item = settingItem[2].find((x) => x.subtext === moduleInfo.description);
|
||||
|
||||
item.type = 'toggle-text-danger-button';
|
||||
item.buttonText = 'Remove';
|
||||
|
||||
if (globalThis.isSettingsOpen() && !globalThis.initialImport) globalThis.settings.createFromItems();
|
||||
},
|
||||
|
||||
moduleRemoved: async (m) => {
|
||||
let item = globalThis.settings.items.find((x) => x[1] === 'Module Store')[2].find((x) => x.subtext === m.description);
|
||||
|
||||
if (item === undefined) return;
|
||||
|
||||
item.type = 'text-and-button';
|
||||
item.buttonText = 'Import';
|
||||
},
|
||||
|
||||
updateStoreSetting: () => {
|
||||
let item = globalThis.settings.items.find((x) => x[1] === 'Module Store');
|
||||
|
||||
item[2] = item[2].slice(0, 2);
|
||||
|
||||
let sortedCategories = globalThis.moduleStoreAPI.modules.reduce((cats, o) => cats.includes(o.category) ? cats : cats.concat(o.category), []).sort((a, b) => a.localeCompare(b));
|
||||
|
||||
let arr = Object.entries(globalThis.moduleStoreAPI.modules.reduce((cats, o) => {
|
||||
if (!cats[o.category]) cats[o.category]=[];
|
||||
cats[o.category].push(o);
|
||||
return cats;
|
||||
},{})).sort((a, b) => a[0].localeCompare(b[0])).map(o => o[1]);
|
||||
|
||||
let funIndex = sortedCategories.indexOf('fun');
|
||||
|
||||
sortedCategories.push(sortedCategories.splice(funIndex, 1)[0]);
|
||||
arr.push(arr.splice(funIndex, 1)[0]);
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
item[2].push({
|
||||
type: 'header',
|
||||
text: sortedCategories[i].replace(/\-/g, ' ')
|
||||
});
|
||||
|
||||
for (let m of arr[i]) {
|
||||
item[2].push({
|
||||
type: globalThis.modules[m.filename] ? 'toggle-text-danger-button' : 'text-and-button',
|
||||
text: `${m.name} <span class="description-3_Ncsb">by</span> ${m.author} <span class="description-3_Ncsb">(v${m.version})</span>`,
|
||||
buttonText: globalThis.modules[m.filename] ? 'Remove' : 'Import',
|
||||
subtext: m.description,
|
||||
onclick: async (el) => {
|
||||
if (globalThis.modules[m.filename]) {
|
||||
el.textContent = 'Removing...';
|
||||
|
||||
globalThis.removeModuleUI(m.filename, 'Module Store');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
el.textContent = 'Importing...';
|
||||
|
||||
await globalThis.moduleStoreAPI.importModule(m.filename);
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
globalThis.openSettingItem('Module Store');
|
||||
},
|
||||
isToggled: () => globalThis.modules[m.filename] !== undefined,
|
||||
onToggle: async (checked) => {
|
||||
if (checked) {
|
||||
globalThis.modules[m.filename] = Object.assign({}, globalThis.disabledModules[m.filename]);
|
||||
delete globalThis.disabledModules[m.filename];
|
||||
|
||||
await globalThis.modules[m.filename].onImport();
|
||||
|
||||
await globalThis.modules[m.filename].onLoadingFinished();
|
||||
|
||||
globalThis.loadSavedModuleSetting(m.filename);
|
||||
} else {
|
||||
globalThis.disabledModules[m.filename] = Object.assign({}, globalThis.modules[m.filename]);
|
||||
|
||||
globalThis.modules[m.filename].remove();
|
||||
|
||||
delete globalThis.modules[m.filename];
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
globalThis.openSettingItem('Module Store');
|
||||
}
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
globalThis.openSettingItem('Module Store');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
export const getCache = () => JSON.parse(localStorage.getItem('goosemodJSCache') || '{}');
|
||||
export const purgeCache = () => localStorage.removeItem('goosemodJSCache');
|
||||
|
||||
export const updateCache = (moduleName, version, js) => {
|
||||
let cache = globalThis.moduleStoreAPI.jsCache.getCache();
|
||||
|
||||
cache[moduleName] = {version, js};
|
||||
|
||||
localStorage.setItem('goosemodJSCache', JSON.stringify(cache));
|
||||
};
|
||||
|
||||
export const getJSForModule = async (moduleName) => {
|
||||
const moduleInfo = globalThis.moduleStoreAPI.modules.find((x) => x.filename === moduleName);
|
||||
const cache = globalThis.moduleStoreAPI.jsCache.getCache();
|
||||
|
||||
if (cache[moduleName] && moduleInfo.version === cache[moduleName].version) {
|
||||
return cache[moduleName].js;
|
||||
} else {
|
||||
const js = await globalThis.cspBypasser.text(moduleInfo.codeURL, false);
|
||||
|
||||
globalThis.moduleStoreAPI.jsCache.updateCache(moduleName, moduleInfo.version, js);
|
||||
|
||||
return js;
|
||||
}
|
||||
};
|
@ -0,0 +1,49 @@
|
||||
export default {
|
||||
eggs: [
|
||||
{
|
||||
text: 'Goose Emoji',
|
||||
message: 'Did you know there is no goose emoji? The most used one as a standin is a swan (\u{1F9A2}). Very sad.'
|
||||
},
|
||||
{
|
||||
text: 'That\'s Numberwang!',
|
||||
message: 'That\'s Wangernum!'
|
||||
},
|
||||
{
|
||||
text: 'When does Atmosphere come out?',
|
||||
message: 'June 15th!'
|
||||
},
|
||||
{
|
||||
text: 'What is the meaning of life?',
|
||||
message: '42, duh.'
|
||||
},
|
||||
{
|
||||
text: 'Honk',
|
||||
message: 'Honk'
|
||||
},
|
||||
{
|
||||
text: 'GooseMod',
|
||||
message: 'You talking about me? ;)'
|
||||
}
|
||||
],
|
||||
|
||||
interval: 0,
|
||||
|
||||
check: () => {
|
||||
let el = document.getElementsByClassName('slateTextArea-1Mkdgw')[0];
|
||||
|
||||
if (!el) return;
|
||||
|
||||
for (let e of globalThis.messageEasterEggs.eggs) {
|
||||
if (el.textContent === e.text) {
|
||||
if (e.cooldown) {
|
||||
e.cooldown -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
globalThis.showToast(e.message);
|
||||
|
||||
e.cooldown = (e.cooldown || 6) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -0,0 +1,15 @@
|
||||
let loadingToast = undefined;
|
||||
|
||||
export const startLoadingScreen = () => {
|
||||
loadingToast = globalThis.showToast('Injecting GooseMod: Starting...', { timeout: 99999 });
|
||||
};
|
||||
|
||||
export const updateLoadingScreen = (tip) => {
|
||||
loadingToast.toastElem.innerHTML = `Injecting GooseMod: ${tip}`;
|
||||
};
|
||||
|
||||
export const stopLoadingScreen = () => {
|
||||
loadingToast.toastElem.innerHTML = `GooseMod has injected successfully`;
|
||||
|
||||
loadingToast.closeFn();
|
||||
};
|
@ -0,0 +1,132 @@
|
||||
export default (buttonText, title, description) => {
|
||||
return new Promise((res) => {
|
||||
//Making the div boxes to house the stuff
|
||||
let confirmELContainer = document.createElement('div');
|
||||
confirmELContainer.classList.add('layerContainer-yqaFcK');
|
||||
|
||||
let confirmELLayer = document.createElement('div');
|
||||
confirmELLayer.classList.add('layer-2KE1M9');
|
||||
|
||||
let confirmEL = document.createElement('div');
|
||||
confirmEL.classList.add("focusLock-Ns3yie");
|
||||
confirmEL.setAttribute('role', 'dialog');
|
||||
confirmEL.setAttribute('aria-label', title);
|
||||
confirmEL.setAttribute('tabindex', '-1');
|
||||
confirmEL.setAttribute('aria-model', 'true');
|
||||
|
||||
let confirmELRoot = document.createElement('div');
|
||||
confirmELRoot.classList.add("root-1gCeng", "small-3iVZYw", "fullscreenOnMobile-1bD22y");
|
||||
confirmELRoot.style.opacity = '1';
|
||||
confirmELRoot.style.transform = 'scale(1)';
|
||||
|
||||
//Header stuff
|
||||
let confirmELHeaderDiv = document.createElement('div');
|
||||
confirmELHeaderDiv.classList.add('flex-1xMQg5', 'flex-1O1GKY', 'horizontal-1ae9ci', 'horizontal-2EEEnY', 'flex-1O1GKY', 'directionRow-3v3tfG', 'justifyStart-2NDFzi', 'alignCenter-1dQNNs', 'noWrap-3jynv6', 'header-1TKi98');
|
||||
confirmELHeaderDiv.style.flex = '0 0 auto';
|
||||
|
||||
let confirmElHeaderH = document.createElement('h4');
|
||||
confirmElHeaderH.classList.add("colorStandard-2KCXvj", "size14-e6ZScH", "h4-AQvcAz", "title-3sZWYQ", "defaultColor-1_ajX0", "defaultMarginh4-2vWMG5");
|
||||
confirmElHeaderH.textContent = title;
|
||||
|
||||
//Body stuff
|
||||
let confirmELBody = document.createElement('div');
|
||||
confirmELBody.classList.add('content-1LAB8Z', 'content-mK72R6', 'thin-1ybCId', 'scrollerBase-289Jih');
|
||||
confirmELBody.setAttribute('dir', 'ltr');
|
||||
confirmELBody.style.overflow = 'hidden scroll';
|
||||
confirmELBody.style.paddingRight = '8px';
|
||||
|
||||
let confirmELBodyText = document.createElement('div')
|
||||
confirmELBodyText.classList.add('colorStandard-2KCXvj', 'size16-1P40sf')
|
||||
confirmELBodyText.textContent = description;
|
||||
|
||||
let confirmELBodyWhitespace = document.createElement('div');
|
||||
confirmELBodyWhitespace.setAttribute('aria-hidden', 'true');
|
||||
confirmELBodyWhitespace.style.position = 'absolute';
|
||||
confirmELBodyWhitespace.style.pointerEvents = 'none';
|
||||
confirmELBodyWhitespace.style.minHeight = '0px';
|
||||
confirmELBodyWhitespace.style.minWidth = '1px';
|
||||
confirmELBodyWhitespace.style.flex = '0 0 auto';
|
||||
confirmELBodyWhitespace.style.height = '20px';
|
||||
|
||||
//Button stuff
|
||||
let confirmELButtonsDiv = document.createElement('div');
|
||||
confirmELButtonsDiv.classList.add('flex-1xMQg5', 'flex-1O1GKY', 'horizontalReverse-2eTKWD', 'horizontalReverse-3tRjY7', 'flex-1O1GKY', 'directionRowReverse-m8IjIq', 'justifyStart-2NDFzi', 'alignStretch-DpGPf3', 'noWrap-3jynv6', 'footer-2gL1pp');
|
||||
|
||||
let confirmELButtonsSubmit = document.createElement('button');
|
||||
confirmELButtonsSubmit.type = 'submit';
|
||||
confirmELButtonsSubmit.classList.add('button-38aScr', 'lookFilled-1Gx00P', 'colorRed-1TFJan', 'sizeMedium-1AC_Sl', 'grow-q77ONN');
|
||||
|
||||
let confirmELButtonsSubmitDiv = document.createElement('div');
|
||||
confirmELButtonsSubmitDiv.classList.add('contents-18-Yxp');
|
||||
confirmELButtonsSubmitDiv.textContent = buttonText;
|
||||
|
||||
let confirmELButtonsCancel = document.createElement('button');
|
||||
confirmELButtonsCancel.type = 'button';
|
||||
confirmELButtonsCancel.classList.add('button-38aScr', 'lookLink-9FtZy-', 'colorPrimary-3b3xI6', 'sizeMedium-1AC_Sl', 'grow-q77ONN');
|
||||
|
||||
let confirmELButtonsCancelDiv = document.createElement('div');
|
||||
confirmELButtonsCancelDiv.classList.add('contents-18-Yxp');
|
||||
confirmELButtonsCancelDiv.textContent = 'Cancel';
|
||||
|
||||
//Misc
|
||||
let confirmELDimBackgroundDiv = document.createElement('div');
|
||||
confirmELDimBackgroundDiv.classList.add('backdropWithLayer-3_uhz4');
|
||||
confirmELDimBackgroundDiv.style.opacity = '0.85';
|
||||
confirmELDimBackgroundDiv.style.backgroundColor = 'rgb(0, 0, 0)';
|
||||
confirmELDimBackgroundDiv.style.transform = 'translateZ(0px)';
|
||||
|
||||
//Add all the elements to the document
|
||||
//Appending misc
|
||||
confirmELContainer.appendChild(confirmELDimBackgroundDiv);
|
||||
|
||||
//Appending root elements
|
||||
confirmELContainer.appendChild(confirmELLayer);
|
||||
confirmELLayer.appendChild(confirmEL);
|
||||
confirmEL.appendChild(confirmELRoot);
|
||||
|
||||
//Appending headers
|
||||
confirmELRoot.appendChild(confirmELHeaderDiv);
|
||||
confirmELHeaderDiv.appendChild(confirmElHeaderH);
|
||||
|
||||
//Appending body
|
||||
confirmELRoot.appendChild(confirmELBody);
|
||||
confirmELBody.appendChild(confirmELBodyText);
|
||||
confirmELBody.appendChild(confirmELBodyWhitespace);
|
||||
|
||||
//Appending buttons
|
||||
confirmELRoot.appendChild(confirmELButtonsDiv);
|
||||
|
||||
confirmELButtonsDiv.appendChild(confirmELButtonsSubmit);
|
||||
confirmELButtonsDiv.appendChild(confirmELButtonsCancel);
|
||||
confirmELButtonsSubmit.appendChild(confirmELButtonsSubmitDiv);
|
||||
confirmELButtonsCancel.appendChild(confirmELButtonsCancelDiv);
|
||||
|
||||
//Inserting element into document
|
||||
document.getElementById('app-mount').insertBefore(confirmELContainer, null);
|
||||
|
||||
//Making it function
|
||||
confirmELButtonsSubmit.onclick = () => {
|
||||
confirmELLayer.remove();
|
||||
confirmELDimBackgroundDiv.remove();
|
||||
|
||||
res(true);
|
||||
};
|
||||
|
||||
confirmELButtonsCancel.onclick = () => {
|
||||
confirmELLayer.remove();
|
||||
confirmELDimBackgroundDiv.remove();
|
||||
|
||||
res(false);
|
||||
};
|
||||
|
||||
confirmELDimBackgroundDiv.onclick = () => {
|
||||
confirmELLayer.remove();
|
||||
confirmELDimBackgroundDiv.remove();
|
||||
};
|
||||
|
||||
document.querySelector('div[aria-label="Close"]').onclick = () => {
|
||||
confirmELLayer.remove();
|
||||
confirmELDimBackgroundDiv.remove();
|
||||
};
|
||||
});
|
||||
}
|
@ -0,0 +1,763 @@
|
||||
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
export const removeModuleUI = (field, where) => {
|
||||
let settingItem = globalThis.settings.items.find((x) => x[1] === 'Manage Modules');
|
||||
|
||||
settingItem[2].splice(settingItem[2].indexOf(settingItem[2].find((x) => x.subtext === globalThis.modules[field].description)), 1);
|
||||
|
||||
globalThis.moduleStoreAPI.moduleRemoved(globalThis.modules[field]);
|
||||
|
||||
globalThis.modules[field].remove();
|
||||
|
||||
delete globalThis.modules[field];
|
||||
|
||||
globalThis.clearModuleSetting(field);
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
globalThis.openSettingItem(where);
|
||||
};
|
||||
|
||||
export const isSettingsOpen = () => {
|
||||
return document.querySelector('div[aria-label="USER_SETTINGS"] div[aria-label="Close"]') !== null;
|
||||
};
|
||||
|
||||
export const closeSettings = () => {
|
||||
let closeEl = document.querySelector('div[aria-label="USER_SETTINGS"] div[aria-label="Close"]');
|
||||
|
||||
if (closeEl === null) return false;
|
||||
|
||||
closeEl.click(); // Close settings via clicking the close settings button
|
||||
};
|
||||
|
||||
export const openSettings = () => {
|
||||
settingsButtonEl.click();
|
||||
};
|
||||
|
||||
export const openSettingItem = (name) => {
|
||||
try {
|
||||
[...settingsSidebarGooseModContainer.children].find((x) => x.textContent === name).click();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const reopenSettings = async () => {
|
||||
globalThis.closeSettings();
|
||||
|
||||
await sleep(1000);
|
||||
|
||||
globalThis.openSettings();
|
||||
|
||||
await sleep(200);
|
||||
|
||||
globalThis.openSettingItem('Module Store');
|
||||
};
|
||||
|
||||
// Settings UI stuff
|
||||
|
||||
let settingsButtonEl;
|
||||
|
||||
(async function() {
|
||||
settingsButtonEl = document.querySelector('button[aria-label="User Settings"]');
|
||||
|
||||
while (!settingsButtonEl) {
|
||||
globalThis.showToast('Failed to get settings button, retrying');
|
||||
settingsButtonEl = document.querySelector('button[aria-label="User Settings"]');
|
||||
|
||||
await sleep(1000);
|
||||
}
|
||||
|
||||
settingsButtonEl.addEventListener('click', injectInSettings);
|
||||
})();
|
||||
|
||||
let settingsLayerEl, settingsSidebarEl, settingsSidebarGooseModContainer, settingsMainEl, settingsClasses;
|
||||
|
||||
const settings = {
|
||||
items: [],
|
||||
|
||||
createItem: (panelName, content, clickHandler, danger = false) => {
|
||||
globalThis.settings.items.push(['item', panelName, content, clickHandler, danger]);
|
||||
},
|
||||
|
||||
createHeading: (headingName) => {
|
||||
globalThis.settings.items.push(['heading', headingName]);
|
||||
},
|
||||
|
||||
createSeparator: () => {
|
||||
globalThis.settings.items.push(['separator']);
|
||||
},
|
||||
|
||||
createFromItems: () => {
|
||||
settingsSidebarGooseModContainer.innerHTML = '';
|
||||
|
||||
for (let i of globalThis.settings.items) {
|
||||
switch (i[0]) {
|
||||
case 'item':
|
||||
globalThis.settings._createItem(i[1], i[2], i[3], i[4]);
|
||||
break;
|
||||
case 'heading':
|
||||
globalThis.settings._createHeading(i[1]);
|
||||
break;
|
||||
case 'separator':
|
||||
globalThis.settings._createSeparator();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_createItem: (panelName, content, clickHandler, danger = false) => {
|
||||
let parentEl = document.createElement('div');
|
||||
|
||||
let headerEl = document.createElement('h2');
|
||||
headerEl.textContent = `${panelName} ${content[0]}`;
|
||||
|
||||
headerEl.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'h2-2gWE-o', 'title-3sZWYQ', 'defaultColor-1_ajX0', 'defaultMarginh2-2LTaUL');
|
||||
|
||||
parentEl.appendChild(headerEl);
|
||||
|
||||
let contentEl = document.createElement('div');
|
||||
contentEl.className = 'children-rWhLdy';
|
||||
|
||||
parentEl.appendChild(contentEl);
|
||||
|
||||
let i = 0;
|
||||
for (let e of content.slice(1)) {
|
||||
let el;
|
||||
|
||||
switch (e.type) {
|
||||
case 'header':
|
||||
el = document.createElement('h2');
|
||||
|
||||
if (i !== 0) {
|
||||
el.classList.add('marginTop20-3TxNs6');
|
||||
}
|
||||
|
||||
el.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'h5-18_1nd', 'title-3sZWYQ', 'marginBottom8-AtZOdT');
|
||||
|
||||
el.textContent = e.text;
|
||||
break;
|
||||
|
||||
case 'toggle': {
|
||||
el = document.createElement('div');
|
||||
|
||||
el.classList.add('marginBottom20-32qID7');
|
||||
|
||||
let txtEl = document.createElement('span');
|
||||
txtEl.classList.add('titleDefault-a8-ZSr', 'title-31JmR4');
|
||||
|
||||
txtEl.style.float = 'left';
|
||||
|
||||
txtEl.innerHTML = e.text;
|
||||
|
||||
let checked = e.isToggled();
|
||||
|
||||
let toggleEl = document.createElement('div');
|
||||
toggleEl.className = 'control-2BBjec';
|
||||
|
||||
let offHTML = '<div class="container-3auIfb" tabindex="-1" style="opacity: 1; background-color: rgb(114, 118, 125);"><svg class="slider-TkfMQL" viewBox="0 0 28 20" preserveAspectRatio="xMinYMid meet" style="left: -3px;"><rect fill="white" x="4" y="0" height="20" width="20" rx="10"></rect><svg viewBox="0 0 20 20" fill="none"><path fill="rgba(114, 118, 125, 1)" d="M5.13231 6.72963L6.7233 5.13864L14.855 13.2704L13.264 14.8614L5.13231 6.72963Z"></path><path fill="rgba(114, 118, 125, 1)" d="M13.2704 5.13864L14.8614 6.72963L6.72963 14.8614L5.13864 13.2704L13.2704 5.13864Z"></path></svg></svg><input id="uid_328" type="checkbox" class="input-rwLH4i" tabindex="0"></div>';
|
||||
let onHTML = '<div class="container-3auIfb" tabindex="-1" style="opacity: 1; background-color: rgb(67, 181, 129);"><svg class="slider-TkfMQL" viewBox="0 0 28 20" preserveAspectRatio="xMinYMid meet" style="left: 12px;"><rect fill="white" x="4" y="0" height="20" width="20" rx="10"></rect><svg viewBox="0 0 20 20" fill="none"><path fill="rgba(67, 181, 129, 1)" d="M7.89561 14.8538L6.30462 13.2629L14.3099 5.25755L15.9009 6.84854L7.89561 14.8538Z"></path><path fill="rgba(67, 181, 129, 1)" d="M4.08643 11.0903L5.67742 9.49929L9.4485 13.2704L7.85751 14.8614L4.08643 11.0903Z"></path></svg></svg><input id="uid_328" type="checkbox" class="input-rwLH4i" tabindex="0"></div>';
|
||||
|
||||
let fn = () => {
|
||||
checked = !checked;
|
||||
|
||||
if (checked) {
|
||||
toggleEl.innerHTML = onHTML;
|
||||
} else {
|
||||
toggleEl.innerHTML = offHTML;
|
||||
}
|
||||
|
||||
e.onToggle(checked, el);
|
||||
};
|
||||
|
||||
toggleEl.onclick = fn;
|
||||
txtEl.onclick = fn;
|
||||
|
||||
el.appendChild(txtEl);
|
||||
el.appendChild(toggleEl);
|
||||
|
||||
toggleEl.innerHTML = checked ? onHTML : offHTML;
|
||||
|
||||
toggleEl.style.float = 'right';
|
||||
|
||||
if (e.subtext) {
|
||||
let subtextEl = document.createElement('div');
|
||||
|
||||
subtextEl.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'description-3_Ncsb', 'formText-3fs7AJ', 'note-1V3kyJ', 'modeDefault-3a2Ph1');
|
||||
|
||||
subtextEl.textContent = e.subtext;
|
||||
|
||||
subtextEl.style.clear = 'both';
|
||||
|
||||
el.appendChild(subtextEl);
|
||||
}
|
||||
|
||||
let dividerEl = document.createElement('div');
|
||||
|
||||
dividerEl.classList.add('divider-3573oO', 'dividerDefault-3rvLe-');
|
||||
dividerEl.style.marginTop = e.subtext ? '20px' : '45px';
|
||||
|
||||
el.appendChild(dividerEl);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'text':
|
||||
el = document.createElement('div');
|
||||
|
||||
el.classList.add('marginBottom20-32qID7');
|
||||
|
||||
let textEl = document.createElement('span');
|
||||
textEl.classList.add('titleDefault-a8-ZSr', 'title-31JmR4');
|
||||
|
||||
textEl.style.float = 'left';
|
||||
|
||||
textEl.innerHTML = e.text;
|
||||
|
||||
el.appendChild(textEl);
|
||||
|
||||
if (e.subtext) {
|
||||
let subtextEl = document.createElement('div');
|
||||
|
||||
subtextEl.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'description-3_Ncsb', 'formText-3fs7AJ', 'note-1V3kyJ', 'modeDefault-3a2Ph1');
|
||||
|
||||
subtextEl.innerHTML = e.subtext;
|
||||
|
||||
subtextEl.style.clear = 'both';
|
||||
|
||||
el.appendChild(subtextEl);
|
||||
}
|
||||
|
||||
let dividerEl_ = document.createElement('div');
|
||||
|
||||
dividerEl_.classList.add('divider-3573oO', 'dividerDefault-3rvLe-');
|
||||
dividerEl_.style.marginTop = e.subtext ? '20px' : '45px';
|
||||
|
||||
el.appendChild(dividerEl_);
|
||||
|
||||
break;
|
||||
|
||||
case 'text-and-danger-button':
|
||||
el = document.createElement('div');
|
||||
|
||||
el.classList.add('marginBottom20-32qID7');
|
||||
|
||||
let txtEl2 = document.createElement('span');
|
||||
txtEl2.classList.add('titleDefault-a8-ZSr', 'title-31JmR4');
|
||||
|
||||
txtEl2.style.float = 'left';
|
||||
|
||||
txtEl2.innerHTML = e.text;
|
||||
|
||||
let buttonEl = document.createElement('div');
|
||||
buttonEl.classList.add('button-38aScr', 'lookOutlined-3sRXeN', 'colorRed-1TFJan', 'sizeSmall-2cSMqn', 'grow-q77ONN');
|
||||
|
||||
buttonEl.onclick = () => {
|
||||
e.onclick(buttonEl);
|
||||
};
|
||||
|
||||
buttonEl.style.cursor = 'pointer';
|
||||
|
||||
buttonEl.style.float = 'right';
|
||||
|
||||
let contentsEl2 = document.createElement('div');
|
||||
|
||||
contentsEl2.classList.add('contents-18-Yxp');
|
||||
|
||||
contentsEl2.textContent = e.buttonText;
|
||||
|
||||
buttonEl.appendChild(contentsEl2);
|
||||
|
||||
el.appendChild(txtEl2);
|
||||
el.appendChild(buttonEl);
|
||||
|
||||
if (e.subtext) {
|
||||
let subtextEl = document.createElement('div');
|
||||
|
||||
subtextEl.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'description-3_Ncsb', 'formText-3fs7AJ', 'note-1V3kyJ', 'modeDefault-3a2Ph1');
|
||||
|
||||
subtextEl.textContent = e.subtext;
|
||||
|
||||
subtextEl.style.clear = 'both';
|
||||
|
||||
el.appendChild(subtextEl);
|
||||
}
|
||||
|
||||
let dividerEl2 = document.createElement('div');
|
||||
|
||||
dividerEl2.classList.add('divider-3573oO', 'dividerDefault-3rvLe-');
|
||||
dividerEl2.style.marginTop = e.subtext ? '20px' : '45px';
|
||||
|
||||
el.appendChild(dividerEl2);
|
||||
|
||||
break;
|
||||
|
||||
case 'text-and-button':
|
||||
el = document.createElement('div');
|
||||
|
||||
el.classList.add('marginBottom20-32qID7');
|
||||
|
||||
let txtEl3 = document.createElement('span');
|
||||
txtEl3.classList.add('titleDefault-a8-ZSr', 'title-31JmR4');
|
||||
|
||||
txtEl3.style.float = 'left';
|
||||
|
||||
txtEl3.innerHTML = e.text;
|
||||
|
||||
let buttonEl2 = document.createElement('div');
|
||||
buttonEl2.classList.add('button-38aScr', 'lookFilled-1Gx00P', 'colorBrand-3pXr91', 'sizeSmall-2cSMqn', 'grow-q77ONN');
|
||||
|
||||
buttonEl2.onclick = () => {
|
||||
e.onclick(buttonEl2);
|
||||
};
|
||||
|
||||
buttonEl2.style.cursor = 'pointer';
|
||||
|
||||
buttonEl2.style.float = 'right';
|
||||
|
||||
let contentsEl3 = document.createElement('div');
|
||||
|
||||
contentsEl3.classList.add('contents-18-Yxp');
|
||||
|
||||
contentsEl3.textContent = e.buttonText;
|
||||
|
||||
buttonEl2.appendChild(contentsEl3);
|
||||
|
||||
el.appendChild(txtEl3);
|
||||
el.appendChild(buttonEl2);
|
||||
|
||||
if (e.subtext) {
|
||||
let subtextEl2 = document.createElement('div');
|
||||
|
||||
subtextEl2.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'description-3_Ncsb', 'formText-3fs7AJ', 'note-1V3kyJ', 'modeDefault-3a2Ph1');
|
||||
|
||||
subtextEl2.textContent = e.subtext;
|
||||
|
||||
subtextEl2.style.clear = 'both';
|
||||
|
||||
el.appendChild(subtextEl2);
|
||||
}
|
||||
|
||||
let dividerEl3 = document.createElement('div');
|
||||
|
||||
dividerEl3.classList.add('divider-3573oO', 'dividerDefault-3rvLe-');
|
||||
dividerEl3.style.marginTop = e.subtext ? '20px' : '45px';
|
||||
|
||||
el.appendChild(dividerEl3);
|
||||
|
||||
break;
|
||||
|
||||
case 'button':
|
||||
el = document.createElement('button');
|
||||
|
||||
el.classList.add('button-38aScr', 'lookFilled-1Gx00P', 'colorBrand-3pXr91', 'sizeSmall-2cSMqn', 'grow-q77ONN');
|
||||
|
||||
let contentsEl = document.createElement('div');
|
||||
|
||||
contentsEl.classList.add('contents-18-Yxp');
|
||||
|
||||
contentsEl.textContent = e.text;
|
||||
|
||||
el.appendChild(contentsEl);
|
||||
|
||||
el.onclick = e.onclick;
|
||||
|
||||
break;
|
||||
|
||||
case 'toggle-text-button': {
|
||||
el = document.createElement('div');
|
||||
|
||||
el.classList.add('marginBottom20-32qID7');
|
||||
|
||||
let checked = e.isToggled();
|
||||
|
||||
let toggleEl = document.createElement('div');
|
||||
toggleEl.className = 'control-2BBjec';
|
||||
|
||||
let offHTML = '<div class="container-3auIfb" tabindex="-1" style="opacity: 1; background-color: rgb(114, 118, 125);"><svg class="slider-TkfMQL" viewBox="0 0 28 20" preserveAspectRatio="xMinYMid meet" style="left: -3px;"><rect fill="white" x="4" y="0" height="20" width="20" rx="10"></rect><svg viewBox="0 0 20 20" fill="none"><path fill="rgba(114, 118, 125, 1)" d="M5.13231 6.72963L6.7233 5.13864L14.855 13.2704L13.264 14.8614L5.13231 6.72963Z"></path><path fill="rgba(114, 118, 125, 1)" d="M13.2704 5.13864L14.8614 6.72963L6.72963 14.8614L5.13864 13.2704L13.2704 5.13864Z"></path></svg></svg><input id="uid_328" type="checkbox" class="input-rwLH4i" tabindex="0"></div>';
|
||||
let onHTML = '<div class="container-3auIfb" tabindex="-1" style="opacity: 1; background-color: rgb(67, 181, 129);"><svg class="slider-TkfMQL" viewBox="0 0 28 20" preserveAspectRatio="xMinYMid meet" style="left: 12px;"><rect fill="white" x="4" y="0" height="20" width="20" rx="10"></rect><svg viewBox="0 0 20 20" fill="none"><path fill="rgba(67, 181, 129, 1)" d="M7.89561 14.8538L6.30462 13.2629L14.3099 5.25755L15.9009 6.84854L7.89561 14.8538Z"></path><path fill="rgba(67, 181, 129, 1)" d="M4.08643 11.0903L5.67742 9.49929L9.4485 13.2704L7.85751 14.8614L4.08643 11.0903Z"></path></svg></svg><input id="uid_328" type="checkbox" class="input-rwLH4i" tabindex="0"></div>';
|
||||
|
||||
toggleEl.innerHTML = checked ? onHTML : offHTML;
|
||||
|
||||
let fn = () => {
|
||||
checked = !checked;
|
||||
|
||||
if (checked) {
|
||||
toggleEl.innerHTML = onHTML;
|
||||
} else {
|
||||
toggleEl.innerHTML = offHTML;
|
||||
}
|
||||
|
||||
e.onToggle(checked, el);
|
||||
};
|
||||
|
||||
toggleEl.onclick = fn;
|
||||
|
||||
toggleEl.style.float = 'left';
|
||||
toggleEl.style.marginRight = '8px';
|
||||
|
||||
el.appendChild(toggleEl);
|
||||
|
||||
let txtEl = document.createElement('span');
|
||||
|
||||
txtEl.onclick = fn;
|
||||
|
||||
txtEl.classList.add('titleDefault-a8-ZSr', 'title-31JmR4');
|
||||
|
||||
txtEl.style.float = 'left';
|
||||
|
||||
txtEl.innerHTML = e.text;
|
||||
|
||||
let buttonEl = document.createElement('div');
|
||||
buttonEl.classList.add('button-38aScr', 'lookFilled-1Gx00P', 'colorBrand-3pXr91', 'sizeSmall-2cSMqn', 'grow-q77ONN');
|
||||
|
||||
buttonEl.onclick = () => {
|
||||
e.onclick(buttonEl);
|
||||
};
|
||||
|
||||
buttonEl.style.cursor = 'pointer';
|
||||
|
||||
buttonEl.style.float = 'right';
|
||||
|
||||
let contentsEl = document.createElement('div');
|
||||
|
||||
contentsEl.classList.add('contents-18-Yxp');
|
||||
|
||||
contentsEl.textContent = e.buttonText;
|
||||
|
||||
buttonEl.appendChild(contentsEl);
|
||||
|
||||
el.appendChild(txtEl);
|
||||
el.appendChild(buttonEl);
|
||||
|
||||
if (e.subtext) {
|
||||
let subtextEl = document.createElement('div');
|
||||
|
||||
subtextEl.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'description-3_Ncsb', 'formText-3fs7AJ', 'note-1V3kyJ', 'modeDefault-3a2Ph1');
|
||||
|
||||
subtextEl.textContent = e.subtext;
|
||||
|
||||
subtextEl.style.clear = 'both';
|
||||
|
||||
el.appendChild(subtextEl);
|
||||
}
|
||||
|
||||
let dividerEl = document.createElement('div');
|
||||
|
||||
dividerEl.classList.add('divider-3573oO', 'dividerDefault-3rvLe-');
|
||||
dividerEl.style.marginTop = e.subtext ? '20px' : '45px';
|
||||
|
||||
el.appendChild(dividerEl);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'toggle-text-danger-button': {
|
||||
el = document.createElement('div');
|
||||
|
||||
el.classList.add('marginBottom20-32qID7');
|
||||
|
||||
let checked = e.isToggled();
|
||||
|
||||
let toggleEl = document.createElement('div');
|
||||
toggleEl.className = 'control-2BBjec';
|
||||
|
||||
let offHTML = '<div class="container-3auIfb" tabindex="-1" style="opacity: 1; background-color: rgb(114, 118, 125);"><svg class="slider-TkfMQL" viewBox="0 0 28 20" preserveAspectRatio="xMinYMid meet" style="left: -3px;"><rect fill="white" x="4" y="0" height="20" width="20" rx="10"></rect><svg viewBox="0 0 20 20" fill="none"><path fill="rgba(114, 118, 125, 1)" d="M5.13231 6.72963L6.7233 5.13864L14.855 13.2704L13.264 14.8614L5.13231 6.72963Z"></path><path fill="rgba(114, 118, 125, 1)" d="M13.2704 5.13864L14.8614 6.72963L6.72963 14.8614L5.13864 13.2704L13.2704 5.13864Z"></path></svg></svg><input id="uid_328" type="checkbox" class="input-rwLH4i" tabindex="0"></div>';
|
||||
let onHTML = '<div class="container-3auIfb" tabindex="-1" style="opacity: 1; background-color: rgb(67, 181, 129);"><svg class="slider-TkfMQL" viewBox="0 0 28 20" preserveAspectRatio="xMinYMid meet" style="left: 12px;"><rect fill="white" x="4" y="0" height="20" width="20" rx="10"></rect><svg viewBox="0 0 20 20" fill="none"><path fill="rgba(67, 181, 129, 1)" d="M7.89561 14.8538L6.30462 13.2629L14.3099 5.25755L15.9009 6.84854L7.89561 14.8538Z"></path><path fill="rgba(67, 181, 129, 1)" d="M4.08643 11.0903L5.67742 9.49929L9.4485 13.2704L7.85751 14.8614L4.08643 11.0903Z"></path></svg></svg><input id="uid_328" type="checkbox" class="input-rwLH4i" tabindex="0"></div>';
|
||||
|
||||
toggleEl.innerHTML = checked ? onHTML : offHTML;
|
||||
|
||||
let fn = () => {
|
||||
checked = !checked;
|
||||
|
||||
if (checked) {
|
||||
toggleEl.innerHTML = onHTML;
|
||||
} else {
|
||||
toggleEl.innerHTML = offHTML;
|
||||
}
|
||||
|
||||
e.onToggle(checked, el);
|
||||
};
|
||||
|
||||
toggleEl.onclick = fn;
|
||||
|
||||
toggleEl.style.float = 'left';
|
||||
toggleEl.style.marginRight = '8px';
|
||||
|
||||
el.appendChild(toggleEl);
|
||||
|
||||
let txtEl = document.createElement('span');
|
||||
|
||||
txtEl.onclick = fn;
|
||||
|
||||
txtEl.classList.add('titleDefault-a8-ZSr', 'title-31JmR4');
|
||||
|
||||
txtEl.style.float = 'left';
|
||||
|
||||
txtEl.innerHTML = e.text;
|
||||
|
||||
let buttonEl = document.createElement('div');
|
||||
buttonEl.classList.add('button-38aScr', 'lookOutlined-3sRXeN', 'colorRed-1TFJan', 'sizeSmall-2cSMqn', 'grow-q77ONN');
|
||||
|
||||
buttonEl.onclick = () => {
|
||||
e.onclick(buttonEl);
|
||||
};
|
||||
|
||||
buttonEl.style.cursor = 'pointer';
|
||||
|
||||
buttonEl.style.float = 'right';
|
||||
|
||||
let contentsEl = document.createElement('div');
|
||||
|
||||
contentsEl.classList.add('contents-18-Yxp');
|
||||
|
||||
contentsEl.textContent = e.buttonText;
|
||||
|
||||
buttonEl.appendChild(contentsEl);
|
||||
|
||||
el.appendChild(txtEl);
|
||||
el.appendChild(buttonEl);
|
||||
|
||||
if (e.subtext) {
|
||||
let subtextEl = document.createElement('div');
|
||||
|
||||
subtextEl.classList.add('colorStandard-2KCXvj', 'size14-e6ZScH', 'description-3_Ncsb', 'formText-3fs7AJ', 'note-1V3kyJ', 'modeDefault-3a2Ph1');
|
||||
|
||||
subtextEl.textContent = e.subtext;
|
||||
|
||||
subtextEl.style.clear = 'both';
|
||||
|
||||
el.appendChild(subtextEl);
|
||||
}
|
||||
|
||||
let dividerEl = document.createElement('div');
|
||||
|
||||
dividerEl.classList.add('divider-3573oO', 'dividerDefault-3rvLe-');
|
||||
dividerEl.style.marginTop = e.subtext ? '20px' : '45px';
|
||||
|
||||
el.appendChild(dividerEl);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
contentEl.appendChild(el);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
let el = document.createElement('div');
|
||||
|
||||
el.classList.add(settingsClasses['item']);
|
||||
el.classList.add(settingsClasses['themed']);
|
||||
|
||||
if (danger) {
|
||||
el.style.color = 'rgb(240, 71, 71)';
|
||||
|
||||
el.onmouseenter = () => {
|
||||
el.style.backgroundColor = 'rgba(240, 71, 71, 0.1)';
|
||||
};
|
||||
|
||||
el.onmouseleave = () => {
|
||||
el.style.backgroundColor = 'unset';
|
||||
};
|
||||
}
|
||||
|
||||
el.setAttribute('tabindex', '0');
|
||||
el.setAttribute('role', 'button');
|
||||
|
||||
el.innerText = panelName;
|
||||
|
||||
el.onclick = async () => {
|
||||
if (clickHandler !== undefined) {
|
||||
clickHandler();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
settingsMainEl.firstChild.innerHTML = '';
|
||||
settingsMainEl.firstChild.appendChild(parentEl);
|
||||
|
||||
for (let e of settingsSidebarEl.children) {
|
||||
e.classList.remove(settingsClasses['selected']);
|
||||
}
|
||||
|
||||
el.classList.add(settingsClasses['selected']);
|
||||
}, 10);
|
||||
};
|
||||
|
||||
settingsSidebarEl.addEventListener('click', () => {
|
||||
if (globalThis.removed === true) return;
|
||||
|
||||
el.classList.remove(settingsClasses['selected']);
|
||||
});
|
||||
|
||||
if (panelName === 'Manage Modules' && window.DiscordNative === undefined) return;
|
||||
|
||||
settingsSidebarGooseModContainer.appendChild(el);
|
||||
},
|
||||
|
||||
_createHeading: (headingName) => {
|
||||
let el = document.createElement('div');
|
||||
el.className = settingsClasses['header'];
|
||||
|
||||
el.setAttribute('tabindex', '0');
|
||||
el.setAttribute('role', 'button');
|
||||
|
||||
el.innerText = headingName;
|
||||
|
||||
settingsSidebarGooseModContainer.appendChild(el);
|
||||
},
|
||||
|
||||
_createSeparator: () => {
|
||||
let el = document.createElement('div');
|
||||
el.className = settingsClasses['separator'];
|
||||
|
||||
settingsSidebarGooseModContainer.appendChild(el);
|
||||
}
|
||||
};
|
||||
|
||||
globalThis.settings = settings;
|
||||
|
||||
let tryingToInject = false;
|
||||
|
||||
export const injectInSettings = async () => {
|
||||
if (globalThis.removed) return;
|
||||
|
||||
if (tryingToInject) return;
|
||||
|
||||
tryingToInject = true;
|
||||
|
||||
settingsLayerEl = undefined;
|
||||
|
||||
while (!settingsLayerEl) {
|
||||
settingsLayerEl = document.querySelector('div[aria-label="USER_SETTINGS"]');
|
||||
await sleep(2);
|
||||
}
|
||||
|
||||
settingsSidebarEl = settingsLayerEl.querySelector('nav > div');
|
||||
|
||||
if (settingsSidebarEl.classList.contains('goosemod-settings-injected')) return;
|
||||
|
||||
settingsSidebarEl.classList.add('goosemod-settings-injected');
|
||||
|
||||
settingsClasses = {};
|
||||
|
||||
for (let e of settingsSidebarEl.children) {
|
||||
for (let c of e.classList) {
|
||||
let name = c.split('-')[0];
|
||||
|
||||
if (settingsClasses[name] === undefined) {
|
||||
settingsClasses[name] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settingsSidebarGooseModContainer = document.createElement('div');
|
||||
settingsSidebarEl.insertBefore(settingsSidebarGooseModContainer, settingsSidebarEl.childNodes[settingsSidebarEl.childElementCount - 4]);//settingsSidebarEl.querySelector(`.${settingsClasses.item}:not(${settingsClasses.themed}) ~ ${settingsClasses.item}:not(${settingsClasses.themed})`));
|
||||
|
||||
let el = document.createElement('div');
|
||||
el.className = settingsClasses['separator'];
|
||||
|
||||
settingsSidebarEl.insertBefore(el, settingsSidebarGooseModContainer.nextSibling); //.insertBefore(settingsSidebarGooseModContainer, settingsSidebarEl.childNodes[settingsSidebarEl.childElementCount - 4]);//settingsSidebarEl.querySelector(`.${settingsClasses.item}:not(${settingsClasses.themed}) ~ ${settingsClasses.item}:not(${settingsClasses.themed})`));
|
||||
|
||||
let versionEl = document.createElement('div');
|
||||
versionEl.classList.add('colorMuted-HdFt4q', 'size12-3cLvbJ');
|
||||
|
||||
versionEl.textContent = `GooseMod ${globalThis.version} (${globalThis.injectorHash.substring(0, 7)})`;
|
||||
|
||||
settingsSidebarEl.lastChild.appendChild(versionEl);
|
||||
|
||||
let versionElUntethered = document.createElement('div');
|
||||
versionElUntethered.classList.add('colorMuted-HdFt4q', 'size12-3cLvbJ');
|
||||
|
||||
versionElUntethered.textContent = `GooseMod Untethered ${globalThis.untetheredVersion || 'N/A'}`;
|
||||
|
||||
settingsSidebarEl.lastChild.appendChild(versionElUntethered);
|
||||
|
||||
settingsMainEl = settingsLayerEl.querySelector('main');
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
|
||||
tryingToInject = false;
|
||||
};
|
||||
|
||||
export const checkSettingsOpenInterval = setInterval(async () => {
|
||||
if (tryingToInject) return;
|
||||
|
||||
let el = document.querySelector('div[aria-label="USER_SETTINGS"]');
|
||||
if (el && !el.querySelector('nav > div').classList.contains('goosemod-settings-injected')) {
|
||||
await globalThis.injectInSettings();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
globalThis.settings.createHeading('GooseMod');
|
||||
|
||||
globalThis.settings.createItem('Manage Modules', ['',
|
||||
{
|
||||
type: 'button',
|
||||
text: 'Import Local Modules',
|
||||
onclick: async () => {
|
||||
let files = await globalThis.importModulesFull();
|
||||
|
||||
for (let f of files) {
|
||||
let n = f.filename.split('.').slice(0, -1).join('.');
|
||||
|
||||
if (globalThis.modules[n].onLoadingFinished !== undefined) {
|
||||
await globalThis.modules[n].onLoadingFinished();
|
||||
}
|
||||
}
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
globalThis.openSettingItem('Manage Modules');
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
type: 'header',
|
||||
text: 'Imported Modules'
|
||||
}
|
||||
]);
|
||||
|
||||
globalThis.settings.createItem('Module Store', ['',
|
||||
{
|
||||
type: 'button',
|
||||
text: 'Update Index',
|
||||
onclick: async () => {
|
||||
await globalThis.moduleStoreAPI.updateModules();
|
||||
|
||||
await globalThis.moduleStoreAPI.updateStoreSetting();
|
||||
|
||||
globalThis.settings.createFromItems();
|
||||
|
||||
globalThis.openSettingItem('Module Store');
|
||||
},
|
||||
}
|
||||
]);
|
||||
|
||||
globalThis.settings.createSeparator();
|
||||
|
||||
globalThis.settings.createItem('Uninstall', [""], async () => {
|
||||
if (await globalThis.confirmDialog('Uninstall', 'Uninstall GooseMod', 'Are you sure you want to uninstall GooseMod? This is a quick uninstall, it may leave some code behind but there should be no remaining noticable changes.')) {
|
||||
globalThis.closeSettings();
|
||||
|
||||
globalThis.remove();
|
||||
}
|
||||
}, true);
|
||||
|
||||
if (window.DiscordNative !== undefined) {
|
||||
globalThis.settings.createItem('Local Reinstall', [''], async () => {
|
||||
if (await globalThis.confirmDialog('Reinstall', 'Reinstall GooseMod', 'Are you sure you want to reinstall GooseMod? This will uninstall GooseMod, then ask you for the inject.js file, then run it to reinstall.')) {
|
||||
globalThis.closeSettings();
|
||||
|
||||
globalThis.remove();
|
||||
|
||||
eval(ab2str((await DiscordNative.fileManager.openFiles())[0].data));
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
globalThis.settings.createSeparator();
|
||||
|
||||
globalThis.settings.createHeading('GooseMod Modules');
|
@ -0,0 +1,155 @@
|
||||
/* Toasts from BBD, slightly modified to fit CSS variables and tweaked to liking - full credit and sources:
|
||||
** CSS: https://github.com/rauenzi/BetterDiscordApp/blob/master/src/styles/index.css
|
||||
** JS: https://github.com/rauenzi/BetterDiscordApp/blob/master/src/modules/utils.js
|
||||
** Again huge thanks to Rauenzi / (B)BD for basing some ideas and code (especially related to webpack modules)
|
||||
** (Classes renamed to not interfere with (B)BD installed alongside)
|
||||
*/
|
||||
|
||||
const toastCSS = `.gm-toasts {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
top: 0;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
pointer-events: none;
|
||||
z-index: 4000;
|
||||
}
|
||||
|
||||
@keyframes gm-toast-up {
|
||||
from {
|
||||
transform: translateY(0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gm-toast {
|
||||
animation: gm-toast-up 300ms ease;
|
||||
transform: translateY(-10px);
|
||||
background: var(--background-floating);
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 0 1px rgba(32,34,37,.6), 0 2px 10px 0 rgba(0,0,0,.2);
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
user-select: text;
|
||||
font-size: 14px;
|
||||
opacity: 1;
|
||||
margin-top: 10px;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@keyframes gm-toast-down {
|
||||
to {
|
||||
transform: translateY(0px);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gm-toast.closing {
|
||||
animation: gm-toast-down 200ms ease;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
|
||||
.gm-toast.icon {
|
||||
padding-left: 30px;
|
||||
background-size: 20px 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 6px 50%;
|
||||
}
|
||||
|
||||
.gm-toast.toast-info {
|
||||
background-color: #4a90e2;
|
||||
}
|
||||
|
||||
.gm-toast.toast-info.icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPiAgICA8cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMSAxNWgtMnYtNmgydjZ6bTAtOGgtMlY3aDJ2MnoiLz48L3N2Zz4=);
|
||||
}
|
||||
|
||||
.gm-toast.toast-success {
|
||||
background-color: #43b581;
|
||||
}
|
||||
|
||||
.gm-toast.toast-success.icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPiAgICA8cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptLTIgMTVsLTUtNSAxLjQxLTEuNDFMMTAgMTQuMTdsNy41OS03LjU5TDE5IDhsLTkgOXoiLz48L3N2Zz4=);
|
||||
}
|
||||
|
||||
.gm-toast.toast-danger,
|
||||
.gm-toast.toast-error {
|
||||
background-color: #f04747;
|
||||
}
|
||||
|
||||
.gm-toast.toast-danger.icon,
|
||||
.gm-toast.toast-error.icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTEyIDJDNi40NyAyIDIgNi40NyAyIDEyczQuNDcgMTAgMTAgMTAgMTAtNC40NyAxMC0xMFMxNy41MyAyIDEyIDJ6bTUgMTMuNTlMMTUuNTkgMTcgMTIgMTMuNDEgOC40MSAxNyA3IDE1LjU5IDEwLjU5IDEyIDcgOC40MSA4LjQxIDcgMTIgMTAuNTkgMTUuNTkgNyAxNyA4LjQxIDEzLjQxIDEyIDE3IDE1LjU5eiIvPiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+PC9zdmc+);
|
||||
}
|
||||
|
||||
.gm-toast.toast-warning,
|
||||
.gm-toast.toast-warn {
|
||||
background-color: #FFA600;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.gm-toast.toast-warning.icon,
|
||||
.gm-toast.toast-warn.icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPiAgICA8cGF0aCBkPSJNMSAyMWgyMkwxMiAyIDEgMjF6bTEyLTNoLTJ2LTJoMnYyem0wLTRoLTJ2LTRoMnY0eiIvPjwvc3ZnPg==);
|
||||
}`;
|
||||
|
||||
const styleSheet = document.createElement('style'); // Add CSS as stylesheet
|
||||
styleSheet.textContent = toastCSS;
|
||||
document.head.appendChild(styleSheet);
|
||||
|
||||
export default (text, options = {}) => {
|
||||
if (!document.querySelector('.gm-toasts')) {
|
||||
const container = document.querySelector('.sidebar-2K8pFh + div') || null;
|
||||
|
||||
const memberlist = container ? container.querySelector('.membersWrap-2h-GB4') : null;
|
||||
|
||||
const form = container ? container.querySelector('form') : null;
|
||||
|
||||
const left = container ? container.getBoundingClientRect().left : 310;
|
||||
const right = memberlist ? memberlist.getBoundingClientRect().left : 0;
|
||||
const width = right ? right - container.getBoundingClientRect().left : window.innerWidth - left - 240;
|
||||
const bottom = form ? form.offsetHeight : 80;
|
||||
|
||||
const toastWrapper = document.createElement('div');
|
||||
|
||||
toastWrapper.classList.add('gm-toasts');
|
||||
|
||||
toastWrapper.style.setProperty('left', left + 'px');
|
||||
toastWrapper.style.setProperty('width', width + 'px');
|
||||
toastWrapper.style.setProperty('bottom', bottom + 'px');
|
||||
|
||||
document.querySelector('#app-mount').appendChild(toastWrapper);
|
||||
}
|
||||
|
||||
const {type = '', icon = true, timeout = 3000} = options;
|
||||
|
||||
const toastElem = document.createElement('div');
|
||||
toastElem.classList.add('gm-toast');
|
||||
|
||||
if (type) toastElem.classList.add('toast-' + type);
|
||||
if (type && icon) toastElem.classList.add('icon');
|
||||
|
||||
toastElem.textContent = text;
|
||||
|
||||
document.querySelector('.gm-toasts').appendChild(toastElem);
|
||||
|
||||
let closeFn = () => {
|
||||
toastElem.classList.add('closing');
|
||||
setTimeout(() => {
|
||||
toastElem.remove();
|
||||
if (!document.querySelectorAll('.gm-toasts .gm-toast').length) document.querySelector('.gm-toasts').remove();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
setTimeout(closeFn, timeout);
|
||||
|
||||
return { toastElem, closeFn };
|
||||
};
|
@ -0,0 +1,109 @@
|
||||
export default {
|
||||
frame: document.createElement('iframe'),
|
||||
|
||||
init: async () => {
|
||||
globalThis.cspBypasser.frame.src = 'discord:';
|
||||
document.body.appendChild(globalThis.cspBypasser.frame);
|
||||
|
||||
//await awaitIframe(globalThis.cspBypasser.frame);
|
||||
|
||||
let script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
|
||||
let code = `
|
||||
window.addEventListener('message', async (e) => {
|
||||
const {url, type, useCORSProxy} = e.data;
|
||||
|
||||
if (!url) return;
|
||||
|
||||
const proxyURL = useCORSProxy ? \`https://cors-anywhere.herokuapp.com/\${url}\` : url;
|
||||
|
||||
if (type === 'img') {
|
||||
let canvas = document.createElement('canvas');
|
||||
let ctx = canvas.getContext('2d');
|
||||
|
||||
let img = new Image();
|
||||
img.src = proxyURL;
|
||||
img.crossOrigin = 'anonymous';
|
||||
|
||||
img.onload = () => {
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
e.source.postMessage({ verify: url, data: canvas.toDataURL("image/png") });
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const req = await fetch(proxyURL, {
|
||||
cache: 'no-store'
|
||||
});
|
||||
|
||||
e.source.postMessage({ verify: url, data: await req[type]() });
|
||||
});`;
|
||||
|
||||
script.appendChild(document.createTextNode(code));
|
||||
|
||||
globalThis.cspBypasser.frame.contentDocument.head.appendChild(script);
|
||||
},
|
||||
|
||||
runCode: (code) => {
|
||||
let script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
|
||||
script.appendChild(document.createTextNode(code));
|
||||
|
||||
globalThis.cspBypasser.frame.contentDocument.head.appendChild(script);
|
||||
},
|
||||
|
||||
json: (url, useCORSProxy = true) => {
|
||||
return new Promise((res) => {
|
||||
globalThis.cspBypasser.frame.contentWindow.postMessage({url, type: 'json', useCORSProxy});
|
||||
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data.verify !== url) return;
|
||||
|
||||
res(e.data.data);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
text: (url, useCORSProxy = true) => {
|
||||
return new Promise((res) => {
|
||||
globalThis.cspBypasser.frame.contentWindow.postMessage({url, type: 'text', useCORSProxy});
|
||||
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data.verify !== url) return;
|
||||
|
||||
res(e.data.data);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
blob: (url, useCORSProxy = true) => {
|
||||
return new Promise((res) => {
|
||||
globalThis.cspBypasser.frame.contentWindow.postMessage({url, type: 'blob', useCORSProxy});
|
||||
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data.verify !== url) return;
|
||||
|
||||
res(e.data.data);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
image: (url, useCORSProxy = true) => {
|
||||
return new Promise((res) => {
|
||||
globalThis.cspBypasser.frame.contentWindow.postMessage({url, type: 'img', useCORSProxy});
|
||||
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data.verify !== url) return;
|
||||
|
||||
res(e.data.data);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
@ -0,0 +1,15 @@
|
||||
// Bypass to get Local Storage (Discord block / remove it) - Source / credit: https://stackoverflow.com/questions/52509440/discord-window-localstorage-is-undefined-how-to-get-access-to-the-localstorage
|
||||
function getLocalStoragePropertyDescriptor() {
|
||||
const iframe = document.createElement('iframe');
|
||||
document.head.append(iframe);
|
||||
|
||||
const pd = Object.getOwnPropertyDescriptor(iframe.contentWindow, 'localStorage');
|
||||
|
||||
iframe.remove();
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
export default () => {
|
||||
Object.defineProperty(window, 'localStorage', getLocalStoragePropertyDescriptor());
|
||||
};
|
@ -0,0 +1,46 @@
|
||||
const obj = { // https://github.com/rauenzi/BetterDiscordApp/blob/master/src/modules/webpackModules.js
|
||||
req: undefined,
|
||||
|
||||
init: () => {
|
||||
obj.req = window.webpackJsonp.push([[], {__extra_id__: (module, exports, req) => module.exports = req}, [["__extra_id__"]]]);
|
||||
|
||||
delete obj.req.m.__extra_id__;
|
||||
delete obj.req.c.__extra_id__;
|
||||
},
|
||||
|
||||
find: (filter) => {
|
||||
for (const i in obj.req.c) {
|
||||
if (obj.req.c.hasOwnProperty(i)) {
|
||||
const m = obj.req.c[i].exports;
|
||||
if (m && m.__esModule && m.default && filter(m.default)) return m.default;
|
||||
if (m && filter(m)) return m;
|
||||
}
|
||||
}
|
||||
|
||||
// console.warn("Cannot find loaded module in cache");
|
||||
return null;
|
||||
},
|
||||
|
||||
findAll: (filter) => {
|
||||
const modules = [];
|
||||
for (const i in obj.req.c) {
|
||||
if (obj.req.c.hasOwnProperty(i)) {
|
||||
const m = obj.req.c[i].exports;
|
||||
if (m && m.__esModule && m.default && filter(m.default)) modules.push(m.default);
|
||||
else if (m && filter(m)) modules.push(m);
|
||||
}
|
||||
}
|
||||
return modules;
|
||||
},
|
||||
|
||||
findByProps: (...propNames) => obj.find(module => propNames.every(prop => module[prop] !== undefined)),
|
||||
findByPropsAll: (...propNames) => obj.findAll(module => propNames.every(prop => module[prop] !== undefined)),
|
||||
|
||||
findByPrototypes: (...protoNames) => obj.find(module => module.prototype && protoNames.every(protoProp => module.prototype[protoProp] !== undefined)),
|
||||
|
||||
findByDisplayName: (displayName) => obj.find(module => module.displayName === displayName),
|
||||
};
|
||||
|
||||
obj.init();
|
||||
|
||||
export default obj;
|
@ -0,0 +1,7 @@
|
||||
const hash = async (str, algorithm) => {
|
||||
const buf = await crypto.subtle.digest(algorithm, new TextEncoder('utf-8').encode(str));
|
||||
return Array.prototype.map.call(new Uint8Array(buf), x => (('00' + x.toString(16)).slice(-2))).join('');
|
||||
};
|
||||
|
||||
export const sha256 = (str) => hash(str, 'SHA-256');
|
||||
export const sha512 = (str) => hash(str, 'SHA-512');
|
@ -0,0 +1,5 @@
|
||||
export const debug = (region, ...args) => {
|
||||
let parentRegion = region.split('.')[0];
|
||||
|
||||
console.log(`%cGooseMod%c %c${region}`, 'border: 1px solid white; padding: 2px; background-color: black; color: white', 'background-color: none', `border: 1px solid white; padding: 2px; background-color: ${(globalThis.modules[parentRegion] && globalThis.modules[parentRegion].logRegionColor) || 'rgb(100, 0, 0)'}; color: white`, ...(args));
|
||||
};
|
Loading…
Reference in new issue