feat(stream): report watch progress to API via HTTP Range tracking
Track the highest byte offset served by the stream server to estimate playback progress (0-100%). A WatchReporter goroutine sends progress to POST /api/internal/agent/watch-progress every 10s during streaming. - Add maxByteOffset + totalFileSize to StreamServer for Range tracking - Add FileSize() to fileProvider interface (all 3 providers) - New WatchReporter: periodic progress reporter tied to daemon context - New WatchProgressUpdate type with optional progress/position/duration - Wire reporter into all 3 stream paths (task stream, disk stream, active download stream)
This commit is contained in:
parent
932312fc56
commit
0dafeaa70d
8 changed files with 366 additions and 10 deletions
68
internal/engine/watch_reporter.go
Normal file
68
internal/engine/watch_reporter.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/torrentclaw/unarr/internal/agent"
|
||||
)
|
||||
|
||||
// WatchReporter periodically sends watch progress to the API based on
|
||||
// HTTP Range request tracking from the StreamServer.
|
||||
type WatchReporter struct {
|
||||
client *agent.Client
|
||||
server *StreamServer
|
||||
taskID string
|
||||
lastSentPct int // last progress percentage reported (0-100)
|
||||
}
|
||||
|
||||
// NewWatchReporter creates a reporter that tracks playback progress via Range offsets.
|
||||
func NewWatchReporter(client *agent.Client, server *StreamServer, taskID string) *WatchReporter {
|
||||
return &WatchReporter{
|
||||
client: client,
|
||||
server: server,
|
||||
taskID: taskID,
|
||||
}
|
||||
}
|
||||
|
||||
// Run reports watch progress every 10 seconds until the context is cancelled.
|
||||
// A final report is sent on shutdown using a short independent timeout.
|
||||
func (wr *WatchReporter) Run(ctx context.Context) {
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Final report on shutdown — use background context since parent is cancelled.
|
||||
finalCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
wr.sendReport(finalCtx)
|
||||
cancel()
|
||||
return
|
||||
case <-ticker.C:
|
||||
wr.sendReport(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wr *WatchReporter) sendReport(ctx context.Context) {
|
||||
pct, _ := wr.server.EstimatedProgress()
|
||||
if pct == 0 || pct == wr.lastSentPct {
|
||||
return
|
||||
}
|
||||
|
||||
wr.lastSentPct = pct
|
||||
update := agent.WatchProgressUpdate{
|
||||
TaskID: wr.taskID,
|
||||
Source: "range",
|
||||
Progress: &pct,
|
||||
}
|
||||
|
||||
reportCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if err := wr.client.ReportWatchProgress(reportCtx, update); err != nil {
|
||||
log.Printf("[%s] watch-progress: report failed: %v", wr.taskID[:8], err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue