refactor: clean up code structure and improve error handling in media controllers
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Discord Moderation Dashboard</title>
|
<title>Discord Moderation Dashboard</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -144,16 +144,22 @@ export default function App() {
|
|||||||
}, [isStreaming, startStreamingLocal, stopStreamingLocal, patchUIState]);
|
}, [isStreaming, startStreamingLocal, stopStreamingLocal, patchUIState]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedVoiceGuild) voice.loadVoiceChannels(selectedVoiceGuild).catch(() => undefined);
|
if (selectedVoiceGuild) {
|
||||||
}, [selectedVoiceGuild, voice.loadVoiceChannels]);
|
voice.loadVoiceChannels(selectedVoiceGuild).catch(() => undefined);
|
||||||
|
}
|
||||||
|
}, [selectedVoiceGuild]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedTextGuild) voice.loadTextTargets(selectedTextGuild).catch(() => undefined);
|
if (selectedTextGuild) {
|
||||||
}, [selectedTextGuild, voice.loadTextTargets]);
|
voice.loadTextTargets(selectedTextGuild).catch(() => undefined);
|
||||||
|
}
|
||||||
|
}, [selectedTextGuild]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (selectedTextChannel) {
|
||||||
messages.fetchMessages(selectedTextChannel).catch(() => undefined);
|
messages.fetchMessages(selectedTextChannel).catch(() => undefined);
|
||||||
}, [selectedTextChannel, messages.fetchMessages]);
|
}
|
||||||
|
}, [selectedTextChannel]);
|
||||||
|
|
||||||
const toggleListening = useCallback(async () => {
|
const toggleListening = useCallback(async () => {
|
||||||
if (isListening) {
|
if (isListening) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export function MessageCard({ message, onReanalyze }: MessageCardProps) {
|
|||||||
<article className="rounded-2xl border border-border bg-card p-4 shadow-sm">
|
<article className="rounded-2xl border border-border bg-card p-4 shadow-sm">
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<img
|
<img
|
||||||
src={message.avatar_url ?? "/default-avatar.png"}
|
src={message.avatar_url ?? "https://cdn.discordapp.com/embed/avatars/0.png"}
|
||||||
alt=""
|
alt=""
|
||||||
className="h-10 w-10 rounded-full object-cover"
|
className="h-10 w-10 rounded-full object-cover"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -18,11 +18,15 @@ export function useMessages() {
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const fetchMessages = useCallback(async (channelId?: string) => {
|
const fetchMessages = useCallback(async (channelId?: string) => {
|
||||||
|
if (!channelId) {
|
||||||
|
setMessages([]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams({ limit: "80" });
|
const params = new URLSearchParams({ limit: "80" });
|
||||||
if (channelId) params.set("channel", channelId);
|
params.set("channel", channelId);
|
||||||
const result = await listMessages(params);
|
const result = await listMessages(params);
|
||||||
setMessages(result.data);
|
setMessages(result.data);
|
||||||
return result.data;
|
return result.data;
|
||||||
|
|||||||
@@ -52,9 +52,21 @@ export class MediaController {
|
|||||||
): Promise<MediaState> {
|
): Promise<MediaState> {
|
||||||
const mode = options.mode ?? "music";
|
const mode = options.mode ?? "music";
|
||||||
if (mode === "screen") {
|
if (mode === "screen") {
|
||||||
|
// Stop current music if any
|
||||||
|
this.playbackToken++;
|
||||||
|
this.playback?.stop();
|
||||||
|
this.playback = null;
|
||||||
return this.startScreen(source);
|
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();
|
this.assertCanStartMusic();
|
||||||
const resolved = await (
|
const resolved = await (
|
||||||
this.dependencies.resolveMediaSource ?? resolveMediaSource
|
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?.()) {
|
if (this.dependencies.isBrowserStreaming?.()) {
|
||||||
throw new AppError(
|
throw new AppError(
|
||||||
"Stop browser microphone streaming before playing media",
|
"Stop browser microphone streaming before playing media",
|
||||||
@@ -122,14 +130,6 @@ export class MediaController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async startScreen(source: string): Promise<MediaState> {
|
private async startScreen(source: string): Promise<MediaState> {
|
||||||
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;
|
const screenController = this.dependencies.screenController;
|
||||||
if (!screenController) {
|
if (!screenController) {
|
||||||
throw new AppError(
|
throw new AppError(
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import {
|
|||||||
Utils,
|
Utils,
|
||||||
} from "@dank074/discord-video-stream";
|
} from "@dank074/discord-video-stream";
|
||||||
import { AppError } from "../errors";
|
import { AppError } from "../errors";
|
||||||
|
import { createChildLogger } from "../logger";
|
||||||
import { discordPlayer } from "../player";
|
import { discordPlayer } from "../player";
|
||||||
|
|
||||||
|
const logger = createChildLogger("screen-share");
|
||||||
import type { DiscordPlayerOwner, ScreenSharePlayback } from "./mediaTypes";
|
import type { DiscordPlayerOwner, ScreenSharePlayback } from "./mediaTypes";
|
||||||
import { createYtDlp } from "./ytdlp";
|
import { createYtDlp } from "./ytdlp";
|
||||||
|
|
||||||
@@ -77,8 +80,8 @@ export function createScreenShareController(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active || getPlayerOwner() !== "none") {
|
if (active) {
|
||||||
throw new AppError("Another media mode is active", "MEDIA_BUSY", 409);
|
active.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -93,6 +96,15 @@ export function createScreenShareController(
|
|||||||
videoCodec: Utils.normalizeVideoCodec("H264"),
|
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;
|
let stopped = false;
|
||||||
const done = playStream(output, dependencies.streamer, {
|
const done = playStream(output, dependencies.streamer, {
|
||||||
type: "go-live",
|
type: "go-live",
|
||||||
|
|||||||
Reference in New Issue
Block a user