Compare commits
6 Commits
638927b2ec
...
eb9bfa949b
Author | SHA1 | Date |
---|---|---|
フズキ | eb9bfa949b | |
Ducko | 202ce7fd73 | |
Ducko | b7d70c2b53 | |
Ducko | a6e70a41dd | |
Ducko | 61c94f40d3 | |
Ducko | 2584ce03c5 |
|
@ -1,126 +1,27 @@
|
||||||
// Also set Powercord global var stuff here since entities import is needed to use Plugin (which every PC plugin uses)
|
import * as Settings from './util/settings';
|
||||||
|
|
||||||
const sendMessage = goosemodScope.webpackModules.findByProps('sendMessage', 'receiveMessage').sendMessage;
|
|
||||||
const getChannelId = goosemod.webpackModules.findByProps('getChannelId').getChannelId;
|
|
||||||
|
|
||||||
export const powercord = {
|
|
||||||
api: {
|
|
||||||
commands: {
|
|
||||||
registerCommand: ({ command, alias, description, usage, executor }) => {
|
|
||||||
// TODO: implement alias
|
|
||||||
|
|
||||||
goosemodScope.patcher.commands.add(command, description,
|
|
||||||
async ( { args: [ { text } ] } ) => {
|
|
||||||
const out = await executor(text.split(' ')); // Run original executor func (await incase it's an async function)
|
|
||||||
|
|
||||||
if (!out.send) {
|
|
||||||
goosemodScope.patcher.internalMessage(out.result); // PC impl. sends internal message when out.send === false, so we also do the same via our previous Patcher API function
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When send is true, we send it as a message via sendMessage
|
|
||||||
|
|
||||||
sendMessage(getChannelId(), {
|
|
||||||
content: out.result,
|
|
||||||
|
|
||||||
tts: false,
|
|
||||||
invalidEmojis: [],
|
|
||||||
validNonShortcutEmojis: []
|
|
||||||
});
|
|
||||||
}, [
|
|
||||||
{ type: 3, required: false, name: 'args', description: 'Arguments for PC command' } // Argument for any string for compat. with PC's classical commands
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
unregisterCommand: (command) => {
|
|
||||||
goosemodScope.patcher.commands.remove(command);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
notices: {
|
|
||||||
sendToast: (_id, { header, content, type, buttons }) => {
|
|
||||||
// TODO: implement full toast in future instead of just small current GM toast
|
|
||||||
|
|
||||||
goosemodScope.showToast(content);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
settings: {
|
|
||||||
registerSettings: (id, { label, render, category }) => {
|
|
||||||
const { React } = goosemodScope.webpackModules.common;
|
|
||||||
|
|
||||||
const SettingsView = goosemodScope.webpackModules.findByDisplayName('SettingsView');
|
|
||||||
|
|
||||||
const FormTitle = goosemodScope.webpackModules.findByDisplayName('FormTitle');
|
|
||||||
const FormSection = goosemodScope.webpackModules.findByDisplayName('FormSection');
|
|
||||||
|
|
||||||
goosemodScope.patcher.inject(id, SettingsView.prototype, 'getPredicateSections', (_, sections) => {
|
|
||||||
if (!sections.find(c => c.section === 'changelog')) return sections;
|
|
||||||
|
|
||||||
const dividers = sections.filter(c => c.section === 'DIVIDER');
|
|
||||||
|
|
||||||
const finalLabel = typeof label === 'function' ? label() : label;
|
|
||||||
|
|
||||||
sections.splice(sections.indexOf(dividers[dividers.length - 2]) - 2, 0,
|
|
||||||
{
|
|
||||||
section: finalLabel,
|
|
||||||
label: finalLabel,
|
|
||||||
predicate: () => { },
|
|
||||||
element: () => React.createElement(FormSection, { },
|
|
||||||
React.createElement(FormTitle, { tag: 'h2' }, finalLabel),
|
|
||||||
|
|
||||||
render({
|
|
||||||
getSetting: settingStores[category].getSetting,
|
|
||||||
updateSetting: settingStores[category].updateSetting
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return sections;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
unregisterSettings: (id) => {
|
|
||||||
goosemodScope.patcher.uninject(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const settingStores = {};
|
|
||||||
|
|
||||||
class SimpleStore {
|
|
||||||
constructor() {
|
|
||||||
this.store = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
getSetting = (key, defaultValue) => {
|
|
||||||
return this.store[key] ?? defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSetting = (key, value) => {
|
|
||||||
this.store[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Plugin {
|
export class Plugin {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.stylesheets = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
loadStylesheet(path) {
|
loadStylesheet(path) {
|
||||||
const url = `https://raw.githubusercontent.com/${this.github.repo}/main/${path}`;
|
const url = `https://raw.githubusercontent.com/${this.github.repo}/HEAD/${path}`; // HEAD essentially means default branch
|
||||||
|
|
||||||
return url;
|
const el = document.createElement('style');
|
||||||
|
|
||||||
|
el.appendChild(document.createTextNode(`@import url(${url})`)); // Load the stylesheet via style element w/ CSS @import
|
||||||
|
|
||||||
|
document.head.appendChild(el);
|
||||||
|
|
||||||
|
this.stylesheets.push(el); // Push to internal array so we can remove the elements on unload
|
||||||
}
|
}
|
||||||
|
|
||||||
delayedConstructor() {
|
delayedConstructor() { // Run funcs which rely on after eval (GooseMod sets keys on this class with more info, mostly metadata)
|
||||||
if (this.delayedConstructed) return;
|
if (this.delayedConstructed) return;
|
||||||
this.delayedConstructed = true;
|
this.delayedConstructed = true;
|
||||||
|
|
||||||
settingStores[this.entityID] = new SimpleStore();
|
Settings.makeStore(this.entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
get entityID() {
|
get entityID() {
|
||||||
|
@ -128,7 +29,17 @@ export class Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
get settings() {
|
get settings() {
|
||||||
return settingStores[this.entityID];
|
const store = Settings.settingStores[this.entityID];
|
||||||
|
|
||||||
|
return { // Basic wrapper with renamed functions
|
||||||
|
get: store.getSetting,
|
||||||
|
set: store.setSetting,
|
||||||
|
delete: store.deleteSetting,
|
||||||
|
|
||||||
|
getKeys: store.getKeys,
|
||||||
|
|
||||||
|
connectStore: () => {} // Unneeded util func, but here incase it is attempted to be called
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get goosemodHandlers() {
|
get goosemodHandlers() {
|
||||||
|
@ -139,7 +50,11 @@ export class Plugin {
|
||||||
this.startPlugin.bind(this)();
|
this.startPlugin.bind(this)();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRemove: this.pluginWillUnload.bind(this)
|
onRemove: () => {
|
||||||
|
this.stylesheets.forEach((x) => x.remove()); // Remove loaded stylesheets which were added with Plugin.loadStylesheet
|
||||||
|
|
||||||
|
this.pluginWillUnload.bind(this)();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
const sendMessage = goosemodScope.webpackModules.findByProps('sendMessage', 'receiveMessage').sendMessage;
|
||||||
|
const getChannelId = goosemod.webpackModules.findByProps('getChannelId').getChannelId;
|
||||||
|
|
||||||
|
export const registerCommand = ({ command, alias, description, usage, executor }) => {
|
||||||
|
// TODO: implement alias
|
||||||
|
|
||||||
|
goosemodScope.patcher.commands.add(command, description,
|
||||||
|
async ( { args: [ { text } ] } ) => {
|
||||||
|
const out = await executor(text.split(' ')); // Run original executor func (await incase it's an async function)
|
||||||
|
|
||||||
|
if (!out.send) {
|
||||||
|
goosemodScope.patcher.internalMessage(out.result); // PC impl. sends internal message when out.send === false, so we also do the same via our previous Patcher API function
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When send is true, we send it as a message via sendMessage
|
||||||
|
|
||||||
|
sendMessage(getChannelId(), {
|
||||||
|
content: out.result,
|
||||||
|
|
||||||
|
tts: false,
|
||||||
|
invalidEmojis: [],
|
||||||
|
validNonShortcutEmojis: []
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
{ type: 3, required: false, name: 'args', description: 'Arguments for PC command' } // Argument for any string for compat. with PC's classical commands
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const unregisterCommand = (command) => {
|
||||||
|
goosemodScope.patcher.commands.remove(command);
|
||||||
|
};
|
|
@ -0,0 +1,11 @@
|
||||||
|
import * as commands from './commands.js';
|
||||||
|
import * as notices from './notices.js';
|
||||||
|
import * as settings from './settings.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
api: {
|
||||||
|
commands,
|
||||||
|
notices,
|
||||||
|
settings
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const sendToast = (_id, { header, content, type, buttons }) => {
|
||||||
|
// TODO: implement full toast in future instead of just small current GM toast
|
||||||
|
|
||||||
|
goosemodScope.showToast(content);
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
import * as Settings from '../util/settings';
|
||||||
|
|
||||||
|
export const registerSettings = (id, { label, render, category }) => {
|
||||||
|
const { React } = goosemodScope.webpackModules.common;
|
||||||
|
|
||||||
|
const SettingsView = goosemodScope.webpackModules.findByDisplayName('SettingsView');
|
||||||
|
|
||||||
|
const FormTitle = goosemodScope.webpackModules.findByDisplayName('FormTitle');
|
||||||
|
const FormSection = goosemodScope.webpackModules.findByDisplayName('FormSection');
|
||||||
|
|
||||||
|
goosemodScope.patcher.inject(id, SettingsView.prototype, 'getPredicateSections', (_, sections) => {
|
||||||
|
const logout = sections.find((c) => c.section === 'logout');
|
||||||
|
if (!logout) return sections;
|
||||||
|
|
||||||
|
const finalLabel = typeof label === 'function' ? label() : label;
|
||||||
|
|
||||||
|
sections.splice(sections.indexOf(logout) - 1, 0,
|
||||||
|
{
|
||||||
|
section: finalLabel,
|
||||||
|
label: finalLabel,
|
||||||
|
predicate: () => { },
|
||||||
|
element: () => React.createElement(FormSection, { },
|
||||||
|
React.createElement(FormTitle, { tag: 'h2' }, finalLabel),
|
||||||
|
|
||||||
|
render({
|
||||||
|
...Settings.settingStores[category]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return sections;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const unregisterSettings = (id) => {
|
||||||
|
goosemodScope.patcher.uninject(id);
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
export const settingStores = {};
|
||||||
|
|
||||||
|
export const makeStore = (key) => {
|
||||||
|
settingStores[key] = new SimpleStore();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SimpleStore {
|
||||||
|
constructor() {
|
||||||
|
this.store = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getSetting = (key, defaultValue) => {
|
||||||
|
return this.store[key] ?? defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSetting = (key, value) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return this.toggleSetting(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSetting = (key) => {
|
||||||
|
this.store[key] = !this.store[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteSetting = (key) => {
|
||||||
|
delete this.store[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
getKeys = () => Object.keys(this.store)
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
"description": "Builder for Module Store v2.",
|
"description": "Builder for Module Store v2.",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"theme": "node ./scripts/add.js theme"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -33,7 +33,9 @@
|
||||||
"powercord/injector": "./moduleWrappers/powercord/injector.js",
|
"powercord/injector": "./moduleWrappers/powercord/injector.js",
|
||||||
"powercord/webpack": "./moduleWrappers/powercord/webpack.js",
|
"powercord/webpack": "./moduleWrappers/powercord/webpack.js",
|
||||||
"powercord/util": "./moduleWrappers/powercord/util.js",
|
"powercord/util": "./moduleWrappers/powercord/util.js",
|
||||||
"powercord/components/settings": "./moduleWrappers/powercord/components/settings.js"
|
"powercord/components/settings": "./moduleWrappers/powercord/components/settings.js",
|
||||||
|
|
||||||
|
"_powercord/global": "./moduleWrappers/powercord/global/index.js"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { createInterface } from 'readline';
|
||||||
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
|
|
||||||
|
const rl = createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout
|
||||||
|
});
|
||||||
|
|
||||||
|
const [ type1, type2, repo ] = process.argv.slice(2);
|
||||||
|
|
||||||
|
console.log(type1, type2, repo);
|
||||||
|
|
||||||
|
const repeatAsk = async (prompt) => {
|
||||||
|
const answers = [];
|
||||||
|
|
||||||
|
const ask = async () => {
|
||||||
|
return await new Promise((resp) => {
|
||||||
|
rl.question(prompt, (ans) => {
|
||||||
|
resp(ans);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let ans;
|
||||||
|
|
||||||
|
while (ans !== '') {
|
||||||
|
ans = await ask();
|
||||||
|
if (ans === '') break;
|
||||||
|
|
||||||
|
answers.push(ans);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
return answers;
|
||||||
|
};
|
||||||
|
|
||||||
|
const authors = await repeatAsk(`Add Author (leave blank if no more) > `);
|
||||||
|
|
||||||
|
console.log(authors);
|
||||||
|
|
||||||
|
const images = await repeatAsk(`Add Image (leave blank if no more) > `);
|
||||||
|
|
||||||
|
console.log(images);
|
||||||
|
|
||||||
|
let js, file;
|
||||||
|
|
||||||
|
switch (type1) {
|
||||||
|
case 'theme': {
|
||||||
|
switch (type2) {
|
||||||
|
case 'pc': {
|
||||||
|
file = `src/modules/ports/themes/pcThemes.js`;
|
||||||
|
js = ` ['${repo}', '', '/powercord_manifest.json', 'pcTheme', {
|
||||||
|
authors: ${JSON.stringify(authors)},
|
||||||
|
images: ${JSON.stringify(images)}
|
||||||
|
}],`;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(js, file);
|
||||||
|
|
||||||
|
let contents = readFileSync(file, 'utf8').split('\n');
|
||||||
|
|
||||||
|
contents.splice(-1, 0, '', ...js.split('\n'));
|
||||||
|
|
||||||
|
contents = contents.join('\n');
|
||||||
|
|
||||||
|
writeFileSync(file, contents);
|
||||||
|
|
||||||
|
rl.close();
|
|
@ -1,7 +1,7 @@
|
||||||
import nova from './nova.js';
|
import nova from './nova.js';
|
||||||
|
|
||||||
import pcPlugins from './ports/plugins/pcPlugins.js';
|
import pcPlugins from './ports/plugins/pcPlugins.js';
|
||||||
import pcThemes from './ports/pcThemes.js';
|
import pcThemes from './ports/themes/pcThemes.js';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default (manifestPath, repo) => {
|
||||||
|
|
||||||
const content = readFileSync(pcManifest.main || 'index.js', 'utf8');//.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
const content = readFileSync(pcManifest.main || 'index.js', 'utf8');//.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
||||||
|
|
||||||
const jsCode = content.replace(`module.exports = class`, `export default new class`).replace(/{ *Plugin *}/, `{ Plugin, powercord }`);
|
const jsCode = `import powercord from '_powercord/global';\n` + content.replace(`module.exports = class`, `export default new class`);
|
||||||
|
|
||||||
writeFileSync(`${manifestPath}/goosemodModule.json`, JSON.stringify(manifest));
|
writeFileSync(`${manifestPath}/goosemodModule.json`, JSON.stringify(manifest));
|
||||||
writeFileSync(`${manifestPath}/../index.js`, jsCode);
|
writeFileSync(`${manifestPath}/../index.js`, jsCode);
|
||||||
|
|
Loading…
Reference in New Issue