Compare commits

...

10 commits

Author SHA1 Message Date
77084203c6
fork init
Some checks failed
Sync to Codeberg / codeberg (push) Waiting to run
test / test (push) Waiting to run
Build DevBuild / Build (push) Has been cancelled
2025-06-06 12:20:47 -04:00
Nuckyz
0ce7772500
FakeNitro: Fix sending animated stickers 2025-06-05 15:42:00 -03:00
Henry
503c90c201
ShowHiddenChannels: Fix showing lock icon for special channels (#3460) 2025-06-05 00:24:04 +00:00
Elvyra
db0bcf7da3
WebContextMenus: Fix copying and saving images (#3459) 2025-06-05 00:18:20 +00:00
Nuckyz
0e90bda3c7
Fix AnonymiseFileNames
Also fix issues with User Profile Modal v2 MutualGroupDMs patches
2025-06-04 20:53:43 -03:00
Nuckyz
f0fcaf734e
ShowHiddenChannels: Fix erroring when avoiding fetching channel messages 2025-05-30 11:49:36 -03:00
Vendicated
eafbc0d15a
WhoReacted: fix crashing (app reloading) 2025-05-29 23:10:58 +02:00
Nuckyz
2a4314efc9
ShowHiddenChannels: Fix incorrectly fetching messages 2025-05-29 17:01:12 -03:00
Ataraxis
b706d53998
Fix not respecting contributor badge preference (#3443) 2025-05-28 11:24:48 -03:00
Nuckyz
76b1fe9a87
Delete MoreCommands plugin
This plugin is useless and the commands it adds have almost no use or can be replaced using the TextReplace plugin
2025-05-28 10:38:20 -03:00
13 changed files with 167 additions and 100 deletions

View file

@ -27,7 +27,7 @@ import { openContributorModal } from "@components/PluginSettings/ContributorModa
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { isPluginDev } from "@utils/misc";
import { shouldShowContributorBadge } from "@utils/misc";
import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
import definePlugin from "@utils/types";
import { Forms, Toasts, UserStore } from "@webpack/common";
@ -39,7 +39,7 @@ const ContributorBadge: ProfileBadge = {
description: "Vencord Contributor",
image: CONTRIBUTOR_BADGE,
position: BadgePosition.START,
shouldShow: ({ userId }) => isPluginDev(userId),
shouldShow: ({ userId }) => shouldShowContributorBadge(userId),
onClick: (_, { userId }) => openContributorModal(UserStore.getUser(userId))
};

View file

@ -72,18 +72,17 @@ export default definePlugin({
patches: [
{
find: 'type:"UPLOAD_START"',
replacement: {
match: /await \i\.uploadFiles\((\i),/,
replace: "$1.forEach($self.anonymise),$&"
},
},
{
find: 'addFilesTo:"message.attachments"',
replacement: {
match: /\i.uploadFiles\((\i),/,
replace: "$1.forEach($self.anonymise),$&"
}
find: "async uploadFiles(",
replacement: [
{
match: /async uploadFiles\((\i),\i\){/,
replace: "$&$1.forEach($self.anonymise);"
},
{
match: /async uploadFilesSimple\((\i)\){/,
replace: "$&$1.forEach($self.anonymise);"
}
],
},
{
find: "#{intl::ATTACHMENT_UTILITIES_SPOILER}",

View file

@ -1,65 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated, Samu and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { ApplicationCommandInputType, findOption, OptionalMessageOption, RequiredMessageOption, sendBotMessage } from "@api/Commands";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
function mock(input: string): string {
let output = "";
for (let i = 0; i < input.length; i++) {
output += i % 2 ? input[i].toUpperCase() : input[i].toLowerCase();
}
return output;
}
export default definePlugin({
name: "MoreCommands",
description: "echo, lenny, mock",
authors: [Devs.Arjix, Devs.echo, Devs.Samu],
commands: [
{
name: "echo",
description: "Sends a message as Clyde (locally)",
options: [OptionalMessageOption],
inputType: ApplicationCommandInputType.BOT,
execute: (opts, ctx) => {
const content = findOption(opts, "message", "");
sendBotMessage(ctx.channel.id, { content });
},
},
{
name: "lenny",
description: "Sends a lenny face",
options: [OptionalMessageOption],
execute: opts => ({
content: findOption(opts, "message", "") + " ( ͡° ͜ʖ ͡°)"
}),
},
{
name: "mock",
description: "mOcK PeOpLe",
options: [RequiredMessageOption],
execute: opts => ({
content: mock(findOption(opts, "message", ""))
}),
},
]
});

View file

@ -121,14 +121,9 @@ export default definePlugin({
},
// Make the gap between each item smaller so our tab can fit.
{
match: /className:\i\.tabBar/,
replace: '$& + " vc-mutual-gdms-modal-v2-tab-bar"'
match: /type:"top",/,
replace: '$&className:"vc-mutual-gdms-modal-v2-tab-bar",'
},
// Make the tab bar item text smaller so our tab can fit.
{
match: /(\.tabBarItem.+?variant:)"heading-md\/normal"/,
replace: '$1"heading-sm/normal"'
}
]
},
{

View file

@ -3,5 +3,5 @@
}
.vc-mutual-gdms-modal-v2-tab-bar {
gap: 12px;
--space-xl: 16px;
}

View file

@ -0,0 +1,120 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { definePluginSettings } from "@api/Settings";
import { Link } from "@components/Link";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
const API_URL = "https://usrbg.dorkbutt.lol/users/users.json";
interface UsrbgApiReturn {
endpoint: string;
bucket: string;
prefix: string;
users: Record<string, string>;
}
const settings = definePluginSettings({
nitroFirst: {
description: "Banner to use if both Nitro and USRBG banners are present",
type: OptionType.SELECT,
options: [
{ label: "Nitro banner", value: true, default: true },
{ label: "USRBG banner", value: false },
]
},
voiceBackground: {
description: "Use USRBG banners as voice chat backgrounds",
type: OptionType.BOOLEAN,
default: true,
restartNeeded: true
}
});
export default definePlugin({
name: "FORKED - USRBG",
description: "Displays user banners from dorkbutt's USRBG server, allowing anyone to get a banner without Nitro",
authors: [Devs.dorkbutt, Devs.AutumnVN, Devs.katlyn, Devs.pylix, Devs.TheKodeToad],
settings,
patches: [
{
find: '.banner)==null?"COMPLETE"',
replacement: {
match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/,
replace: "$self.patchBannerUrl(arguments[0])||$&"
}
},
{
find: "\"data-selenium-video-tile\":",
predicate: () => settings.store.voiceBackground,
replacement: [
{
match: /(?<=function\((\i),\i\)\{)(?=let.{20,40},style:)/,
replace: "$1.style=$self.getVoiceBackgroundStyles($1);"
}
]
}
],
data: null as UsrbgApiReturn | null,
settingsAboutComponent: () => {
return (
"Message @dorkbutt about getting your personal banner added!"
);
},
getVoiceBackgroundStyles({ className, participantUserId }: any) {
if (className.includes("tile_")) {
if (this.userHasBackground(participantUserId)) {
return {
backgroundImage: `url(${this.getImageUrl(participantUserId)})`,
backgroundSize: "cover",
backgroundPosition: "center",
backgroundRepeat: "no-repeat"
};
}
}
},
patchBannerUrl({ displayProfile }: any) {
if (displayProfile?.banner && settings.store.nitroFirst) return;
if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId);
},
userHasBackground(userId: string) {
return !!this.data?.users[userId];
},
getImageUrl(userId: string): string | null {
if (!this.userHasBackground(userId)) return null;
// We can assert that data exists because userHasBackground returned true
const { endpoint, bucket, prefix, users: { [userId]: etag } } = this.data!;
return `${endpoint}/${bucket}/${prefix}${userId}?${etag}`;
},
async start() {
const res = await fetch(API_URL);
if (res.ok) {
this.data = await res.json();
}
}
});

View file

@ -0,0 +1,6 @@
{"endpoint":"https://usrbg.dorkbutt.lol","bucket":"usrbg","prefix":"v2/",
"users":{
"862105885660676146":"db1d",
"578012873813524530":"315c"
}
}

View file

@ -267,7 +267,7 @@ export default definePlugin({
{
find: '"MessageManager"',
replacement: {
match: /"Skipping fetch because channelId is a static route"\);return}(?=.+?getChannel\((\i)\))/,
match: /forceFetch:\i,isPreload:.+?}=\i;(?=.+?getChannel\((\i)\))/,
replace: (m, channelId) => `${m}if($self.isHiddenChannel({channelId:${channelId}}))return;`
}
},
@ -494,10 +494,11 @@ export default definePlugin({
isHiddenChannel(channel: Channel & { channelId?: string; }, checkConnect = false) {
try {
if (!channel) return false;
if (channel == null || Object.hasOwn(channel, "channelId") && channel.channelId == null) return false;
if (channel.channelId) channel = ChannelStore.getChannel(channel.channelId);
if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false;
if (channel.channelId != null) channel = ChannelStore.getChannel(channel.channelId);
if (channel == null || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false;
if (["browse", "customize", "guide"].includes(channel.id)) return false;
return !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || checkConnect && !PermissionStore.can(PermissionsBits.CONNECT, channel);
} catch (e) {

View file

@ -122,10 +122,16 @@ export default definePlugin({
{
find: "Copy image not supported",
replacement: {
match: /(?<=(?:canSaveImage|canCopyImage)\(\i?\)\{.{0,50})!\i\.isPlatformEmbedded/g,
replace: "false"
}
replacement: [
{
match: /(?<=(?:canSaveImage|canCopyImage)\(.{0,120}?)!\i\.isPlatformEmbedded/g,
replace: "false"
},
{
match: /canCopyImage\(.+?(?=return"function"==typeof \i\.clipboard\.copyImage)/,
replace: "$&return true;"
}
]
},
// Add back Copy & Save Image
{
@ -137,7 +143,7 @@ export default definePlugin({
replace: "false"
},
{
match: /return\s*?\[.{0,50}?(?=\?.{0,100}?id:"copy-image")/,
match: /return\s*?\[.{0,50}?(?=\?\(0,\i\.jsxs?.{0,100}?id:"copy-image")/,
replace: "return [true"
},
{

View file

@ -66,7 +66,7 @@ function fetchReactions(msg: Message, emoji: ReactionEmoji, type: number) {
function getReactionsWithQueue(msg: Message, e: ReactionEmoji, type: number) {
const key = `${msg.id}:${e.name}:${e.id ?? ""}:${type}`;
const cache = reactions[key] ??= { fetched: false, users: {} };
const cache = reactions[key] ??= { fetched: false, users: new Map() };
if (!cache.fetched) {
queue.unshift(() => fetchReactions(msg, e, type));
cache.fetched = true;
@ -159,7 +159,7 @@ export default definePlugin({
}, [message.id, forceUpdate]);
const reactions = getReactionsWithQueue(message, emoji, type);
const users = Object.values(reactions).filter(Boolean) as User[];
const users = [...reactions.values()].filter(Boolean);
return (
<div
@ -187,7 +187,7 @@ export default definePlugin({
interface ReactionCacheEntry {
fetched: boolean;
users: Record<string, User>;
users: Map<string, User>;
}
interface RootObject {

View file

@ -589,6 +589,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "samsam",
id: 836452332387565589n,
},
Cootshk: {
name: "Cootshk",
id: 921605971577548820n
},
} satisfies Record<string, Dev>);
// iife so #__PURE__ works correctly

View file

@ -92,6 +92,7 @@ export function identity<T>(value: T): T {
export const isMobile = navigator.userAgent.includes("Mobi");
export const isPluginDev = (id: string) => Object.hasOwn(DevsById, id);
export const shouldShowContributorBadge = (id: string) => isPluginDev(id) && DevsById[id].badge !== false;
export function pluralise(amount: number, singular: string, plural = singular + "s") {
return amount === 1 ? `${amount} ${singular}` : `${amount} ${plural}`;

View file

@ -138,7 +138,7 @@ export const UserUtils = {
export const UploadManager = findByPropsLazy("clearAll", "addFile");
export const UploadHandler = {
promptToUpload: findByCodeLazy("#{intl::ATTACHMENT_TOO_MANY_ERROR_TITLE}") as (files: File[], channel: Channel, draftType: Number) => void
promptToUpload: findByCodeLazy("=!0,showLargeMessageDialog:") as (files: File[], channel: Channel, draftType: Number) => void
};
export const ApplicationAssetUtils = mapMangledModuleLazy("getAssetImage: size must === [", {