import { useRef } from "react"
import { useOnScreen } from "@/hooks/useOnScreen"
import { isRef, useArtifactUrl } from "@/lib/media"
import { cn } from "@/lib/utils"
import { useBoundValue } from "./dataContext"
import { config, text } from "./ui/core/config"
import type { WidgetProps } from "./widgets"
/**
* What a message's bytes look like: a frame, a clip, a segment.
*
* Media never travels as a message — the reference does. The bytes come down
* the socket in front of it where the engine is holding the frame in memory,
* and are fetched from the artifact store otherwise; either way this tile only
* asks for what it is drawing. A camera serving its own stream is still played
* from source: point `stream_url` at it and the browser does the work.
*/
export function MediaWidget({ widget }: WidgetProps) {
const cfg = config(widget)
return (
)
}
/**
* The tile's body, for anywhere a message's media is shown.
*
* Frames are asked for only while the tile is on screen, in a tab being
* looked at: a camera is only sent while somebody watches it, and a tile
* scrolled away or behind another tab is nobody. A clip keeps playing either
* way.
*/
export function MediaView({
message,
stream = "",
dtype = "",
fit = "cover",
autoplay = false,
label,
}: {
message: string
stream?: string
dtype?: string
fit?: "cover" | "contain"
autoplay?: boolean
label?: string
}) {
const box = useRef(null)
const shown = useOnScreen(box)
const live = useBoundValue(message || undefined)
const value = live?.value
const ref = isRef(value) ? value : null
const kind = (ref?.media_type ?? dtype).split("/")[0]
const playing = kind === "audio" || kind === "video"
const active = shown || playing
const url = useArtifactUrl(
active ? ref : null,
active ? message || undefined : undefined,
)
const objectFit = fit === "contain" ? "object-contain" : "object-cover"
const alt = label || ref?.name || message
return (
{body()}
)
function body() {
// A camera serving its own stream is played from source: the engine
// carries references at whatever rate the flow publishes them, which is
// not video.
if (stream && kind !== "audio") {
return (
)
}
if (!message && !stream) {
return