feat: implement media echo fix and YouTube screenshare design

- Introduced a new `ScreenShareController` to manage YouTube screenshare functionality.
- Updated `DiscordPlayer` to track ownership of audio streams, preventing conflicts between music playback and screenshare.
- Added error handling for various states including voice connection checks and media busy states.
- Created unit tests for `ScreenShareController` and `DiscordPlayer` ownership rules to ensure correct functionality.
- Added documentation for the new media echo fix and screenshare design.
This commit is contained in:
MythEclipse
2026-05-16 15:48:28 +07:00
parent e32e092596
commit d50ce8698f
21 changed files with 2284 additions and 51 deletions

View File

@@ -14,7 +14,12 @@ function getHandler(
describe("createMediaRoutes", () => {
it("returns media status", async () => {
const controller = {
getState: vi.fn(() => ({ playing: false, current: null, queue: [] })),
getState: vi.fn(() => ({
playing: false,
activeMode: null,
current: null,
queue: [],
})),
queue: vi.fn(),
skip: vi.fn(),
stop: vi.fn(),
@@ -30,13 +35,14 @@ describe("createMediaRoutes", () => {
expect(json).toHaveBeenCalledWith({
playing: false,
activeMode: null,
current: null,
queue: [],
});
});
it("queues a source", async () => {
const state = { playing: true, current: null, queue: [] };
const state = { playing: true, activeMode: null, current: null, queue: [] };
const controller = {
getState: vi.fn(),
queue: vi.fn(async () => state),
@@ -58,10 +64,71 @@ describe("createMediaRoutes", () => {
expect(controller.queue).toHaveBeenCalledWith(
"https://example.com/song.mp3",
{ mode: "music" },
);
expect(json).toHaveBeenCalledWith(state);
});
it("queues a screen source", async () => {
const state = {
playing: true,
activeMode: "screen" as const,
current: null,
queue: [],
};
const controller = {
getState: vi.fn(),
queue: vi.fn(async () => state),
skip: vi.fn(),
stop: vi.fn(),
};
const handler = getHandler(
createMediaRoutes(controller),
"/media/queue",
"post",
);
const json = vi.fn();
await handler?.(
{ body: { source: "https://youtu.be/video", mode: "screen" } } as Request,
{ json } as unknown as Response,
vi.fn(),
);
expect(controller.queue).toHaveBeenCalledWith("https://youtu.be/video", {
mode: "screen",
});
expect(json).toHaveBeenCalledWith(state);
});
it("passes invalid mode errors to Express", async () => {
const controller = {
getState: vi.fn(),
queue: vi.fn(),
skip: vi.fn(),
stop: vi.fn(),
};
const handler = getHandler(
createMediaRoutes(controller),
"/media/queue",
"post",
);
const next = vi.fn();
await handler?.(
{
body: { source: "https://example.com/song.mp3", mode: "video" },
} as Request,
{ json: vi.fn() } as unknown as Response,
next,
);
expect(next.mock.calls[0][0]).toMatchObject({
code: "INVALID_MEDIA_MODE",
statusCode: 400,
});
});
it("passes missing source errors to Express", async () => {
const controller = {
getState: vi.fn(),