From 484202e90dc1b6d9cecf0d06eee66b2929caae9f Mon Sep 17 00:00:00 2001 From: saopig1 <4x7sw862st@gmail.com> Date: Sat, 30 May 2026 14:44:28 +0800 Subject: [PATCH] feat(autopause): pure occupancy-decision function --- src/bot/auto-pause.test.ts | 29 +++++++++++++++++++++++++++++ src/bot/auto-pause.ts | 23 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/bot/auto-pause.test.ts create mode 100644 src/bot/auto-pause.ts diff --git a/src/bot/auto-pause.test.ts b/src/bot/auto-pause.test.ts new file mode 100644 index 0000000..15ab59e --- /dev/null +++ b/src/bot/auto-pause.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from "vitest"; +import { decideOccupancyAction } from "./auto-pause.js"; + +describe("decideOccupancyAction", () => { + it("pauses when empty while playing and enabled", () => { + expect(decideOccupancyAction("playing", false, true, 0)).toBe("pause"); + }); + it("does not pause when the feature is disabled", () => { + expect(decideOccupancyAction("playing", false, false, 0)).toBe("none"); + }); + it("does not pause when idle (nothing playing)", () => { + expect(decideOccupancyAction("idle", false, true, 0)).toBe("none"); + }); + it("does not pause when already paused", () => { + expect(decideOccupancyAction("paused", false, true, 0)).toBe("none"); + }); + it("resumes when re-populated and we auto-paused", () => { + expect(decideOccupancyAction("paused", true, true, 2)).toBe("resume"); + }); + it("does NOT resume a user-paused track on re-population", () => { + expect(decideOccupancyAction("paused", false, true, 2)).toBe("none"); + }); + it("does nothing when re-populated and already playing", () => { + expect(decideOccupancyAction("playing", false, true, 2)).toBe("none"); + }); + it("resume is independent of the enabled flag (we already auto-paused)", () => { + expect(decideOccupancyAction("paused", true, false, 1)).toBe("resume"); + }); +}); diff --git a/src/bot/auto-pause.ts b/src/bot/auto-pause.ts new file mode 100644 index 0000000..60f1223 --- /dev/null +++ b/src/bot/auto-pause.ts @@ -0,0 +1,23 @@ +export type PlayerStateName = "idle" | "playing" | "paused"; +export type OccupancyAction = "pause" | "resume" | "none"; + +/** + * Decide what auto-pause should do given channel occupancy. + * - empty (userCount <= 0): pause iff enabled and currently playing. + * - re-populated (userCount > 0): resume iff we previously auto-paused and are still paused. + * `autoPaused` distinguishes our auto-pause from a user pause, so user pauses are never resumed. + */ +export function decideOccupancyAction( + playerState: PlayerStateName, + autoPaused: boolean, + enabled: boolean, + userCount: number, +): OccupancyAction { + const empty = userCount <= 0; + if (empty) { + if (enabled && playerState === "playing") return "pause"; + return "none"; + } + if (autoPaused && playerState === "paused") return "resume"; + return "none"; +}