diff --git a/plugins/Moyai/manifest.json b/plugins/Moyai/manifest.json new file mode 100644 index 0000000..c4533f7 --- /dev/null +++ b/plugins/Moyai/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "🗿", + "description": "🗿", + "authors": [ + { + "name": "Cynosphere", + "id": "150745989836308480" + }, + { + "name": "kmmiio99o", + "id": "879393496627306587" + } + ], + "main": "src/index.ts", + "vendetta": { + "icon": "ic_speaker" + } +} diff --git a/plugins/Moyai/src/index.ts b/plugins/Moyai/src/index.ts new file mode 100644 index 0000000..c710036 --- /dev/null +++ b/plugins/Moyai/src/index.ts @@ -0,0 +1,101 @@ +import { storage } from "@vendetta/plugin"; +import { findByStoreName } from "@vendetta/metro"; +import { ReactNative, FluxDispatcher } from "@vendetta/metro/common"; +import MoyaiSettings from "./settings"; + +const { DCDSoundManager } = ReactNative.NativeModules; +const SelectedChannelStore = findByStoreName("SelectedChannelStore"); + +const THUD_URL = + "https://raw.githubusercontent.com/Metastruct/garrysmod-chatsounds/master/sound/chatsounds/autoadd/memes/overused%20thud.ogg"; +const SOUND_ID = 6969; +let SOUND_DURATION = -1; + +const prepareSound = () => + new Promise((resolve) => { + try { + DCDSoundManager.prepare(THUD_URL, "media", SOUND_ID, (_, meta) => + resolve(meta) + ); + } catch { + resolve({ duration: 1000 }); + } + }); +let playingTimeout: ReturnType | null = null; +let playing = false; +async function playSound() { + try { + if (playing) { + if (playingTimeout != null) clearTimeout(playingTimeout); + DCDSoundManager.stop(SOUND_ID); + playing = false; + } + playing = true; + await DCDSoundManager.play(SOUND_ID); + playingTimeout = setTimeout(() => { + playing = false; + DCDSoundManager.stop(SOUND_ID); + playingTimeout = null; + }, SOUND_DURATION); + } catch { + playing = false; + } +} + +const moyaiRegex = /🗿|/gi; + +function onMessage(event) { + try { + if ( + event.message?.content && + event.channelId == SelectedChannelStore.getChannelId() && + !event.message.state + ) { + const matches = event.message.content.match(moyaiRegex); + if (matches) { + for (let i = 0; i < matches.length; i++) { + setTimeout(playSound, i * 350); + } + } + } + } catch { + // ignore + } +} + +function onReaction(event) { + try { + if ( + (storage.allowReactions ?? true) && + event.channelId == SelectedChannelStore.getChannelId() && + !event.optimistic + ) { + const name = event.emoji?.name; + if (name === "🗿" || (name && /moy?ai/i.test(name))) { + playSound(); + } + } + } catch { + // ignore + } +} + +let soundPrepared = false; + +export default { + onLoad: () => { + if (!soundPrepared) { + prepareSound().then((meta: Record) => { + soundPrepared = true; + SOUND_DURATION = meta.duration; + }); + } + FluxDispatcher.subscribe("MESSAGE_CREATE", onMessage); + FluxDispatcher.subscribe("MESSAGE_REACTION_ADD", onReaction); + }, + onUnload: () => { + FluxDispatcher.unsubscribe("MESSAGE_CREATE", onMessage); + FluxDispatcher.unsubscribe("MESSAGE_REACTION_ADD", onReaction); + }, + settings: MoyaiSettings, +}; diff --git a/plugins/Moyai/src/settings.tsx b/plugins/Moyai/src/settings.tsx new file mode 100644 index 0000000..655c58d --- /dev/null +++ b/plugins/Moyai/src/settings.tsx @@ -0,0 +1,32 @@ +import { plugin } from "@vendetta"; +import { findByProps } from "@vendetta/metro"; +import { React } from "@vendetta/metro/common"; + +const { ScrollView } = findByProps("ScrollView"); +const { TableRowGroup, TableSwitchRow, Stack } = findByProps( + "TableSwitchRow", + "TableRowGroup", + "Stack", +); + +export default function MoyaiSettings() { + const [, forceUpdate] = React.useReducer((x: number) => ~x, 0); + + return ( + + + + { + plugin.storage.allowReactions = v; + forceUpdate(); + }} + /> + + + + ); +}