import { useEffect, useRef } from "react"; import beepSound from "../../assets/sound.wav"; import type { Network, Particle, StreamProperties } from "@/api/types"; import { apiClient } from "@/api/client"; import { useAuthStore } from "@/stores/auth-store"; import { useAutoplayStore } from "@/stores/autoplay-store"; import { resolveHumanDisplay } from "@/lib/humans"; import { logError } from "@/lib/errors"; /** * Triggers autoplay when a stream's latest child changes to a new media particle. * Plays a beep sound for new text particles from other users. * Sends autoplay data to the separate autoplay window via IPC. */ export function useStreamAutoplay( latestChild: Particle | null, streamParticle: Particle & { type: "stream"; properties: StreamProperties }, networkId: string, network: Network | undefined, ) { const userId = useAuthStore((s) => s.user?.id) ?? ""; const settledIdRef = useRef(undefined); useEffect(() => { if (!latestChild) return; // First real value: record as baseline, don't autoplay if (settledIdRef.current === undefined) { settledIdRef.current = latestChild.id; return; } if (latestChild.id === settledIdRef.current) return; settledIdRef.current = latestChild.id; if (latestChild.created_by_human_id === userId) return; if (useAutoplayStore.getState().muted) return; if (latestChild.type === "text") { // Browser autoplay policy can block this before user interaction; that's // fine — the beep is a nice-to-have, not a critical signal. new Audio(beepSound).play().catch((err) => logError(err, { scope: "autoplay.beep" }), ); return; } if (latestChild.type !== "media") return; const particle = latestChild; const { displayName, initials } = resolveHumanDisplay( particle.created_by_human_id, network?.humans, ); apiClient.getParticleDownloadUrl(particle.properties.object_id).then((downloadUrl) => { window.electronAutoplay.play({ particleId: particle.id, streamId: streamParticle.id, networkId, downloadUrl, mimeType: particle.properties.mime_type, durationMs: particle.properties.duration_ms, senderName: displayName, senderInitials: initials, }); }).catch((err) => logError(err, { scope: "autoplay.fetchUrl", particleId: particle.id }), ); }, [latestChild?.id]); // eslint-disable-line react-hooks/exhaustive-deps }