feat(stream): serve /stream from a debrid HTTPS link (hueco #2/2a)
The daemon can now stream a session straight from a server-resolved debrid direct URL instead of disk/torrent, delivering the "play instantáneo cache-fast" promise for cache-confirmed torrents the user never downloaded. - debridFileProvider: an io.ReadSeekCloser over HTTP Range — network-free Seek, lazy GET on Read, reopen-on-seek, a HEAD up front for the size, and a URL-derived name so the served Content-Type is video/mp4 (not octet-stream) when the web's name lacks an extension. - OnStreamSession branches on StreamSession.DirectURL before the filePath checks (no local path, no ffmpeg), builds the provider in a goroutine (HEAD off the sync loop) and marks the session ready. - Bump 0.10.0 -> 0.11.0 as the debrid-stream floor the web gates on. Validated e2e against a real AllDebrid account: a cached mp4 plays 1080p in Chrome through the agent, including the high-offset seek for a non-faststart file's moov atom. 2b (HLS-from-URL for mkv/HEVC) + 2c (cache-fast preference + mid-stream fallback) remain.
This commit is contained in:
parent
292d5923cf
commit
b8d2b90370
6 changed files with 573 additions and 3 deletions
|
|
@ -566,6 +566,38 @@ func runDaemonStart() error {
|
|||
if playerSessionRegistry.has(sess.SessionID) {
|
||||
return // already running
|
||||
}
|
||||
|
||||
// Debrid direct-play (hueco #2 / 2a): the source has no local file — the
|
||||
// web resolved an HTTPS debrid link (cache-confirmed, browser-native
|
||||
// container) and the daemon streams /stream from it via ranged GETs.
|
||||
// Runs BEFORE the filePath checks (there is no local path) and needs no
|
||||
// ffmpeg. Provider setup does a HEAD, so hand it off to a goroutine to
|
||||
// keep the sync loop from blocking other pending actions; register the
|
||||
// session up front so a duplicate sync within the setup window is a
|
||||
// no-op (matches the HLS branch's handoff rationale).
|
||||
if sess.DirectURL != "" {
|
||||
playerSessionRegistry.add(sess.SessionID, func() { streamSrv.ClearFile() })
|
||||
go func() {
|
||||
bctx, cancel := context.WithTimeout(ctx, 15*time.Second)
|
||||
defer cancel()
|
||||
provider, perr := engine.NewDebridFileProvider(bctx, sess.DirectURL, sess.FileName, sess.FileSize)
|
||||
if perr != nil {
|
||||
playerSessionRegistry.remove(sess.SessionID)
|
||||
log.Printf("[stream %s] debrid provider failed: %v", agent.ShortID(sess.SessionID), perr)
|
||||
return
|
||||
}
|
||||
streamSrv.SetFile(provider, sess.TaskID)
|
||||
log.Printf("[stream %s] debrid direct-play: %s (%d bytes)",
|
||||
agent.ShortID(sess.SessionID), provider.FileName(), provider.FileSize())
|
||||
rctx, rcancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer rcancel()
|
||||
if err := agentClient.MarkSessionReady(rctx, sess.SessionID); err != nil {
|
||||
log.Printf("[stream %s] mark-ready failed: %v", agent.ShortID(sess.SessionID), err)
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
filePath := sess.FilePath
|
||||
if filePath == "" {
|
||||
log.Printf("[hls %s] rejected: empty file path", agent.ShortID(sess.SessionID))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package cmd
|
||||
|
||||
// Version is the CLI version. Overridden by goreleaser ldflags at release time.
|
||||
var Version = "0.10.0"
|
||||
var Version = "0.11.0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue