Plugin

USRBG

Displays user banners from USRBG, allowing anyone to get a banner without Nitro

Appearance Customisation
index.tsx
Download

Source

src/plugins/usrbg/index.tsx
1import { definePluginSettings } from "@api/Settings";
2import { LinkButton } from "@components/Button";
3import { Devs } from "@utils/constants";
4import definePlugin, { OptionType } from "@utils/types";
5
6const API_URL = "https:class="ts-cmt">//usrbg.is-hardly.online/users";
7
8interface UsrbgApiReturn {
9 endpoint: string;
10 bucket: string;
11 prefix: string;
12 users: Record<string, string>;
13}
14
15const settings = definePluginSettings({
16 nitroFirst: {
17 description: "Banner to use if both Nitro and USRBG banners are present",
18 type: OptionType.SELECT,
19 options: [
20 { label: "Nitro banner", value: true, default: true },
21 { label: "USRBG banner", value: false },
22 ]
23 },
24 voiceBackground: {
25 description: "Use USRBG banners as voice chat backgrounds",
26 type: OptionType.BOOLEAN,
27 default: true,
28 restartNeeded: true
29 }
30});
31
32export default definePlugin({
33 name: "USRBG",
34 description: "Displays user banners from USRBG, allowing anyone to get a banner without Nitro",
35 tags: ["Appearance", "Customisation"],
36 authors: [Devs.AutumnVN, Devs.katlyn, Devs.pylix, Devs.TheKodeToad],
37 settings,
38 patches: [
39 {
40 find: &#039;:"SHOULD_LOAD");&#039;,
41 replacement: {
42 match: /\i(?:\?)?.getPreviewBanner\(\i,\i,\i\)(?=.{0,100}"COMPLETE")/,
43 replace: "$self.patchBannerUrl(arguments[0])||$&"
44
45 }
46 },
47 {
48 find: "\"data-selenium-video-tile\":",
49 predicate: () => settings.store.voiceBackground,
50 replacement: [
51 {
52 match: /(?<=function\((\i),\i\)\{)(?=let.{20,40},style:)/,
53 replace: "$1.style=$self.getVoiceBackgroundStyles($1);"
54 }
55 ]
56 },
57 {
58 find: &#039;"VideoBackground-web"&#039;,
59 predicate: () => settings.store.voiceBackground,
60 replacement: {
61 match: /backgroundColor:.{0,25},\{style:(?=\i\?)/,
62 replace: "$&$self.userHasBackground(arguments[0]?.userId)?null:",
63 }
64 }
65 ],
66
67 data: null as UsrbgApiReturn | null,
68
69 settingsAboutComponent: () => {
70 return (
71 <LinkButton href="https:class="ts-cmt">//github.com/AutumnVN/usrbg#how-to-request-your-own-usrbg-banner" variant="primary">
72 Get your own USRBG banner
73 </LinkButton>
74 );
75 },
76
77 getVoiceBackgroundStyles({ className, participantUserId }: any) {
78 if (className.includes("tile")) {
79 if (this.userHasBackground(participantUserId)) {
80 return {
81 backgroundImage: `url(${this.getImageUrl(participantUserId)})`,
82 backgroundSize: "cover",
83 backgroundPosition: "center",
84 backgroundRepeat: "no-repeat"
85 };
86 }
87 }
88 },
89
90 patchBannerUrl({ displayProfile }: any) {
91 if (displayProfile?.banner && settings.store.nitroFirst) return;
92 if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId);
93 },
94
95 userHasBackground(userId: string) {
96 return !!this.data?.users[userId];
97 },
98
99 getImageUrl(userId: string): string | null {
100 if (!this.userHasBackground(userId)) return null;
101
102 // We can assert that data exists because userHasBackground returned true
103 const { endpoint, bucket, prefix, users: { [userId]: etag } } = this.data!;
104 return `${endpoint}/${bucket}/${prefix}${userId}?${etag}`;
105 },
106
107 async start() {
108 const res = await fetch(API_URL);
109 if (res.ok) {
110 this.data = await res.json();
111 }
112 }
113});
114