diff --git a/internal/api/play.go b/internal/api/play.go index 94329ae..02ea645 100644 --- a/internal/api/play.go +++ b/internal/api/play.go @@ -245,8 +245,38 @@ type transcodeMachine struct { } // getTranscode: GET /api/transcode — the setting, and what every machine can encode on, -// asked of each now. +// asked of each now. ?only=selected asks only the chosen machine, for the device's name. func (s *Server) getTranscode(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Get("only") == "selected" { + c := s.transcodeChoice() + out := map[string]any{"selected": c} + if c != nil { + name := c.Device + ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) + defer cancel() + var devs []media.Device + if c.Node == "" { + caps, _ := s.thumbs.capsFor(ctx, false, false) + devs = media.Devices(caps) + } else if code, b, err := s.nodes.Do(ctx, c.Node, "GET", "/api/files/play-devices", nil, nil); err == nil && code == 200 { + var d struct{ Devices []media.Device } + _ = json.Unmarshal(b, &d) + devs = d.Devices + } + for _, d := range devs { + if d.ID == c.Device { + name = d.Name + } + } + host := c.Node + if host == "" { + host = s.hostName() + } + out["host"], out["name"] = host, name + } + jsonOK(w, 200, out) + return + } names := []string{""} if s.nodes != nil { names = append(names, s.nodes.Names()...) diff --git a/web/src/Files.tsx b/web/src/Files.tsx index 80f0027..2eb37bf 100644 --- a/web/src/Files.tsx +++ b/web/src/Files.tsx @@ -307,6 +307,9 @@ export default function Files({ onOpenInTerminal }: { onOpenInTerminal?: (cmd: s const [thumbs, setThumbs] = useState(null) const [listEl, setListEl] = useState(null) const near = useMemo(() => (listEl && previews ? new Near(listEl) : null), [listEl, previews]) + // Video previews are made on the Transcode device (Settings), wherever it is. + const [tc, setTc] = useState('') + useEffect(() => { api.transcodeSelected().then((t) => setTc(t.selected ? `videos on ${t.host}'s ${t.name} (Settings → Transcode device), images on this machine's CPU` : '')).catch(() => {}) }, []) const readThumbs = useCallback((refresh = false) => { api.thumbStatus(sudo, refresh).then(setThumbs).catch((e) => setThumbs({ ok: false, engine: '', summary: '', gpus: [], error: e instanceof Error ? e.message : 'failed', user: '', cache: { path: '', entries: 0, bytes: 0 } })) }, [sudo]) useEffect(() => { try { localStorage.setItem(PREVIEWS_KEY, previews ? '1' : '0') } catch { /* private mode */ } }, [previews]) useEffect(() => { if (previews) readThumbs(); else setThumbs(null) }, [previews, readThumbs]) @@ -409,7 +412,7 @@ export default function Files({ onOpenInTerminal }: { onOpenInTerminal?: (cmd: s
- + setQ(e.target.value)} /> diff --git a/web/src/api.ts b/web/src/api.ts index ca59890..b618a6e 100644 --- a/web/src/api.ts +++ b/web/src/api.ts @@ -298,6 +298,7 @@ export const api = { playStatus: (node: string, id: string) => req('GET', nodeAPI(node, `/api/files/play/${id}`), undefined, true), playStop: (node: string, id: string) => req('DELETE', nodeAPI(node, `/api/files/play/${id}`), undefined, true), transcode: () => req('GET', '/api/transcode', undefined, true), + transcodeSelected: () => req<{ selected: { node: string; device: string } | null; host?: string; name?: string }>('GET', '/api/transcode?only=selected', undefined, true), setTranscode: (node: string, device: string) => req('PUT', '/api/transcode', device ? { node, device } : {}, true), fileReadURL: (path: string, sudo: boolean) => apiPath(`/api/files/read?${q(path, sudo)}`), fileDownloadURL: (path: string, sudo: boolean) => apiPath(`/api/files/download?${q(path, sudo)}`),