#🧩-plugin-development

1 messages Β· Page 89 of 1

obsidian shell
#

@hushed loom rn i do this

const ReworkedAddonCard = PluginCard({
                                    plugin: Vencord.Plugins.plugins[
                                        plugin.name
                                    ],
                                    disabled: false,
                                    onRestartNeeded() {
                                        Toasts.show({
                                            id: Toasts.genId(),
                                            type: Toasts.Type.MESSAGE,
                                            message:
                                                "Restart to apply changes!",
                                        });
                                    },
                                });

how do i get reactive plugin

#

so if i enable it it actually enables

#

plugin is not actually a real plugin object

hushed loom
#

i don't have enough context

#

where is ReworkedAddonCard used

hushed loom
#

but that prob won't catch if it needs restart

#

you can prob write some shitcode to do that

obsidian shell
#

maybe i should just display: none; the toggle

hushed loom
#

how does normal settings menu do it

#

@obsidian shell why are you using PluginCard

#

use AddonCard

obsidian shell
#

oh

#

but then don't i have to reimpl everything from scratch

hushed loom
#

50 lines

#

cry

obsidian shell
#

works so good

#

wait i can replace the info buttons with github button

#

or with a delete button

#

which would be better

hushed loom
#

you already have github button with source

obsidian shell
#

what else could i possibly add while i'm at it

quick zephyr
#

taylor what are you doing here

tropic ice
obsidian shell
broken storm
#

Like, I wanna install it lol

quick zephyr
obsidian shell
#

true

obsidian shell
obsidian shell
# obsidian shell thing

actually i’ll replace the uninstall button by a 3 dot menu that’s like

Plugin Settings
β€”β€”β€”β€”
Open in File Explorer
Check Updates
Change Branch
β€”β€”β€”β€”
Uninstall
Report

obsidian shell
tropic ice
#

oh

#

never noticed it before

obsidian shell
tropic ice
#

ok for me it's from an equicord plugin
(idk how to do the --trace-deprecation, since i'm running pnpm build not node build, so i just did project search)

obsidian shell
#

pnpm build runs this node --require=./scripts/suppressExperimentalWarnings.js scripts/build/build.mjs

tropic ice
#

ah

cobalt prism
#

Did the import { Settings } from "Vencord"; declaration got changed on recent commits? Whats the new module declaration if did Thinkmee

#

nvm its changed to @api/Settings got it work now PoinkoThumbsUp

vapid oar
#

does discord have a function to turn message records back into the API structure? eg Message.activityInstance -> activity, Message.mentionRoles -> mention_roles etc

dull magnet
#

there's like message.toJSON() or smth like that

#

idk if it's what u need

dull magnet
atomic sierra
atomic sierra
#

what do i do in this situation

atomic sierra
iron epoch
#

I think css could do this as well

atomic sierra
#

:daim:

tropic ice
iron epoch
#

Ik the difference, it's more of the plugin might be possible in css unless I am missing smth

tropic ice
#

you can't change the color of

text like this with css

foggy aurora
#

i have a plugin that hooks into file uploads using raw document.addEventListener for change, drop, and paste in start()/stop(). i know this is wrong, it's completely outside react and vencord doesn't allow it

what i'm doing now

start() {
  document.addEventListener("change", onInputChange, true);
  document.addEventListener("drop", onDrop, true);
  document.addEventListener("paste", onPaste, true);
}

can anyone help me guide me on how to not use dom manipulation for this?

fair spear
#

does anybody know which element renders the slowmode text?

quick zephyr
#

So like is there any easier way to use components that aren't exported or do I just have to do obscene things to use them?

fair spear
#

okay i also need to know how to send a message that actually WORKS

cedar olive
#

but basically you call a function within your plugin to set the component to a local variable

quick zephyr
#

huh interesting

fair spear
#

is react devtools working
at all
i have the setting enabled but opening the devtools panel shows nothing of it

#

oh wait its back somehow
i dont know why it does that sometimes

tropic ice
#

I think you need to refresh discord for it to appear for some reason

quick zephyr
#

after a full restart you need to do a reload

river breach
#

hello, i am having trouble parsing the codebase because there is a lot
i would image that there is built in functionality in the vencord codebase to traverse up a dom element's internal react tree to hook into a related class instance and hook into its handler functions or whatever else functions, but i can't really figure out how i would do this in a plugin. i see ReplaceFn and its usage in PatchPreviewProps/FullPatchInputProps/PatchReplacement

    /** The replacement string or function which returns the string for the patch replacement */
    replace: string | ReplaceFn;

with patches theres find, and replacement, which has a match and replace
i cant seem to figure out what these things map to though

i looked at the dev site but it looks like a WIP so i hope asking here is not too much trouble. sorry if i overlooked something stupid also or am looking at the completely wrong area. that tends to happen from time to time

vast karma
#

Vencord doesn't usually mess around with react trees

#

Patches are on code, not data

river breach
#

OH

#

that makes so much more sense

fair spear
#

if i were to hit the internal search API for discord for one query (working on a searching plugin) would that go against anything or is there something for that (probably not)

gloomy terrace
hushed loom
dull magnet
#

they just need to run as root lol

#

Also isn't dvm broken now

quick zephyr
#

I have to sudo my injecting too cause when I moved to cachyos (arch btw) and didn't understand what I was doing I chose /opt/discord as the path lol

dull magnet
#

that's a good path

hushed loom
#

(i think)

dull magnet
#

ye

hushed loom
#

might fork dvm if it hits stable before dvm fixed

obsidian shell
dull magnet
#

I think dvm is dead tbh

#

no commits in years

hushed loom
dull magnet
#

love

#

he does

#

but nixos

#

evil

#

wip! currently implementing a nix-darwin setup and a arm64 nixos vm setup, to see the old readme, check out README_OLD.md

hushed loom
dull magnet
#

rip

hushed loom
dull magnet
#

let me check

#

ye

#

just this

hushed loom
#

copy paste bug <3

valid portal
obsidian shell
#

did you AI ✨ it

valid portal
#

nuhuh

obsidian shell
#

what is this better hub thing

valid portal
#

uhh its a github wrapper with a different UI

#

i like it and i forgor to switch the link to github.com

#

surprisingly enough when github was down, somehow this thing was still up?

obsidian shell
#

do i really need to auth for ts

valid portal
valid portal
obsidian shell
#

yea

#

ur job is done for tbh

valid portal
#

fuck πŸ’”

obsidian shell
valid portal
#

yes

obsidian shell
#

malware

valid portal
#

i'm also using the wonderful fflate

obsidian shell
quick zephyr
#

thats literally what V got on my ass about with downloadify v1

obsidian shell
#

why do you have a csp bypass 😭

#

also cant this be done in renderer

valid portal
valid portal
obsidian shell
#

okay make it a better csp bypass then

#

like don't take a arbitrary url

valid portal
#

but

#

i'm lazy

#

have we considered that

obsidian shell
obsidian shell
#

so only take the whatever part

#

and put a native prompt

proud parrotBOT
# obsidian shell https://git.nin0.dev/userplugins/userpluginInstaller/src/commit/4c7066708a6cfe49...

native.ts: Lines 94-113

const cloneDialog = await dialog.showMessageBox({
    title: "Clone userplugin",
    message: `You are about to clone a userplugin from ${source}.`,
    type: "question",
    detail: `The repository name is "${repo}" and it is owned by "${owner}".\nThe repository URL is ${link}\n\n(If you did not request this intentionally, choose Cancel)`,
    buttons: ["Cancel", "Clone repository and continue install", "Open repository in browser"]
});
switch (cloneDialog.response) {
    case 0: {
        return reject("Rejected by user");
    }
    case 1: {
        await cloneRepo(link, repo);
        break;
    }
    case 2: {
        await shell.openExternal(link);
        return reject("silentStop");
    }
}
valid portal
#

hm

valid portal
#

in my mind i was like "who's sending shit over 50 mb that's files/images"

#

you've proved me wrong apparently

quick zephyr
#

bros gonna get someone's pc killed by a zipbomb

valid portal
#

unironically i did try a zip bomb

#

it just failed

#

oh also supports images

valid portal
#

why tf would i want to do a native prompt

obsidian shell
#

any action escaping the browser sandbox should be confirmed by the user

valid portal
#

ehhh..fair?

#

but the user has to expand the zipPreview anways with a button

#

it isnt automatically done

obsidian shell
#

yeah

valid portal
#

so isnt the user confirming it themselves anyway

#

a native confirm modal would be lowk infuriating to deal with

obsidian shell
#

but i, a malicious userplugin dev, can VencordNative.pluginHelpers.ZipDownload.download("whatever")

valid portal
#

good point

obsidian shell
#

tbf it's not that bad

#

you don't preview many zips a day anyway

obsidian shell
valid portal
obsidian shell
#

if they install a malicious userplugin they'd expect it to be malicious within the browser sandbox

#

unless it has a native.ts

valid portal
#

i'll add the native prompt when they try and expand the button

obsidian shell
#

yeah

#

that's when the function should be called then right

valid portal
#

before it would auto-fetch which i now realize is not great

#

my thought process was for speed and efficiency

#

but with security in mind thats not a great idea LOL

obsidian shell
#

too

valid portal
#

yes

obsidian shell
#

good

hushed loom
lost gulch
#

Does this read the zip header?

valid portal
hushed loom
#

Can't you read it without extracting it

#

Also, how would that work on just like a really large zip file

tiny ibex
tropic ice
#

i was forced into not fetching it :(

#

whoa i'm regular

tropic ice
#

(i might've added a variable max size in it, i don't remember exactly)

valid portal
#

i havent really put something in place for zip bombs

valid portal
#

also does anyone know a better way to show errors in the textInput component than adding your own Basetext

#

I remember a vague way to do it but i forgot

#

nvm figured it out

grand haven
#

zip is a streamable format sir

#

you don't need to download more than a few kilobytes to read the metadata

#

see zip-go

#

on npm

valid portal
#

i didnt want to have to add another dependency

#

so i stuck with fflate

#

πŸ—£οΈ

grand haven
#

zip go uses browser APIs to read zips

#

it's like x30 faster

grand haven
#

thats compression stream vs pako

valid portal
#

oof, okay maybe fflate was not the right choice

#

when i get back from Jujitsu I'll for sure look into zip-go

valid portal
#

just to be 100% sure

#

this is it right?

grand haven
# grand haven

and pako itself is already x3 faster than the web version of fflate

grand haven
#

AND on top of that, it can stream the file, rather than downloading it entirely

#

which means you'll likely end up with a few thousand times faster loads

valid portal
#

so for my use case, which do you think is better

#

pako or zip-go

grand haven
#

for previews? zip-go

#

for decrompression? zip-go

valid portal
grand haven
#

for lower ram usage? zip-go

valid portal
#

because when the user clicks on it, it shows a modal with a code block of the text content

grand haven
#

read the readme sir

import read from 'zip-go/lib/reader.js'

for await (const entry of read(blob)) {
  console.log(entry)
  console.log(entry.name)
  console.log(entry.size)
  console.log(entry.type)
  console.log(entry.directory)

  const ab = await entry.arrayBuffer()
  const text = await entry.text()
  const readableStream = entry.stream()

  // returns a real web File Object, if the entry is uncompressed
  // it will just slice the zip with it's start/end position
  const file = await entry.file()
}
valid portal
#

alr well i've got to go to jujutsu or im lowk gonna be late and get my ass handed to me

grand haven
#

and with shit like url-file you can do:

import read from 'zip-go'
import { fromURL } from '@thaunknown/url-file'

for await (const entry of read(await fromURL('https://example.com/file.zip'))) {
  // from zip-go readme:
  console.log(entry)
  console.log(entry.name)
  console.log(entry.size)
  console.log(entry.type)
  console.log(entry.directory)

  const ab = await entry.arrayBuffer()
  const text = await entry.text()
  const readableStream = entry.stream()

  // returns a real web File Object, if the entry is uncompressed
  // it will just slice the zip with it's start/end position
  const file = await entry.file()
}
valid portal
#

i'll look at this when i get back

valid portal
#

think i'll stick with fflate

grand haven
fair spear
#

im making a thing

#

i vagueposted im making a search thing
i think i posted about this before anyways but whatever

azure fossil
quaint cipher
dull magnet
#

its probably not loaded

#

manually requiring it loaded it

supple rose
#

is there any way to create a seperate window from the default discord window, I want to display my muted/deafened state in there, I tried just creating a new electron window but when I try to pnpm inject it just crashes

proud parrotBOT
#

index.tsx: Lines 332-345

const RenderPopout = ErrorBoundary.wrap(({ channel, name }: { channel: Channel; name: string; }) => {
    // Copy from an unexported function of the one they use in the experiment
    // right click a channel and search withTitleBar:!0,windowKey
    return (
        <PopoutWindow
            withTitleBar
            windowKey={`DISCORD_VC_SC-${channel.id}`}
            title={name || "Vencord"}
            channelId={channel.id}
        >
            <FullChannelView providedChannel={channel} />
        </PopoutWindow>
    );
});
silk sorrel
supple rose
#

yea I'm not sure what I'm doing wrong, when I pnpm inject it keeps crashing with the following error message

#

I put the plugin in a folder inside userplugins but when I inject it just keeps crashing

#

ok nvm I'm dumb, I didn't run pnpm build before injecting

supple rose
#

I can't seem to get the window to actually open, this is my current code

import definePlugin from "@utils/types";
import { PopoutActions } from "@webpack/common";
import ErrorBoundary from "@components/ErrorBoundary";
import { Channel, Guild, User } from "@vencord/discord-types";
import { findComponentByCodeLazy } from "@webpack";
const PopoutWindow = findComponentByCodeLazy("Missing guestWindow reference");

const size = 300;

export default definePlugin({
    name: "Overlay",
    description: "Plugin for displaying an overlay for the Muted/Deafened State",
    authors: [{ name: "ienis", id: 339352508705275904n }],
    start() {
        PopoutActions.open(
            "Overlay",
            () => <RenderPopout />,
            {
                // x: position.x,
                // y: position.y,
                backgroundColor: "black",
                left: screen.availWidth - size - 1,
                top: screen.availHeight - size - 1,
                // menubar: false,
                // skipTaskbar: true,
                movable: false,
                width: size,
                height: size,
                // autoHideMenuBar: true,
                alwaysOnTop: true,
                // transparent: true,
                // fullscreen: false,
                // frame: false,
                resizable: false,
                // hasShadow: false,
            }
        );
    }
});


const RenderPopout = ErrorBoundary.wrap(() => {
    // Copy from an unexported function of the one they use in the experiment
    // right click a channel and search withTitleBar:!0,windowKey
    return (
        <PopoutWindow
            // withTitleBar
            windowKey={"Overlay"}
            title={"Overlay"}
        // channelId={channel.id}
        >
        </PopoutWindow>
    );
});
silk sorrel
silk sorrel
#

ohh the key has to start with DISCORD_ and it can't be named DISCORD_Overlay

#

insane foreshadowing ```js
findComponentByCodeLazy("Missing guestWindow reference");

supple rose
#

thanks a lot, it works now

supple rose
#

the only thing now is that it still creates the buttons for closing the window and stuff

silk sorrel
#

set frame to false and specify a titleBarStyle

#

passing an invalid value like "nah" seems to actually hide them permanently on macos lol
ig it fallbacks to "default"

#

oh null works too

supple rose
#

when I set it to hidden it still shows the discord one

dull magnet
#

it's electron docs

supple rose
#

yea setting the style to hidden doesn't seem to work

#

it just get's inserted when creating a popout

#

ok so apparently just not using the RenderPopout is the solution

#

any way to make it click through?

supple rose
#

is there a way to trigger a rerender when useStateFromStore returns something else because it doesn't for me

const userVoice: MuteState = useStateFromStores([VoiceStateStore], () => {
    const voiceState = VoiceStateStore.getVoiceStateForUser("339352508705275904");
    return {
        selfDeaf: voiceState?.selfDeaf ?? false,
        serverMute: voiceState?.mute ?? false,
        selfMute: voiceState?.selfMute ?? false,
        serverDeaf: voiceState?.deaf ?? false,
    };
});
#

also is there a way to get the userId from the current user insead of just using my id?

quick zephyr
silk sorrel
supple rose
# silk sorrel this looks correct (in fact the userVoice object is recalculated more times than...

this is my current code for reference

import { useStateFromStores, VoiceStateStore } from "@webpack/common";
import styles from "./Modify.module.css";
import svgData from "./svgData";

export type MuteState = {
    selfDeaf: boolean,
    serverMute: boolean,
    selfMute: boolean,
    serverDeaf: boolean,
};

type VoiceStateType = {
    mute: () => React.JSX.Element;
    deaf: () => React.JSX.Element;
};

export default function Modify() {
    const userVoice: MuteState = useStateFromStores([VoiceStateStore], () => {
        const voiceState = VoiceStateStore.getVoiceStateForUser("339352508705275904");
        return {
            selfDeaf: voiceState?.selfDeaf ?? false,
            serverMute: voiceState?.mute ?? false,
            selfMute: voiceState?.selfMute ?? false,
            serverDeaf: voiceState?.deaf ?? false,
        };
    });

    const icons = svgData(userVoice);

    const Mute = icons.mute;
    const Deaf = icons.deaf;

    return <div className={styles.container}>
        <div className={styles.grid}>
            <Mute />
            <Deaf />
        </div>
    </div>;
}
#

the svg's don't change when I mute and stuff

silk sorrel
#

hmm, and how are you rendering the Modify component?

supple rose
#

w8 nvm they do

#

but only when I'm in a voice channel

supple rose
#

but it only seems to trigger a rerender when I'm actually inside a voice channel

silk sorrel
#

do you have this in a repo somewhere

supple rose
#

this is something I just wanted to have for myself so not really

#

svgData is just a normal function that returns svg's as react elements

#

everything else is in there

#

it only seems to change state/rerender when I'm inside a voice channel, is there a way to change that tho so it also triggers when I'm not

quick zephyr
#

you might want to be using MediaEngineStore

supple rose
#

how do I use that?

quick zephyr
#

idk what local mute is

#

oh it's when you mute someone

#

you can pass it a user id

#

so not relevant for your thing

#

other 4 are though

supple rose
#

it says Checks if self is muted. on .isMute() tho

quick zephyr
#

?

supple rose
#

the type for it

quick zephyr
#

isnt that the goal

supple rose
#

yes

quick zephyr
#

then whats the issue

supple rose
#

nothing, just said that bc you said not relevant for me

quick zephyr
#

localmute isnt relevant

supple rose
#

only thing is how do I keep track of state bc it's a function call, I'd have to just rerender every set amount of time

quick zephyr
#
export default function Modify() {
    useStateFromStores([MediaEngineStore]);

    const userVoice = { selfDeaf: MediaEngineStore.isSelfDeaf(), ... }
    const icons = svgData(userVoice);

    const Mute = icons.mute;
    const Deaf = icons.deaf;

    return <div className={styles.container}>
        <div className={styles.grid}>
            <Mute />
            <Deaf />
        </div>
    </div>;
}

maybe im tweakin but this I think?

#

idk if that would update too often though idk how touchy the media engine store is

#

could just use a normal useState and update it via MediaEngineStore.addChangeListener and filter for your target changes maybe idk

silk sorrel
#

useStateFromStores calls add(React)ChangeListener internally

quick zephyr
#

yeah but does it filter for the specific changes you're looking for?

#

or everything in the store

#

MediaEngineStore is pretty big

#

while in vc it might go wild tbh

#

ok added a log through addChangeListener and it dont spam at all really

#

so probably fine to just sub to entire store

silk sorrel
# quick zephyr or everything in the store

Well, everything. Flux doesn't have a way to subscribe to a part of a store (except for a few libDiscore stores, I think)
but you could just do this ig ```js
useStateFromStores([MediaEngineStore], () => {
return { selfDeaf: MediaEngineStore.isSelfDeaf(), ... };
}, [], lodash.isEqual);

if you specify the deps array (this is similar to useEffect actually), it will recompute the value only if the store actually changes, not when the component rerenders due to other props/state changes
if you specify the equality operator, it will return the same object if it's structurally equal to the previous one, reducing other rerenders when this object is used

that's as far as my useStateFromStores optimization tips go lol
silk sorrel
#

lmao

supple rose
#

MediaEngineStore.isMute() returns true if either I'm server muted or self muted

quick zephyr
#

const serverMuted = MediaEngineStore.isMute() && !MediaEngineStore.isSelfMute()

#

well I guess not huh

supple rose
#

MediaEngineStore.isMute() doesn't update when I get server muted and leave a channel tho

#

I think I'll just use both MediaEngineStore for self mute and VoiceStateStore for server mute because that should work

quick zephyr
#

well yeah cause you're still server muted

#

why would it change just cause you left

supple rose
#

because I'm technically not muted anymore

quick zephyr
#

yes you are

#

join back

#

still muted

#

it's a persistent server side value

supple rose
#

got it to work with this now

const userVoice: MuteState = useStateFromStores([MediaEngineStore], () => {
    const voiceState = VoiceStateStore.getVoiceStateForUser(UserStore.getCurrentUser().id);
    return {
        selfMute: MediaEngineStore.isSelfMute(),
        serverMute: voiceState?.mute ?? false,
        selfDeaf: MediaEngineStore.isSelfDeaf(),
        serverDeaf: voiceState?.deaf ?? false,
    };
});
silk sorrel
#

don't forget to add VoiceStateStore to the stores array

#

UserStore could also technically change when switching users, but that's overkill

supple rose
#

only thing now is how do I make PopoutActions.open() be click through

#

there doesn't seem to be an option for it BrowserWindowFeatures

silk sorrel
#

hmm, idk if vencord has an api for that, the electron docs mention setIgnoreMouseEvents but you can only call that in native

supple rose
#

I think I'm doing something wrong, when I add a native.ts file and start discord it crashes

#

even when I just console.log("test") in it

#

nvm now it works for some reason

#

why can't I use readFileSync/writeFileSync?

#

nvm I just need the file to exist

#

got it to work now, thanks a lot for all your help

supple rose
#

only thing now is how do I remove the background because it's a popout window without removing the actual background from discord

#

I set it to transparent and stuff already

supple rose
#

I tried this but it doesn't seem to work

window.webContents.insertCSS('html, body, div#app-mount {background: transparent;}');
#

even setting it through just css in the plugin it doesn't work

#

does anyone know what the actual background css definition is

silk sorrel
#

did you enable window transparency in vencord?

supple rose
# silk sorrel did you enable window transparency in vencord?

yea

const values = {
    width: size,
    defaultWidth: size,
    height: size,
    defaultHeight: size,

    directories: false,
    location: false,
    titleBarStyle: "hidden",
    toolbar: false,
    menubar: false,
    skipTaskbar: false,
    transparent: true,
    frame: false,
    hasShadow: false,

    alwaysOnTop: false,
    defaultAlwaysOnTop: false,

    resizable: true,
    movable: false,
}
supple rose
#

but if you set a background in css it still shows it and discord automatically set's one to the popout window so I have to remove it from it

silk sorrel
supple rose
#

do I need to make a custom theme for this now or how exactly do I set the background

silk sorrel
#

I think it should just work on its own, if you set the custom window's html+body background color to transparent, but I could be wrong

hushed loom
supple rose
silk sorrel
#

there are actually useStateFromStores wrappers with a custom comparator, but vencord doesn't use those anywhere

hushed loom
silk sorrel
#

lodash.isEqual my beloved

hushed loom
supple rose
#

yea

supple rose
#

ok I got it to work, I just set the backgroundColor in the open call to #00000000

#

don't even need the transparency setting in vencord

#

put it in the bottom right

dull magnet
#

wouldnt tray options have been sufficient

silk sorrel
#

did you get the click-through working btw?

supple rose
supple rose
supple rose
#

also for some reason in some games like balatro it still doesn't display always on top even tho I set it to and also did

window.setAlwaysOnTop(true, "screen-saver");
window.setVisibleOnAllWorkspaces(true, {
    visibleOnFullScreen: true
});
window.moveTop();
#

not sure why

#

I also made it toggleable by setting the opacity to 0 and 1 when I press F17 (FN+F5 on my keyboard) and it also moves it to top and when I do that in the game it still doesn't display it above it

silk sorrel
supple rose
#

only the legacy one or whatever it's called

#

but I'm in borderless so in theory it should still show the overlay above

#

I think balatro's borderless implementation is just wierd

static jewel
#

Does anyone know in which cases discord set your device as "VR" i never saw it enabled automatically

supple rose
normal wagon
#

id assume it's being on the meta quest

#

not sure whether discord is on the vision pro Shrug

hushed loom
static jewel
#

Β―_(ツ)_/Β―

normal wagon
static jewel
normal wagon
blissful spade
#

I’m currently researching Discord’s internal localization/i18n system for a Vencord plugin.

Right now I’m trying to find the proper source for the base message catalog instead of scraping runtime strings from webpack modules. I managed to extract a large amount of strings, but most are noisy/runtime values.

Does Discord expose a central locale/messages module internally, or are translations split across multiple dynamically loaded chunks?

blissful spade
blissful spade
# quick zephyr this?

Want to extract the app’s internal texts. For example, extracting en-US texts and converting them into another language.

devout skiff
#

there might be more than one I guess

sharp crane
#

does RestAPI not exist anymore?

vast karma
#

Nope, new corporate policy, no more resting. You need to work 24/7.

sharp crane
#

:c ykwim

sharp crane
devout skiff
#

So a lot of people are adopting AI agents like openclaw and hermes and using them through discord (sometimes to our detriment lol). These AI's often dump markdown text, and because of discord's incomplete implementation not all of it renders properly. I made a plugin to address this called BetterMarkdown. It extends discords markdown parser to include tables, task lists, horizontal rulers and eventually whatever else is missing that would make sense to implement. I just had some questions:

  1. I read that vencord is no longer accepting submissions for plugins. even if thats the case could I submit a PR (even as draft) to at least get the AI feedback and improve the plugin? With maybe the potential of it getting merged? I dont want to contribute to any spam

  2. is there any guidance or wisdom for ensuring this plays well with the stock plugins? This is wrapping discord's own parser and already works well with message logger but maybe there are other considerations. I had a poke around the wiki and couldn't find anything. I just tried to follow the pattern of the stock plugins

devout skiff
# dull magnet don't pr ai generated code

I used AI to help me, but it's all human reviewed (I dev professionally). The total codebase is small enough that I think another dev could review it in a reasonable amount of time also. if thats still not acceptable though I understand.

dull magnet
#

no

devout skiff
#

even if I promised in good faith that I reviewed each line manually? its not like I had it generate 100% of code, but it gave me snippets and things and helped me read through existing plugins. I couldn't find any centralized docs to reference. even if no PR, if I shared it would you provide some quick feedback?

#

I guess anyone could If I shared it. I see now there is a section for 3rd party plugins?

devout skiff
hushed loom
devout skiff
#

awesome thank you. all of this is exactly what I was looking for! I've been wanting to fix discords lazy markdown for so long 😭 . Still kinda nuts to me you can just do that now with vencord. I wonder if the equivalent of this mod exists for ios...

broken storm
#

Vencord doesn’t exist for iOS

#

-# what’s the command again

#

-# welp whatever pretend there’s an auto response or smth

timid finch
#

vesktop iphone

#

Is it possible to get vencord Or vesktop in iPhone ios??

dim jay
#

wait actually

#

there might

devout skiff
#

I see. Kettu might be the way to go then. I wonder if a preinjected ipa can be sideloaded as I think you need a jailbreak to install tweaks

dim jay
broken storm
#

Is there a template for PRing plugins (or anything) to Vencord? I've looked but I can't find one, or just don't know where to look lol

obsidian shell
#

else your plugin dir should be src/yourPlugin/

broken storm
obsidian shell
#

no there isn't a template

#

i guess just describe your change in a short sentence (do not use AI for the pr description)

broken storm
#

alr πŸ‘ thx

mint widget
#

hi, trying to find if there is a documentation for vencord docs for what is possible with plugins, looking into creating a plugin for bookmarking messages

timid finch
#

this exists in equicord

mint widget
timid finch
#

it's a fork, but my point is u can see it's code

#

as a reference for that

mint widget
#

ah like that, thank you

mint widget
#

nevermind found it

timid finch
#

lemme look

#

oh

#

what was it btw

mint widget
#

i believe this one is the one handling bookmarks since bookmarks are mentioned here

timid finch
#

i remember the name wasn't something descriptive

#

it's holyNotes

#

i thinkβ„’

mint widget
#

holyNotes ahh then channelTabs must be something else

timid finch
#

channel tabs is like

#

browser tabs for channels

#

iirc

mint widget
#

although holyNotes is mentioned there i cant find the source for that

#

all i found for holyNotes is just initializing from plugins.holyNotes and i cant find that

timid finch
#

it may have been removed

#

maybe it broke too often or something

mint widget
#

ahh its made like an app too

#

what i want to do is different, adding a bookmark icon to each message and having its own bookmark tab somewhere where you go through your bookmarks

#

i made two plugins before but i have zero idea how i would do these tbh

timid finch
#

yea that's what this was p sure

#

it adds a context menu option on hover

mint widget
#

oh yea i see

timid finch
#

then there wkuld be some like "pins" style menu i think?

mint widget
#

i think it mustve got removed

timid finch
#

where u could pull up the list

timid finch
mint widget
#

i found it somewhere

timid finch
#

nice

mint widget
#

well honestly checking it out i think i will leave this up to someone else to make i dont have that much free time right now and this would probably take a long time 😭

#

i think ill just make a discord app for notes or look if theres an existing one

timid finch
#

i just forward messages to a private channel in my own discord

#

lol

mint widget
#

yeah thats the only option but its pretty ass compared to what could be more a streamlined process

timid finch
#

yeh gl Prayging

mint widget
timid finch
#

ah cool

supple rose
#

how do I expose functions from the node env to the dom, same was as electron or different?

dull magnet
supple rose
#

I did, so VencordNative.pluginHelpers.ConsoleShortcuts?

hushed loom
#

(but generally yes, vencordNative.pluginHelpers.yourPluginName

supple rose
#

I know this kinda doesn't fit into this channel but I'm not very familiar with the concept of a lockfile, but how do I add packages if I want to use them in my plugin?

obsidian shell
supple rose
#

wdym

#

so like creating a subpackage for my plugin?

obsidian shell
#

which package do you wanna use

supple rose
#

ws

obsidian shell
#

what are you trying to do

supple rose
#

want to display spotify lyrics in my discord overlay that I made using websockets

obsidian shell
supple rose
#

yea

obsidian shell
#

okay then since plugins run in a web context you can just use the WebSocket web api

#

vai how to use websocket js

shrewd tundraBOT
# obsidian shell vai how to use websocket js

To use WebSockets in JavaScript, you'll primarily interact with the WebSocket API. Here's a concise overview:

1. Create a WebSocket Object

Instantiate a new WebSocket object, providing the URL of your WebSocket server. Use wss:// for secure connections, similar to https://.

let socket = new WebSocket("wss://your-websocket-server.com/path");

2. Handle Events

WebSockets are event-driven. You'll attach functions to these events:

  • onopen: Fired when the connection is successfully established.

    socket.onopen = (event) => {
        console.log("Connection established!");
    };
    
  • onmessage: Fired when data is received from the server. The received data is in event.data.

    socket.onmessage = (event) => {
        console.log(`Data received: ${event.data}`);
    };
    
  • onclose: Fired when the connection is closed. event.wasClean indicates if it was a clean closure, and event.code provides a status code.

    socket.onclose = (event) => {
        console.log(`Connection closed: ${event.code} ${event.reason}`);
    };
    
  • onerror: Fired if an error occurs during connection or communication.

    socket.onerror = (error) => {
        console.error("WebSocket Error:", error);
    };
    

3. Send Data

Use the send() method to transmit data to the server. Data can be a string or binary (ArrayBuffer or Blob).

socket.send("Hello from the client!");

4. Close the Connection

To close the WebSocket connection, call the close() method.

socket.close();

Remember that WebSockets enable real-time, two-way communication between a client and a server, making them ideal for applications requiring continuous data exchange like chat apps or online games.

-# Response generated by gemini-2.5-flash. AI may be incorrect or misleading.

supple rose
#

I want discord to be the ws server tho that's why I want to use ws because the spotify app doesn't run on electron and doesn't have something like a native file

#

with your example I'd need a third app just for sending data between spotify and discord

obsidian shell
#

then you could install a dependency as long as you are willing to potentially manage merge conflicts

Also you wouldn’t be able to submit the plugin to #1256395889354997771 or as a PR

#

and you can use a native.ts file on the vencord side

#

But that’s also very overengineered you should just use lrclib

supple rose
#

that's what I'm using for fetching the lyrics but I don't get stuff like song progress or the paused state when only doing that

#

how do I add dependecies tho, when I run pnpm add -w ws it doesn't allow me to build anymore

#

and just adding without the flag gives me an error message to run it with the flag

silk sorrel
#

hop on extendify

supple rose
#

I'm currently using spicetify

silk sorrel
#

oh wait yeah it might be CEF
my bad

quick zephyr
#

you have spotify premium?

supple rose
supple rose
#

I know I could use a web api key for that stuff I didn't really want to bother with the webapi

#

because I'd need to fetch every couple of secods for checking if the song is currently playing

quick zephyr
#

ah that's local state stuff I guess. maybe idk

supple rose
#

this seems like it should actually work pretty easily

#

I'd need to add authentication but it should be pretty easy I think

#

thanks a lot

#

not that I really plan to publish my plugin due to how niche it is and I really just wanted to have this myself, but if I was planning to publish this it still wouldn't be allowed because it requires the need to input your spitify web api token into

timid finch
#

can u nest css in the styles.css for a plugni so u dont affect other random stuff if its using a generic class

#

ok look slike u can nvm

#

but its weird theyre all like mostly flat

obsidian shell
supple rose
#

I prefer to just stick to css module files as in filename.module.css and then importing it in js

broken storm
#

Patch by MessageCorrector had no effect (Module id is 173169): /(\i)=\(0,(\i)\.(\i)\)\(\{messages:(\i)/
aw cmon bruh

#

but now I figured out why it wasn't working

royal ginkgo
#

so are the general requirements for submitting a plugin? i would assume it needs to be cross-platform

#

I am trying to make a plugin adding pgp related features (encrypting, decrypting, signing, verifying) and am thinking about just running gpg to do everything

dull magnet
#

too niche and doesn't work well inside discord

#

Use proper encrypted messengers like Signal, XMPP, Matrix

royal ginkgo
#

ah

royal ginkgo
#

how can I make a setting which isn't visible in the setting ui, i basically just need to have a string that persists through restarts

silk sorrel
#

hidden: true

royal ginkgo
#

then how do I set and read the setting

silk sorrel
#

using the settings api
const {setting} = settings.use(["setting"]) in a react component
or directly from the settings object

royal ginkgo
#

ok

royal ginkgo
#

is it possible to make a command which has a list of choice options? I want a command where you can specify a unlimited about of keys and I need the keys to only be the keys in a list

#

I know I can do choices: [] but I need the user to be able to select any amount of choices

#

so actually ig I want a multi select thing

#

where the user can select any amount of items in a list

proud parrotBOT
dim jay
#

look at how petpet does it

#

till line 147

royal ginkgo
#

ah ok, thanks

dim jay
#

i might be wrong

#

but it would make sense for it to be that

royal ginkgo
#

I think what I want is different, that implementation seems to be for having like 5 ways to get a image, I just have an arbitrary list which I need to let users select many items in that list

#

so ig I could make each key a different bool option

dim jay
#

wouldnt strings just be better

royal ginkgo
#

i don't want the user to be able to enter a key which isn't valid

#

one thing I am gonna try is making a modal for selecting the keys

royal ginkgo
#

is it possible to replace the contents of a message?

#

ig I could do document.getElementById("message-content-<message_id>").children[0].innerHTML = content

#

would that allow xss?

vast karma
#

Most certainly

royal ginkgo
#

yeaaa

dull magnet
#
updateMessage(channelId, messageId, { content: "balls" })
royal ginkgo
#

ah

#

thanks

dull magnet
# royal ginkgo ah

but also if you want to permanently change something in every message that fulfils some criterium you should patch the message renderer instead

royal ginkgo
#

I just wanted to change a message whenever a button is pressed and this seems to work fine, thank you though :3

dull magnet
#

oki

#

but theres a chance for the change to be lost in some scenarios

royal ginkgo
#

how would I patch the message renderer? i am making a option to just automatically decrypt messages

hushed loom
royal ginkgo
#

what are message accessories

hushed loom
royal ginkgo
#

i have no clue what I am doing 😭

#

does anyone know how to patch the message renderer?

fair spear
#

fun fact you can actually navigate into a discord category like a normal channel for some reason

silk sorrel
#

back in my day you could navigate to a server channel in dms or a dm in a server cuz it wasn't even validated

amber mantle
#

that can still happen on the rn apps

#

also wysi

silk sorrel
#

I dont see it (1:27pm) 😭

little maple
#

how can i get the text of the user in the message box?

dull magnet
#

why would there be documentation for how to do things in a proprietary app

#

you have to reverse engineer to figure it out

#

cry me a river dude you're asking why there's no documentation for literal proprietary discord stuff

#

the documentation for that is existing plugins where the authors have already done the reverse engineering work

#

Also a ton of typescript types for many common discord modules

little maple
#

ok, sorry, i don't want to argue

#

i will retract my statement

dull magnet
#

literally 75% of the work has been done for you and you're too lazy to do the remaining 25%

#

go do some normal js dev if you need documentation for every step

little maple
#

i already apologized

#

there is one thing i am curious on though: how can i make the user react to a message with an emoji?

dull magnet
#

you can find it with react devtools

#

inspect any button that adds a reaction

#

then see its onClick handler and check the code

#

.

#

or just search the discord sources for keywords like addReaction, ADD_REACTION

little maple
#

got it

#

thank you

#

does the dev companion plugin include react devtools? sorry dumb question

dull magnet
#

you enable it in vencord settings

little maple
#

ok, i found the onClick function for an emoji, but i am not sure what to do from there, as i don't see the actual logic that adds the reaction.