Skip to content

Commit

Permalink
Add Custom Sounds
Browse files Browse the repository at this point in the history
  • Loading branch information
Cynosphere committed Jan 13, 2025
1 parent 2ac27f4 commit 89e5e6e
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/customSounds/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ExtensionWebpackModule, Patch } from "@moonlight-mod/types";

export const patches: Patch[] = [
{
find: '("sound has no duration"),',
replace: [
{
match: /(let \i=await fetch\()(\i\(\d+\)\("\.\/"\.concat\((\i),"\.mp3"\)\))/,
replacement: (_, start, url, soundName) =>
`const url=require("customSounds_replacer").default(${soundName})??${url};${start}url`
},
{
match: /new Audio;\i\.src=/,
replacement: `$&require("customSounds_replacer").default(this.name)??`
}
]
}
];

export const webpackModules: Record<string, ExtensionWebpackModule> = {
replacer: {},
settings: {
entrypoint: true,
dependencies: [
{ id: "react" },
{ ext: "spacepack", id: "spacepack" },
{ id: "discord/components/common/index" },
"intl:",
'"./discodo.mp3":'
]
}
};
21 changes: 21 additions & 0 deletions src/customSounds/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
"id": "customSounds",
"version": "1.0.0",
"meta": {
"name": "Custom Sounds",
"tagline": "Replace client sounds",
"description": "Do not use attachment URLs, they will not refresh.",
"authors": ["Cynosphere"],
"tags": ["chat"],
"source": "https://github.com/Cynosphere/moonlight-extensions"
},
"dependencies": ["spacepack"],
"settings": {
"sounds": {
"type": "custom",
"advice": "none"
}
},
"apiLevel": 2
}
34 changes: 34 additions & 0 deletions src/customSounds/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.customSounds-sound {
display: grid;
grid-template-columns: 0.6fr auto;
padding: 14px;
align-items: center;
font-weight: 500;
height: 80px;
box-sizing: border-box;

& > .customSounds-label {
display: flex;
flex-direction: column;
gap: 4px;
color: var(--header-primary);
line-height: 24px;
font-size: 16px;
font-weight: 500;

& > .inline {
width: fit-content;
padding: 0 0.2em;
margin: -0.2em 0;
border-radius: 4px;
font-size: 85%;
font-family: var(--font-code);
text-indent: 0;
text-indent: 0;
white-space: pre-wrap;
line-height: 1.125rem;
background: var(--background-secondary);
border: 1px solid var(--background-tertiary);
}
}
}
6 changes: 6 additions & 0 deletions src/customSounds/webpackModules/replacer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function getReplacement(name: string): string | undefined {
const sounds = moonlight.getConfigOption<Record<string, string>>("customSounds", "sounds") ?? {};
const sound = sounds[name];

return sound === "" ? undefined : sound;
}
126 changes: 126 additions & 0 deletions src/customSounds/webpackModules/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import React from "@moonlight-mod/wp/react";
import Moonbase from "@moonlight-mod/wp/moonbase_moonbase";
import type { CustomComponentProps } from "@moonlight-mod/types/coreExtensions/moonbase";
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";

const i18n = spacepack.findByCode("intl:")[0].exports;
const { FormDivider, Text, TextInput } = spacepack.require("discord/components/common/index");

const soundNames = spacepack
.findByCode('"./discodo.mp3":')[0]
.exports.keys()
.map((name: string) => name.replace("./", "").replace(".mp3", ""));

const soundStrings: Record<string, string> = {
call_ringing_beat: "Incoming Call (rare variant)",
clip_error: "Clip Failed",
clip_save: "Clip Saved",
discodo: "Discodo (start-up easter egg)",
message3: "Same-channel Message",
stage_waiting: "Stage waiting music",
vibing_wumpus: "Relax with Wumpus music"
};
moonlight.lunast.register({
name: "customSounds_NotificationSettings",
find: ".default.setNotifyMessagesInSelectedChannel,children:",
process({ id, ast }) {
const { traverse } = moonlight.lunast.utils;

traverse(ast, {
$: { scope: true },
ArrayExpression({ node }) {
if (
node &&
node.elements.some(
(obj) =>
obj &&
obj.type === "ObjectExpression" &&
obj.properties.some(
(prop) =>
prop &&
prop.type === "Property" &&
prop.key &&
prop.key.type === "Identifier" &&
prop.key.name === "label"
)
)
) {
for (const element of node!.elements) {
if (!element || element.type !== "ObjectExpression") continue;

const sound = element.properties.find(
(prop) => prop && prop.type === "Property" && prop.key.type === "Identifier" && prop.key.name === "sound"
)!;
if (sound == null) continue;

const label = element.properties.find(
(prop) => prop && prop.type === "Property" && prop.key.type === "Identifier" && prop.key.name === "label"
)!;

const name =
sound && sound.type === "Property" && sound.value && sound.value.type === "Literal"
? sound.value.value
: null;
if (name == null) continue;

const labelProp =
label &&
label.type === "Property" &&
label.value &&
label.value.type === "CallExpression" &&
label.value.arguments[0].type === "MemberExpression" &&
label.value.arguments[0].property;
if (!labelProp) continue;

const langKey =
labelProp.type === "Identifier" ? labelProp.name : labelProp.type === "Literal" ? labelProp.value : null;
if (langKey == null) continue;

soundStrings[name as string] = "intl:" + langKey;
}
}
}
});

return true;
}
});

function SoundSettings({ value = {}, setValue }: CustomComponentProps): React.ReactNode {
const elements = [];

for (const name of soundNames) {
let label = soundStrings[name];
if (label?.startsWith("intl:")) {
label = i18n.intl.string(i18n.t[label.replace("intl:", "")]);
}

elements.push(
<>
<div className="customSounds-sound">
<div className="customSounds-label">
{label != null ? <Text variant="text-md/normal">{label}</Text> : null}
<code className="inline">{name}</code>
</div>
<TextInput
value={value[name] ?? ""}
onChange={(newValue: string) => {
if (newValue === "") {
delete value[name];
} else {
value[name] = newValue;
}

setValue(value);
}}
/>
</div>
<FormDivider />
</>
);
}

return elements;
}

Moonbase.registerConfigComponent("customSounds", "sounds", SoundSettings);

0 comments on commit 89e5e6e

Please sign in to comment.