From c8d7c4bba5b473030d459dbe37e1ae726ddb46cf Mon Sep 17 00:00:00 2001 From: Deivid Soto Date: Sun, 31 May 2026 10:32:34 +0200 Subject: [PATCH] feat(stream): direct-play passthrough for browser-native files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hueco #3 / 3a (CLI side). StreamSession gains PlayMethod; when the web sends "direct", the daemon serves the raw file over /stream (HTTP Range, no ffmpeg) instead of transcoding to HLS — zero CPU, instant seek. Runs before the ffmpeg-availability check so direct-play works even with transcode disabled. Legacy/empty PlayMethod keeps the HLS path, so an old web that never sends "direct" is unaffected. --- internal/agent/types.go | 7 +++++++ internal/cmd/daemon.go | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/internal/agent/types.go b/internal/agent/types.go index d45b1b3..3a401f3 100644 --- a/internal/agent/types.go +++ b/internal/agent/types.go @@ -410,6 +410,13 @@ type StreamSession struct { // AudioIndex selects the source audio track (-map 0:a:N). -1 means // "use the default/first track". AudioIndex int `json:"audioIndex,omitempty"` + // PlayMethod is how the daemon should serve this session: + // "" — default (HLS transcode); also what legacy servers send. + // "direct" — the source is already browser-native (the web decided this + // from library scan metadata + an agent-version gate). Serve + // the raw file over /stream (HTTP Range, no ffmpeg) instead of + // transcoding to HLS. See hueco #3 phase 3a in the roadmap. + PlayMethod string `json:"playMethod,omitempty"` } // SyncResponse is returned by the server with all pending actions for the CLI. diff --git a/internal/cmd/daemon.go b/internal/cmd/daemon.go index a373d7b..11ccf0c 100644 --- a/internal/cmd/daemon.go +++ b/internal/cmd/daemon.go @@ -589,6 +589,30 @@ func runDaemonStart() error { filePath = found } + // Direct-play (hueco #3 / 3a): the web decided this source is already + // browser-native (mp4 h264/aac 8-bit SDR) from library scan metadata, + // gated on agent version. Serve the raw file over /stream (HTTP Range, + // no ffmpeg) instead of transcoding to HLS — zero CPU, instant seek. + // Runs BEFORE the ffmpeg-availability check on purpose: direct-play + // needs no ffmpeg, so it must work even when transcode is disabled. + if sess.PlayMethod == "direct" { + streamSrv.SetFile(engine.NewDiskFileProvider(filePath), sess.TaskID) + // cancel just clears the served file so daemon shutdown / drain + // stops exposing it on /stream. There's no ffmpeg child to kill. + playerSessionRegistry.add(sess.SessionID, func() { streamSrv.ClearFile() }) + log.Printf("[stream %s] direct-play: %s", agent.ShortID(sess.SessionID), filepath.Base(filePath)) + // File is on disk → ready immediately. Tell the web so the player + // attaches