2026-07-27 21:54:31 +07:00
|
|
|
import { useEffect } from "react";
|
2026-08-01 09:19:39 +07:00
|
|
|
import useSWR, { useSWRConfig } from "swr";
|
|
|
|
|
import { useAction } from "@/hooks/use-action";
|
2026-07-27 21:54:31 +07:00
|
|
|
import { mediaApi } from "@/lib/api";
|
2026-07-26 16:14:32 +07:00
|
|
|
import type { MediaState } from "@/lib/types";
|
2026-07-27 21:54:31 +07:00
|
|
|
import type { WsHook } from "@/lib/ws-hook";
|
2026-07-26 16:14:32 +07:00
|
|
|
|
2026-08-01 09:19:39 +07:00
|
|
|
const MEDIA_KEY = ["media-state"] as const;
|
|
|
|
|
|
2026-08-07 10:44:03 +07:00
|
|
|
export function useMediaState(initialData?: MediaState) {
|
2026-08-01 09:19:39 +07:00
|
|
|
return useSWR<MediaState>(MEDIA_KEY, () => mediaApi.getStatus(), {
|
|
|
|
|
refreshInterval: 10_000,
|
|
|
|
|
shouldRetryOnError: false,
|
2026-08-07 10:44:03 +07:00
|
|
|
fallbackData: initialData,
|
2026-08-01 09:19:39 +07:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function useMediaAction<TArgs>(fn: (args: TArgs) => Promise<MediaState>) {
|
|
|
|
|
const { mutate } = useSWRConfig();
|
|
|
|
|
return useAction(fn, {
|
|
|
|
|
onSuccess: (data) => {
|
|
|
|
|
void mutate(MEDIA_KEY, data, { revalidate: false });
|
|
|
|
|
},
|
2026-07-26 16:55:20 +07:00
|
|
|
});
|
2026-07-26 16:14:32 +07:00
|
|
|
}
|
|
|
|
|
|
2026-07-26 16:55:20 +07:00
|
|
|
export function useMediaQueue() {
|
2026-08-01 22:09:02 +07:00
|
|
|
return useMediaAction((input: { url: string; mode?: "music" | "screen" }) =>
|
|
|
|
|
mediaApi.queue(input.url, input.mode ?? "music"),
|
2026-08-01 11:36:40 +07:00
|
|
|
);
|
2026-07-26 16:55:20 +07:00
|
|
|
}
|
2026-07-26 16:14:32 +07:00
|
|
|
|
2026-07-26 16:55:20 +07:00
|
|
|
export function useMediaSkip() {
|
2026-08-01 09:19:39 +07:00
|
|
|
return useMediaAction(() => mediaApi.skip());
|
2026-07-26 16:55:20 +07:00
|
|
|
}
|
2026-07-26 16:14:32 +07:00
|
|
|
|
2026-07-26 16:55:20 +07:00
|
|
|
export function useMediaStop() {
|
2026-08-01 09:19:39 +07:00
|
|
|
return useMediaAction(() => mediaApi.stop());
|
2026-07-26 16:55:20 +07:00
|
|
|
}
|
2026-07-26 16:14:32 +07:00
|
|
|
|
2026-08-07 14:53:37 +07:00
|
|
|
export function useMediaLoop() {
|
|
|
|
|
return useMediaAction((loop: boolean) => mediaApi.loop(loop));
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-26 16:55:20 +07:00
|
|
|
/** Subscribe to WS media_state events to keep cache fresh */
|
|
|
|
|
export function useMediaWsSync(ws: WsHook) {
|
2026-08-01 09:19:39 +07:00
|
|
|
const { mutate } = useSWRConfig();
|
2026-07-26 16:46:53 +07:00
|
|
|
useEffect(() => {
|
2026-07-26 16:55:20 +07:00
|
|
|
const unsub = ws.on("media_state", (data) => {
|
2026-08-01 09:19:39 +07:00
|
|
|
void mutate(MEDIA_KEY, data as MediaState, { revalidate: false });
|
2026-07-26 16:55:20 +07:00
|
|
|
});
|
|
|
|
|
return unsub;
|
2026-08-01 09:19:39 +07:00
|
|
|
}, [ws, mutate]);
|
2026-07-26 16:14:32 +07:00
|
|
|
}
|