feat: add media queue foundation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-05-15 16:55:16 +07:00
co-authored by Claude Opus 4.7
parent ed438e6fc0
commit d42d3f8def
3 changed files with 166 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
import type {
MediaQueueItem,
MediaState,
ResolvedMediaSource,
} from "./mediaTypes";
export class MediaQueue {
private current: MediaQueueItem | null = null;
private readonly items: MediaQueueItem[] = [];
constructor(
private readonly createId = () => crypto.randomUUID(),
private readonly now = () => Date.now(),
) {}
add(source: ResolvedMediaSource, requestedBy = "dashboard"): MediaQueueItem {
const item: MediaQueueItem = {
id: this.createId(),
mode: "music",
requestedBy,
addedAt: this.now(),
status: "queued",
...source,
};
this.items.push(item);
return { ...item };
}
startNext(): MediaQueueItem | null {
if (this.current) return { ...this.current };
const next = this.items.shift();
if (!next) return null;
this.current = { ...next, status: "playing" };
return { ...this.current };
}
completeCurrent(): void {
this.current = null;
}
failCurrent(): void {
if (this.current) {
this.current = { ...this.current, status: "failed" };
}
this.current = null;
}
clear(): void {
this.current = null;
this.items.length = 0;
}
snapshot(): Pick<MediaState, "current" | "queue"> {
return {
current: this.current ? { ...this.current } : null,
queue: this.items.map((item) => ({ ...item })),
};
}
}
+40
View File
@@ -0,0 +1,40 @@
import type { Readable } from "node:stream";
export type MediaMode = "music" | "screen";
export type MediaSourceKind = "url" | "local";
export type MediaQueueItemStatus = "queued" | "playing" | "failed";
export interface ResolvedMediaSource {
source: string;
title: string;
kind: MediaSourceKind;
}
export interface MediaQueueItem extends ResolvedMediaSource {
id: string;
mode: MediaMode;
requestedBy: string;
addedAt: number;
status: MediaQueueItemStatus;
}
export interface MediaState {
playing: boolean;
current: MediaQueueItem | null;
queue: MediaQueueItem[];
}
export interface MusicPlayback {
done: Promise<void>;
stop(): void;
}
export interface MusicPlayer {
play(source: ResolvedMediaSource): MusicPlayback;
}
export interface DiscordAudioPlayer {
isConnected(): boolean;
playStream(stream: Readable): void;
stop(): void;
}