312 |
313 |
314 |
315 |
316 |
317 |
324 |
325 |
326 |
327 | Search Sounds
328 | setSearchQuery(e)}
331 | placeholder="Search by name or ID"
332 | />
333 |
334 |
335 |
336 | {filteredSoundTypes.map(type => {
337 | const currentOverride = getOverride(type.id);
338 |
339 | return (
340 | {
345 |
346 | setOverride(type.id, currentOverride);
347 |
348 | if (currentOverride.enabled && currentOverride.selectedSound === "custom" && currentOverride.selectedFileId) {
349 | try {
350 | await ensureDataURICached(currentOverride.selectedFileId);
351 | } catch (error) {
352 | console.error(`[CustomSounds] Failed to cache data URI for ${type.id}:`, error);
353 | showToast("Error loading custom sound file");
354 | }
355 | }
356 |
357 | console.log(`[CustomSounds] Settings saved for ${type.id}:`, currentOverride);
358 | }}
359 | />
360 | );
361 | })}
362 |
363 |
364 | );
365 | }
366 | }
367 | });
368 |
369 | export function isOverriden(id: string): boolean {
370 | return !!getOverride(id)?.enabled;
371 | }
372 |
373 | export function findOverride(id: string): SoundOverride | null {
374 | const override = getOverride(id);
375 | return override?.enabled ? override : null;
376 | }
377 |
378 | export default definePlugin({
379 | name: "CustomSounds",
380 | description: "Customize Discord's sounds.",
381 | authors: [Devs.ScattrdBlade, Devs.TheKodeToad],
382 | patches: [
383 | {
384 | find: 'Error("could not play audio")',
385 | replacement: [
386 | {
387 | match: /(?<=new Audio;\i\.src=)\i\([0-9]+\)\("\.\/"\.concat\(this\.name,"\.mp3"\)\)/,
388 | replace: "(() => { const customUrl = $self.getCustomSoundURL(this.name); return customUrl || $& })()"
389 | },
390 | {
391 | match: /Math.min\(\i\.\i\.getOutputVolume\(\)\/100\*this\._volume/,
392 | replace: "$& * ($self.findOverride(this.name)?.volume ?? 100) / 100"
393 | }
394 | ]
395 | },
396 | {
397 | find: ".playWithListener().then",
398 | replacement: {
399 | match: /\i\.\i\.getSoundpack\(\)/,
400 | replace: '$self.isOverriden(arguments[0]) ? "classic" : $&'
401 | }
402 | }
403 | ],
404 | settings,
405 | findOverride,
406 | isOverriden,
407 | getCustomSoundURL,
408 | refreshDataURI,
409 | ensureDataURICached,
410 | debugCustomSounds,
411 | startAt: StartAt.Init,
412 |
413 | async start() {
414 | console.log("[CustomSounds] Plugin starting...");
415 |
416 | try {
417 | await preloadDataURIs();
418 | console.log("[CustomSounds] Startup complete");
419 | } catch (error) {
420 | console.error("[CustomSounds] Startup failed:", error);
421 | }
422 | }
423 | });
424 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | .vc-custom-sounds-card {
2 | padding: 1em 1em 0;
3 | }
4 |
5 | .vc-custom-sounds-id {
6 | color: var(--text-muted);
7 | }
8 |
9 | .vc-custom-sounds-upload {
10 | display: inline;
11 | }
12 |
13 | .vc-custom-sounds-seasonal-title {
14 | margin-top: 16px;
15 | padding-top: 8px;
16 | border-top: 1px solid var(--background-modifier-accent);
17 | }
18 |
19 | .vc-custom-sounds-sound-section {
20 | margin-bottom: 16px;
21 | }
22 |
23 | .vc-custom-sounds-url-input {
24 | width: 100%;
25 | padding: 8px;
26 | background: var(--input-background);
27 | border: none;
28 | border-radius: 3px;
29 | color: var(--text-normal);
30 | }
31 |
32 | .vc-custom-sounds-buttons {
33 | display: flex;
34 | gap: 8px;
35 | margin-bottom: 16px;
36 | }
37 |
38 | .vc-custom-sounds-search {
39 | margin-bottom: 16px;
40 | }
41 |
42 | .vc-custom-sounds-search input {
43 | width: 100%;
44 | padding: 8px;
45 | background: var(--input-background);
46 | border: none;
47 | border-radius: 3px;
48 | color: var(--text-normal);
49 | }
50 |
51 | .vc-custom-sounds-sounds-list {
52 | display: flex;
53 | flex-direction: column;
54 | gap: 16px;
55 | }
56 |
57 | .vc-custom-sounds-preview-controls {
58 | display: flex;
59 | }
60 |
--------------------------------------------------------------------------------
/types.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Vencord, a Discord client mod
3 | * Copyright (c) 2025 Vendicated and contributors
4 | * SPDX-License-Identifier: GPL-3.0-or-later
5 | */
6 |
7 | export interface SoundType {
8 | name: string;
9 | id: string;
10 | seasonal?: string[];
11 | }
12 |
13 | export interface SoundOverride {
14 | enabled: boolean;
15 | selectedSound: string;
16 | volume: number;
17 | useFile: boolean;
18 | selectedFileId?: string;
19 | }
20 |
21 | export interface SoundPlayer {
22 | loop(): void;
23 | play(): void;
24 | pause(): void;
25 | stop(): void;
26 | }
27 |
28 | export const seasonalSounds = {
29 | "halloween_call_calling": "https://canary.discord.com/assets/0950a7ea4f1dd037870b.mp3",
30 | "winter_call_calling": "https://canary.discord.com/assets/7b945e7be3f86c5b7c82.mp3",
31 | "halloween_call_ringing": "https://canary.discord.com/assets/1b883b366ae11a303b82.mp3",
32 | "winter_call_ringing": "https://canary.discord.com/assets/e087eb83aaa4c43a44bc.mp3",
33 | "call_ringing_beat": "https://canary.discord.com/assets/3b3a2f5f29b9cb656efb.mp3",
34 | "call_ringing_snow_halation": "https://canary.discord.com/assets/99b1d8a6fe0b95e99827.mp3",
35 | "call_ringing_snowsgiving": "https://canary.discord.com/assets/54527e70cf0ddaeff76f.mp3",
36 | "halloween_deafen": "https://canary.discord.com/assets/c4aedda3b528df50221c.mp3",
37 | "winter_deafen": "https://canary.discord.com/assets/9bb77985afdb60704817.mp3",
38 | "halloween_disconnect": "https://canary.discord.com/assets/ca7d2e46cb5a16819aff.mp3",
39 | "winter_disconnect": "https://canary.discord.com/assets/ec5d85405877c27caeda.mp3",
40 | "halloween_message1": "https://canary.discord.com/assets/e386c839fb98675c6a79.mp3",
41 | "halloween_mute": "https://canary.discord.com/assets/ee7fdadf4c714eed6254.mp3",
42 | "winter_mute": "https://canary.discord.com/assets/6d7616e08466ab9f1c6d.mp3",
43 | "halloween_undeafen": "https://canary.discord.com/assets/045e5b9608df1607e0cf.mp3",
44 | "winter_undeafen": "https://canary.discord.com/assets/fa8da1499894ecac36c7.mp3",
45 | "halloween_unmute": "https://canary.discord.com/assets/260c581568eacca03f7e.mp3",
46 | "winter_unmute": "https://canary.discord.com/assets/9dbfb1c211e3815cd7b1.mp3",
47 | "halloween_user_join": "https://canary.discord.com/assets/80cf806f45467a5898cd.mp3",
48 | "winter_user_join": "https://canary.discord.com/assets/badc42c2a9063b4a962c.mp3",
49 | "halloween_user_leave": "https://canary.discord.com/assets/f407ad88a1dc40541769.mp3",
50 | "winter_user_leave": "https://canary.discord.com/assets/ec3d9eaea30b33e16da6.mp3"
51 | } as const;
52 |
53 | export const soundTypes: readonly SoundType[] = [
54 | { name: "Activity End", id: "activity_end" },
55 | { name: "Activity Launch", id: "activity_launch" },
56 | { name: "Activity User Join", id: "activity_user_join" },
57 | { name: "Activity User Left", id: "activity_user_left" },
58 | { name: "ASMR Message", id: "asmr_message1" },
59 | { name: "Bit Message", id: "bit_message1" },
60 | { name: "Bop Message", id: "bop_message1" },
61 | { name: "Call Calling", id: "call_calling", seasonal: ["halloween_call_calling", "winter_call_calling"] },
62 | {
63 | name: "Call Ringing",
64 | id: "call_ringing",
65 | seasonal: [
66 | "halloween_call_ringing",
67 | "winter_call_ringing",
68 | "call_ringing_beat",
69 | "call_ringing_snow_halation",
70 | "call_ringing_snowsgiving"
71 | ]
72 | },
73 | { name: "Clip Error", id: "clip_error" },
74 | { name: "Clip Save", id: "clip_save" },
75 | { name: "DDR Down", id: "ddr-down" },
76 | { name: "DDR Left", id: "ddr-left" },
77 | { name: "DDR Right", id: "ddr-right" },
78 | { name: "DDR Up", id: "ddr-up" },
79 | { name: "Deafen", id: "deafen", seasonal: ["halloween_deafen", "winter_deafen"] },
80 | { name: "Discodo", id: "discodo" },
81 | { name: "Disconnect", id: "disconnect", seasonal: ["halloween_disconnect", "winter_disconnect"] },
82 | { name: "Ducky Message", id: "ducky_message1" },
83 | { name: "Hang Status Select", id: "hang_status_select" },
84 | { name: "Highfive Clap", id: "highfive_clap" },
85 | { name: "Highfive Whistle", id: "highfive_whistle" },
86 | { name: "Human Man", id: "human_man" },
87 | { name: "LoFi Message", id: "lofi_message1" },
88 | { name: "Mention 1", id: "mention1" },
89 | { name: "Mention 2", id: "mention2" },
90 | { name: "Mention 3", id: "mention3" },
91 | { name: "Message 1", id: "message1", seasonal: ["halloween_message1"] },
92 | { name: "Message 2", id: "message2" },
93 | { name: "Message 3", id: "message3" },
94 | { name: "Mute", id: "mute", seasonal: ["halloween_mute", "winter_mute"] },
95 | { name: "Overlay Unlock", id: "overlayunlock" },
96 | { name: "Poggermode Achievement", id: "poggermode_achievement_unlock" },
97 | { name: "Poggermode Applause", id: "poggermode_applause" },
98 | { name: "Poggermode Enabled", id: "poggermode_enabled" },
99 | { name: "Poggermode Message", id: "poggermode_message_send" },
100 | { name: "PTT Start", id: "ptt_start" },
101 | { name: "PTT Stop", id: "ptt_stop" },
102 | { name: "Reconnect", id: "reconnect" },
103 | { name: "Robot Man", id: "robot_man" },
104 | { name: "Stage Waiting", id: "stage_waiting" },
105 | { name: "Stream Ended", id: "stream_ended" },
106 | { name: "Stream Started", id: "stream_started" },
107 | { name: "Stream User Joined", id: "stream_user_joined" },
108 | { name: "Stream User Left", id: "stream_user_left" },
109 | { name: "Success", id: "success" },
110 | { name: "Undeafen", id: "undeafen", seasonal: ["halloween_undeafen", "winter_undeafen"] },
111 | { name: "Unmute", id: "unmute", seasonal: ["halloween_unmute", "winter_unmute"] },
112 | { name: "User Join", id: "user_join", seasonal: ["halloween_user_join", "winter_user_join"] },
113 | { name: "User Leave", id: "user_leave", seasonal: ["halloween_user_leave", "winter_user_leave"] },
114 | { name: "User Moved", id: "user_moved" },
115 | { name: "Vibing Wumpus", id: "vibing_wumpus" }
116 | ] as const;
117 |
118 | export function makeEmptyOverride(): SoundOverride {
119 | return {
120 | enabled: false,
121 | selectedSound: "default",
122 | volume: 100,
123 | useFile: false,
124 | selectedFileId: undefined
125 | };
126 | }
127 |
--------------------------------------------------------------------------------