From 7dedac2094232ec693803ea196e0a673f62611c6 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Sat, 16 May 2026 23:11:46 +0700 Subject: [PATCH] refactor: clean up code structure and improve error handling in media controllers --- frontend/index.html | 1 - frontend/src/App.tsx | 18 +++++++++----- .../src/components/messages/MessageCard.tsx | 2 +- frontend/src/hooks/useMessages.ts | 6 ++++- src/media/mediaController.ts | 24 +++++++++---------- src/media/screenShareController.ts | 16 +++++++++++-- 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index aebd286..07de5e2 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,7 +2,6 @@ - Discord Moderation Dashboard diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 62d8d1e..0d82e72 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -144,16 +144,22 @@ export default function App() { }, [isStreaming, startStreamingLocal, stopStreamingLocal, patchUIState]); useEffect(() => { - if (selectedVoiceGuild) voice.loadVoiceChannels(selectedVoiceGuild).catch(() => undefined); - }, [selectedVoiceGuild, voice.loadVoiceChannels]); + if (selectedVoiceGuild) { + voice.loadVoiceChannels(selectedVoiceGuild).catch(() => undefined); + } + }, [selectedVoiceGuild]); useEffect(() => { - if (selectedTextGuild) voice.loadTextTargets(selectedTextGuild).catch(() => undefined); - }, [selectedTextGuild, voice.loadTextTargets]); + if (selectedTextGuild) { + voice.loadTextTargets(selectedTextGuild).catch(() => undefined); + } + }, [selectedTextGuild]); useEffect(() => { - messages.fetchMessages(selectedTextChannel).catch(() => undefined); - }, [selectedTextChannel, messages.fetchMessages]); + if (selectedTextChannel) { + messages.fetchMessages(selectedTextChannel).catch(() => undefined); + } + }, [selectedTextChannel]); const toggleListening = useCallback(async () => { if (isListening) { diff --git a/frontend/src/components/messages/MessageCard.tsx b/frontend/src/components/messages/MessageCard.tsx index 0ecf916..2ae9b66 100644 --- a/frontend/src/components/messages/MessageCard.tsx +++ b/frontend/src/components/messages/MessageCard.tsx @@ -23,7 +23,7 @@ export function MessageCard({ message, onReanalyze }: MessageCardProps) {
diff --git a/frontend/src/hooks/useMessages.ts b/frontend/src/hooks/useMessages.ts index c56cf1a..efdbea7 100644 --- a/frontend/src/hooks/useMessages.ts +++ b/frontend/src/hooks/useMessages.ts @@ -18,11 +18,15 @@ export function useMessages() { const [error, setError] = useState(null); const fetchMessages = useCallback(async (channelId?: string) => { + if (!channelId) { + setMessages([]); + return []; + } setLoading(true); setError(null); try { const params = new URLSearchParams({ limit: "80" }); - if (channelId) params.set("channel", channelId); + params.set("channel", channelId); const result = await listMessages(params); setMessages(result.data); return result.data; diff --git a/src/media/mediaController.ts b/src/media/mediaController.ts index 7bdee4c..7b33ccd 100644 --- a/src/media/mediaController.ts +++ b/src/media/mediaController.ts @@ -52,9 +52,21 @@ export class MediaController { ): Promise { const mode = options.mode ?? "music"; if (mode === "screen") { + // Stop current music if any + this.playbackToken++; + this.playback?.stop(); + this.playback = null; return this.startScreen(source); } + // mode === "music" + // Stop screen if active + if (this.screenPlayback || this.dependencies.screenController?.isActive()) { + this.screenPlayback?.stop(); + this.screenPlayback = null; + this.activeMode = null; + } + this.assertCanStartMusic(); const resolved = await ( this.dependencies.resolveMediaSource ?? resolveMediaSource @@ -108,10 +120,6 @@ export class MediaController { ); } - if (this.screenPlayback || this.dependencies.screenController?.isActive()) { - throw new AppError("Another media mode is active", "MEDIA_BUSY", 409); - } - if (this.dependencies.isBrowserStreaming?.()) { throw new AppError( "Stop browser microphone streaming before playing media", @@ -122,14 +130,6 @@ export class MediaController { } private async startScreen(source: string): Promise { - if ( - this.screenPlayback || - this.dependencies.screenController?.isActive() || - this.playback || - this.queueStore.snapshot().current - ) { - throw new AppError("Another media mode is active", "MEDIA_BUSY", 409); - } const screenController = this.dependencies.screenController; if (!screenController) { throw new AppError( diff --git a/src/media/screenShareController.ts b/src/media/screenShareController.ts index f245467..5b2c3e9 100644 --- a/src/media/screenShareController.ts +++ b/src/media/screenShareController.ts @@ -6,7 +6,10 @@ import { Utils, } from "@dank074/discord-video-stream"; import { AppError } from "../errors"; +import { createChildLogger } from "../logger"; import { discordPlayer } from "../player"; + +const logger = createChildLogger("screen-share"); import type { DiscordPlayerOwner, ScreenSharePlayback } from "./mediaTypes"; import { createYtDlp } from "./ytdlp"; @@ -77,8 +80,8 @@ export function createScreenShareController( ); } - if (active || getPlayerOwner() !== "none") { - throw new AppError("Another media mode is active", "MEDIA_BUSY", 409); + if (active) { + active.stop(); } try { @@ -93,6 +96,15 @@ export function createScreenShareController( videoCodec: Utils.normalizeVideoCodec("H264"), }); + // Add FFmpeg error logging + if (command && "stderr" in command && (command as any).stderr) { + (command as any).stderr.on("data", (data: Buffer) => { + if (data.toString().includes("Error")) { + logger.error({ error: data.toString() }, "FFmpeg Screen Error"); + } + }); + } + let stopped = false; const done = playStream(output, dependencies.streamer, { type: "go-live",