Compare commits

...

22 commits

Author SHA1 Message Date
AdiGro
52b51def99
Merge 513eccb70a into 6cce8a8bc4 2024-09-17 22:49:29 +02:00
Nuckyz
6cce8a8bc4
Experiments: Allow clips to be recorded without streaming
Some checks failed
Sync to Codeberg / codeberg (push) Has been cancelled
test / test (push) Has been cancelled
2024-09-17 14:30:23 -03:00
Nuckyz
1848b16536
ReviewDB: Fix in panel profile 2024-09-17 14:30:23 -03:00
Kyuuhachi
c572116b97
BetterSettings: Add submenu for plugins (#2858)
Co-authored-by: Vendicated <vendicated@riseup.net>
2024-09-17 15:40:11 +00:00
Lumap
e26986f66a
AppleMusicRichPresence: fix formatting when listening to radio (#2869)
Co-authored-by: Ryan Cao <70191398+ryanccn@users.noreply.github.com>
Co-authored-by: v <vendicated@riseup.net>
2024-09-17 17:29:46 +02:00
Taran Grover
513eccb70a change patches and extract code in functions 2024-09-13 01:31:11 +02:00
AdiGro
11dd4cf3b0
Update src/plugins/filterBotMentions/index.tsx
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
2024-09-12 05:02:27 +02:00
Taran Grover
1755c2cf6f extract filter callback into a function 2024-09-12 04:55:54 +02:00
Taran Grover
4d9acac992 find prop outside of the function and added types 2024-09-12 03:13:32 +02:00
AdiGro
24fa55bbbe
Update README.md 2024-09-12 02:35:50 +02:00
AdiGro
3bf235d115
Update README.md 2024-09-12 02:34:44 +02:00
Taran Grover
6b952c24be edit plugin description to be less misunderstandable 2024-09-12 02:32:43 +02:00
Taran Grover
ecfc09ac3f use camcel case for plugin names 2024-09-12 02:31:47 +02:00
Taran Grover
608fdd4f96 use camcel case for plugin names 2024-09-12 02:30:40 +02:00
Taran Grover
2b887fda18 add types 2024-09-12 02:28:06 +02:00
Taran Grover
18c2b7d730 add to Devs 2024-09-12 02:27:59 +02:00
AdiGro
35bc98b2b5
add [myself] to devs 2024-09-12 02:21:25 +02:00
AdiGro
73a6d43840
Update src/plugins/filterBotMentions/index.tsx
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
2024-09-12 02:18:28 +02:00
AdiGro
cd2568cfcd
Update src/plugins/filterBotMentions/index.tsx
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
2024-09-12 02:18:12 +02:00
Taran Grover
bc655d673b lint 2024-09-12 00:03:55 +02:00
AdiGro
e7a233f1d3
Update index.tsx 2024-09-12 00:00:32 +02:00
Taran Grover
cdc2055e78 feat(Plugin): Filter bot mentions 2024-09-11 23:51:43 +02:00
10 changed files with 220 additions and 25 deletions

View file

@ -24,7 +24,7 @@ interface ActivityButton {
} }
interface Activity { interface Activity {
state: string; state?: string;
details?: string; details?: string;
timestamps?: { timestamps?: {
start?: number; start?: number;
@ -52,8 +52,8 @@ const enum ActivityFlag {
export interface TrackData { export interface TrackData {
name: string; name: string;
album: string; album?: string;
artist: string; artist?: string;
appleMusicLink?: string; appleMusicLink?: string;
songLink?: string; songLink?: string;
@ -61,8 +61,8 @@ export interface TrackData {
albumArtwork?: string; albumArtwork?: string;
artistArtwork?: string; artistArtwork?: string;
playerPosition: number; playerPosition?: number;
duration: number; duration?: number;
} }
const enum AssetImageType { const enum AssetImageType {
@ -155,8 +155,8 @@ const settings = definePluginSettings({
function customFormat(formatStr: string, data: TrackData) { function customFormat(formatStr: string, data: TrackData) {
return formatStr return formatStr
.replaceAll("{name}", data.name) .replaceAll("{name}", data.name)
.replaceAll("{album}", data.album) .replaceAll("{album}", data.album ?? "")
.replaceAll("{artist}", data.artist); .replaceAll("{artist}", data.artist ?? "");
} }
function getImageAsset(type: AssetImageType, data: TrackData) { function getImageAsset(type: AssetImageType, data: TrackData) {
@ -212,14 +212,16 @@ export default definePlugin({
const assets: ActivityAssets = {}; const assets: ActivityAssets = {};
const isRadio = Number.isNaN(trackData.duration) && (trackData.playerPosition === 0);
if (settings.store.largeImageType !== AssetImageType.Disabled) { if (settings.store.largeImageType !== AssetImageType.Disabled) {
assets.large_image = largeImageAsset; assets.large_image = largeImageAsset;
assets.large_text = customFormat(settings.store.largeTextString, trackData); if (!isRadio) assets.large_text = customFormat(settings.store.largeTextString, trackData);
} }
if (settings.store.smallImageType !== AssetImageType.Disabled) { if (settings.store.smallImageType !== AssetImageType.Disabled) {
assets.small_image = smallImageAsset; assets.small_image = smallImageAsset;
assets.small_text = customFormat(settings.store.smallTextString, trackData); if (!isRadio) assets.small_text = customFormat(settings.store.smallTextString, trackData);
} }
const buttons: ActivityButton[] = []; const buttons: ActivityButton[] = [];
@ -243,17 +245,17 @@ export default definePlugin({
name: customFormat(settings.store.nameString, trackData), name: customFormat(settings.store.nameString, trackData),
details: customFormat(settings.store.detailsString, trackData), details: customFormat(settings.store.detailsString, trackData),
state: customFormat(settings.store.stateString, trackData), state: isRadio ? undefined : customFormat(settings.store.stateString, trackData),
timestamps: (settings.store.enableTimestamps ? { timestamps: (trackData.playerPosition && trackData.duration && settings.store.enableTimestamps) ? {
start: Date.now() - (trackData.playerPosition * 1000), start: Date.now() - (trackData.playerPosition * 1000),
end: Date.now() - (trackData.playerPosition * 1000) + (trackData.duration * 1000), end: Date.now() - (trackData.playerPosition * 1000) + (trackData.duration * 1000),
} : undefined), } : undefined,
assets, assets,
buttons: buttons.length ? buttons.map(v => v.label) : undefined, buttons: !isRadio && buttons.length ? buttons.map(v => v.label) : undefined,
metadata: { button_urls: buttons.map(v => v.url) || undefined, }, metadata: !isRadio && buttons.length ? { button_urls: buttons.map(v => v.url) } : undefined,
type: settings.store.activityType, type: settings.store.activityType,
flags: ActivityFlag.INSTANCE, flags: ActivityFlag.INSTANCE,

View file

@ -0,0 +1,68 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { openPluginModal } from "@components/PluginSettings/PluginModal";
import { isObjectEmpty } from "@utils/misc";
import { Alerts, i18n, Menu, useMemo, useState } from "@webpack/common";
import Plugins from "~plugins";
function onRestartNeeded() {
Alerts.show({
title: "Restart required",
body: <p>You have changed settings that require a restart.</p>,
confirmText: "Restart now",
cancelText: "Later!",
onConfirm: () => location.reload()
});
}
export default function PluginsSubmenu() {
const sortedPlugins = useMemo(() => Object.values(Plugins)
.sort((a, b) => a.name.localeCompare(b.name)), []);
const [query, setQuery] = useState("");
const search = query.toLowerCase();
const include = (p: typeof Plugins[keyof typeof Plugins]) => (
Vencord.Plugins.isPluginEnabled(p.name)
&& p.options && !isObjectEmpty(p.options)
&& (
p.name.toLowerCase().includes(search)
|| p.description.toLowerCase().includes(search)
|| p.tags?.some(t => t.toLowerCase().includes(search))
)
);
const plugins = sortedPlugins.filter(include);
return (
<>
<Menu.MenuControlItem
id="vc-plugins-search"
control={(props, ref) => (
<Menu.MenuSearchControl
{...props}
query={query}
onChange={setQuery}
ref={ref}
placeholder={i18n.Messages.SEARCH}
/>
)}
/>
{!!plugins.length && <Menu.MenuSeparator />}
{plugins.map(p => (
<Menu.MenuItem
key={p.name}
id={p.name}
label={p.name}
action={() => openPluginModal(p, onRestartNeeded)}
/>
))}
</>
);
}

View file

@ -13,6 +13,8 @@ import { waitFor } from "@webpack";
import { ComponentDispatch, FocusLock, i18n, Menu, useEffect, useRef } from "@webpack/common"; import { ComponentDispatch, FocusLock, i18n, Menu, useEffect, useRef } from "@webpack/common";
import type { HTMLAttributes, ReactElement } from "react"; import type { HTMLAttributes, ReactElement } from "react";
import PluginsSubmenu from "./PluginsSubmenu";
type SettingsEntry = { section: string, label: string; }; type SettingsEntry = { section: string, label: string; };
const cl = classNameFactory(""); const cl = classNameFactory("");
@ -118,13 +120,21 @@ export default definePlugin({
}, },
{ // Settings cog context menu { // Settings cog context menu
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL", find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
replacement: { replacement: [
{
match: /(EXPERIMENTS:.+?)(\(0,\i.\i\)\(\))(?=\.filter\(\i=>\{let\{section:\i\}=)/, match: /(EXPERIMENTS:.+?)(\(0,\i.\i\)\(\))(?=\.filter\(\i=>\{let\{section:\i\}=)/,
replace: "$1$self.wrapMenu($2)" replace: "$1$self.wrapMenu($2)"
},
{
match: /case \i\.\i\.DEVELOPER_OPTIONS:return \i;/,
replace: "$&case 'VencordPlugins':return $self.PluginsSubmenu();"
} }
} ]
},
], ],
PluginsSubmenu,
// This is the very outer layer of the entire ui, so we can't wrap this in an ErrorBoundary // This is the very outer layer of the entire ui, so we can't wrap this in an ErrorBoundary
// without possibly also catching unrelated errors of children. // without possibly also catching unrelated errors of children.
// //

View file

@ -126,7 +126,7 @@ export default definePlugin({
} }
}, },
{ {
find: '"Handling ping: "', find: '"_handleLocalVideoDisabled: ',
predicate: () => settings.store.disableNoisyLoggers, predicate: () => settings.store.disableNoisyLoggers,
replacement: { replacement: {
match: /new \i\.\i\("RTCConnection\("\.concat.+?\)\)(?=,)/, match: /new \i\.\i\("RTCConnection\("\.concat.+?\)\)(?=,)/,

View file

@ -23,12 +23,13 @@ import { ErrorCard } from "@components/ErrorCard";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack"; import { findByPropsLazy, findLazy } from "@webpack";
import { Forms, React } from "@webpack/common"; import { Forms, React } from "@webpack/common";
import hideBugReport from "./hideBugReport.css?managed"; import hideBugReport from "./hideBugReport.css?managed";
const KbdStyles = findByPropsLazy("key", "combo"); const KbdStyles = findByPropsLazy("key", "combo");
const BugReporterExperiment = findLazy(m => m?.definition?.id === "2024-09_bug_reporter");
const settings = definePluginSettings({ const settings = definePluginSettings({
toolbarDevMenu: { toolbarDevMenu: {
@ -78,8 +79,8 @@ export default definePlugin({
{ {
find: "toolbar:function", find: "toolbar:function",
replacement: { replacement: {
match: /\i\.isStaff\(\)/, match: /hasBugReporterAccess:(\i)/,
replace: "true" replace: "_hasBugReporterAccess:$1=true"
}, },
predicate: () => settings.store.toolbarDevMenu predicate: () => settings.store.toolbarDevMenu
}, },
@ -91,10 +92,18 @@ export default definePlugin({
match: /\i\.isDM\(\)\|\|\i\.isThread\(\)/, match: /\i\.isDM\(\)\|\|\i\.isThread\(\)/,
replace: "false", replace: "false",
} }
},
// enable option to always record clips even if you are not streaming
{
find: "isDecoupledGameClippingEnabled(){",
replacement: {
match: /\i\.isStaff\(\)/,
replace: "true"
}
} }
], ],
start: () => enableStyle(hideBugReport), start: () => !BugReporterExperiment.getCurrentConfig().hasBugReporterAccess && enableStyle(hideBugReport),
stop: () => disableStyle(hideBugReport), stop: () => disableStyle(hideBugReport),
settingsAboutComponent: () => { settingsAboutComponent: () => {

View file

@ -0,0 +1,13 @@
# FilterBotMentions
Allows you to filter bot mentions in recent mentions panel.
# Usage
You can include/exclude mentions by bots in the box either using the checkbox in recent mentions panel, or in the plugin settings.
Include mentions by bots:
![image](https://github.com/user-attachments/assets/a80a41fc-9bae-4612-a23a-b1894e0f8fd2)
Excluded mentions by bots:
![image](https://github.com/user-attachments/assets/fdf973eb-23ef-4101-b4de-e3fb6663f41b)

View file

@ -0,0 +1,84 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { getCurrentGuild } from "@utils/discord";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findStoreLazy } from "@webpack";
import { Menu } from "@webpack/common";
import { Message } from "discord-types/general";
const settings = definePluginSettings({
toggle: {
type: OptionType.BOOLEAN,
description: "Include mentions by bots in inbox",
default: true,
},
});
type RecentMentionsStore = { guildFilter: string, roleFilter: boolean, everyoneFilter: boolean; };
type fetchRecentMentionsType = (before: BigInt | null, limit: Number | null, all_servers: string | null | undefined, role: boolean, everyone: boolean,) => void;
const { fetchRecentMentions } = findByPropsLazy("fetchRecentMentions") as { fetchRecentMentions: fetchRecentMentionsType; };
const recentMentionsStore = findStoreLazy("RecentMentionsStore") as RecentMentionsStore;
export default definePlugin({
name: "FilterBotMentions",
description: "Filter mentions by bots in inbox",
authors: [Devs.Taran],
patches: [
{
find: "get lastLoaded",
replacement: {
match: /getMentions.{0,30}\?\i/,
replace: "$&.filter($self.filterMessages)"
}
},
{
find: "mentions-filter",
replacement: {
match: /children:\[\(0,\i\.jsx\).{0,600}\}\)\]/,
replace: "$&.concat($self.patchMenu())"
}
}
],
settings,
reloadMentions(): void {
const all_servers: boolean = recentMentionsStore.guildFilter === "ALL_SERVERS";
const { roleFilter: role, everyoneFilter: everyone } = recentMentionsStore;
const serverToFilter: string | undefined | null = all_servers ? null : getCurrentGuild()?.id;
fetchRecentMentions(null, null, serverToFilter, role, everyone);
},
toggleBotMentions(): void {
settings.store.toggle = !settings.store.toggle;
},
filterMessages(message: Message): boolean {
return !message.author.bot || settings.store.toggle;
},
patchMenu() {
return (
<Menu.MenuCheckboxItem
id="Bots"
label="Include mentions by bots"
action={() => {
this.toggleBotMentions();
this.reloadMentions();
}}
checked={settings.store.toggle}
/>
);
}
});

View file

@ -91,7 +91,7 @@ export default definePlugin({
} }
}, },
{ {
find: ".PANEL,isInteractionSource:", find: ".PANEL,interactionType:",
replacement: { replacement: {
match: /{profileType:\i\.\i\.PANEL,children:\[/, match: /{profileType:\i\.\i\.PANEL,children:\[/,
replace: "$&$self.BiteSizeReviewsButton({user:arguments[0].user})," replace: "$&$self.BiteSizeReviewsButton({user:arguments[0].user}),"

View file

@ -575,6 +575,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "RamziAH", name: "RamziAH",
id: 1279957227612147747n, id: 1279957227612147747n,
}, },
Taran: {
name: "Taran",
id: 482951588055351306n
},
} satisfies Record<string, Dev>); } satisfies Record<string, Dev>);
// iife so #__PURE__ works correctly // iife so #__PURE__ works correctly

View file

@ -72,6 +72,11 @@ export interface Menu {
onChange(value: number): void, onChange(value: number): void,
renderValue?(value: number): string, renderValue?(value: number): string,
}>; }>;
MenuSearchControl: RC<{
query: string
onChange(query: string): void;
placeholder?: string;
}>;
} }
export interface ContextMenuApi { export interface ContextMenuApi {