diff --git a/src/plugins/vcNarrator/index.tsx b/src/plugins/vcNarrator/index.tsx index 6e8e4bbf5e..cbf3fd9c21 100644 --- a/src/plugins/vcNarrator/index.tsx +++ b/src/plugins/vcNarrator/index.tsx @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import { Notifications } from "@api/index"; +import { showNotification } from "@api/Notifications"; import { Settings } from "@api/Settings"; import { ErrorCard } from "@components/ErrorCard"; import { Devs } from "@utils/constants"; @@ -148,13 +150,20 @@ function playSample(tempSettings: any, type: string) { const currentUser = UserStore.getCurrentUser(); const myGuildId = SelectedGuildStore.getGuildId(); + if (settings.notification) { + showNotification({ + title: "Voice Channel Sample", + body: formatText(settings[type + "Message"], currentUser.username, "general", (currentUser as any).globalName ?? currentUser.username, GuildMemberStore.getNick(myGuildId, currentUser.id) ?? currentUser.username) + }); + return; + } speak(formatText(settings[type + "Message"], currentUser.username, "general", (currentUser as any).globalName ?? currentUser.username, GuildMemberStore.getNick(myGuildId, currentUser.id) ?? currentUser.username), settings); } export default definePlugin({ name: "VcNarrator", description: "Announces when users join, leave, or move voice channels via narrator", - authors: [Devs.Ven], + authors: [Devs.Ven, Devs.ImLvna], reporterTestable: ReporterTestable.None, flux: { @@ -182,6 +191,13 @@ export default definePlugin({ const nickname = user && (GuildMemberStore.getNick(myGuildId, userId) ?? user); const channel = ChannelStore.getChannel(id).name; + if (Settings.plugins.VcNarrator.notification) { + showNotification({ + title: "Voice Channel", + body: formatText(template, user, channel, displayName, nickname) + }); + return; + } speak(formatText(template, user, channel, displayName, nickname)); // updateStatuses(type, state, isMe); @@ -194,6 +210,13 @@ export default definePlugin({ if (!s) return; const event = s.mute || s.selfMute ? "unmute" : "mute"; + if (Settings.plugins.VcNarrator.notification) { + showNotification({ + title: "Voice Channel", + body: formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", "") + }); + return; + } speak(formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", "")); }, @@ -203,147 +226,158 @@ export default definePlugin({ if (!s) return; const event = s.deaf || s.selfDeaf ? "undeafen" : "deafen"; - speak(formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", "")); - } - }, + if (Settings.plugins.VcNarrator.notification) { + showNotification({ + title: "Voice Channel", + body: formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", "") + }); + return; + speak(formatText(Settings.plugins.VcNarrator[event + "Message"], "", ChannelStore.getChannel(chanId).name, "", "")); + } + }, + + start() { + if (typeof speechSynthesis === "undefined" || speechSynthesis.getVoices().length === 0) { + new Logger("VcNarrator").warn( + "SpeechSynthesis not supported or no Narrator voices found. Thus, this plugin will not work. Check my Settings for more info" + ); + return; + } + + }, + + optionsCache: null as Record | null, + + get options() { + return this.optionsCache ??= { + notification: { + type: OptionType.BOOLEAN, + description: "Send Notifications instead of speaking", + default: false + }, + voice: { + type: OptionType.SELECT, + description: "Narrator Voice", + options: window.speechSynthesis?.getVoices().map(v => ({ + label: v.name, + value: v.voiceURI, + default: v.default + })) ?? [] + }, + volume: { + type: OptionType.SLIDER, + description: "Narrator Volume", + default: 1, + markers: [0, 0.25, 0.5, 0.75, 1], + stickToMarkers: false + }, + rate: { + type: OptionType.SLIDER, + description: "Narrator Speed", + default: 1, + markers: [0.1, 0.5, 1, 2, 5, 10], + stickToMarkers: false + }, + sayOwnName: { + description: "Say own name", + type: OptionType.BOOLEAN, + default: false + }, + latinOnly: { + description: "Strip non latin characters from names before saying them", + type: OptionType.BOOLEAN, + default: false + }, + joinMessage: { + type: OptionType.STRING, + description: "Join Message", + default: "{{USER}} joined" + }, + leaveMessage: { + type: OptionType.STRING, + description: "Leave Message", + default: "{{USER}} left" + }, + moveMessage: { + type: OptionType.STRING, + description: "Move Message", + default: "{{USER}} moved to {{CHANNEL}}" + }, + muteMessage: { + type: OptionType.STRING, + description: "Mute Message (only self for now)", + default: "{{USER}} Muted" + }, + unmuteMessage: { + type: OptionType.STRING, + description: "Unmute Message (only self for now)", + default: "{{USER}} unmuted" + }, + deafenMessage: { + type: OptionType.STRING, + description: "Deafen Message (only self for now)", + default: "{{USER}} deafened" + }, + undeafenMessage: { + type: OptionType.STRING, + description: "Undeafen Message (only self for now)", + default: "{{USER}} undeafened" + } + }; + }, + + settingsAboutComponent({ tempSettings: s }) { + const [hasVoices, hasEnglishVoices] = useMemo(() => { + const voices = speechSynthesis.getVoices(); + return [voices.length !== 0, voices.some(v => v.lang.startsWith("en"))]; + }, []); - start() { - if (typeof speechSynthesis === "undefined" || speechSynthesis.getVoices().length === 0) { - new Logger("VcNarrator").warn( - "SpeechSynthesis not supported or no Narrator voices found. Thus, this plugin will not work. Check my Settings for more info" + const types = useMemo( + () => Object.keys(Vencord.Plugins.plugins.VcNarrator.options!).filter(k => k.endsWith("Message")).map(k => k.slice(0, -7)), + [], ); - return; - } - }, - - optionsCache: null as Record | null, - - get options() { - return this.optionsCache ??= { - voice: { - type: OptionType.SELECT, - description: "Narrator Voice", - options: window.speechSynthesis?.getVoices().map(v => ({ - label: v.name, - value: v.voiceURI, - default: v.default - })) ?? [] - }, - volume: { - type: OptionType.SLIDER, - description: "Narrator Volume", - default: 1, - markers: [0, 0.25, 0.5, 0.75, 1], - stickToMarkers: false - }, - rate: { - type: OptionType.SLIDER, - description: "Narrator Speed", - default: 1, - markers: [0.1, 0.5, 1, 2, 5, 10], - stickToMarkers: false - }, - sayOwnName: { - description: "Say own name", - type: OptionType.BOOLEAN, - default: false - }, - latinOnly: { - description: "Strip non latin characters from names before saying them", - type: OptionType.BOOLEAN, - default: false - }, - joinMessage: { - type: OptionType.STRING, - description: "Join Message", - default: "{{USER}} joined" - }, - leaveMessage: { - type: OptionType.STRING, - description: "Leave Message", - default: "{{USER}} left" - }, - moveMessage: { - type: OptionType.STRING, - description: "Move Message", - default: "{{USER}} moved to {{CHANNEL}}" - }, - muteMessage: { - type: OptionType.STRING, - description: "Mute Message (only self for now)", - default: "{{USER}} Muted" - }, - unmuteMessage: { - type: OptionType.STRING, - description: "Unmute Message (only self for now)", - default: "{{USER}} unmuted" - }, - deafenMessage: { - type: OptionType.STRING, - description: "Deafen Message (only self for now)", - default: "{{USER}} deafened" - }, - undeafenMessage: { - type: OptionType.STRING, - description: "Undeafen Message (only self for now)", - default: "{{USER}} undeafened" + let errorComponent: React.ReactElement | null = null; + if (!hasVoices) { + let error = "No narrator voices found. "; + error += navigator.platform?.toLowerCase().includes("linux") + ? "Install speech-dispatcher or espeak and run Discord with the --enable-speech-dispatcher flag" + : "Try installing some in the Narrator settings of your Operating System"; + errorComponent = {error}; + } else if (!hasEnglishVoices) { + errorComponent = You don't have any English voices installed, so the narrator might sound weird; } - }; - }, - - settingsAboutComponent({ tempSettings: s }) { - const [hasVoices, hasEnglishVoices] = useMemo(() => { - const voices = speechSynthesis.getVoices(); - return [voices.length !== 0, voices.some(v => v.lang.startsWith("en"))]; - }, []); - - const types = useMemo( - () => Object.keys(Vencord.Plugins.plugins.VcNarrator.options!).filter(k => k.endsWith("Message")).map(k => k.slice(0, -7)), - [], - ); - - let errorComponent: React.ReactElement | null = null; - if (!hasVoices) { - let error = "No narrator voices found. "; - error += navigator.platform?.toLowerCase().includes("linux") - ? "Install speech-dispatcher or espeak and run Discord with the --enable-speech-dispatcher flag" - : "Try installing some in the Narrator settings of your Operating System"; - errorComponent = {error}; - } else if (!hasEnglishVoices) { - errorComponent = You don't have any English voices installed, so the narrator might sound weird; - } - return ( - - - You can customise the spoken messages below. You can disable specific messages by setting them to nothing - - - The special placeholders {"{{USER}}"}, {"{{DISPLAY_NAME}}"}, {"{{NICKNAME}}"} and {"{{CHANNEL}}"}{" "} - will be replaced with the user's name (nothing if it's yourself), the user's display name, the user's nickname on current server and the channel's name respectively - - {hasEnglishVoices && ( - <> - Play Example Sounds -
- {types.map(t => ( - - ))} -
- - )} - {errorComponent} -
- ); - } -}); + return ( + + + You can customise the spoken messages below. You can disable specific messages by setting them to nothing + + + The special placeholders {"{{USER}}"}, {"{{DISPLAY_NAME}}"}, {"{{NICKNAME}}"} and {"{{CHANNEL}}"}{" "} + will be replaced with the user's name (nothing if it's yourself), the user's display name, the user's nickname on current server and the channel's name respectively + + {hasEnglishVoices && ( + <> + Play Example Sounds +
+ {types.map(t => ( + + ))} +
+ + )} + {errorComponent} +
+ ); + } + });