fix(stream): /critico review fixes for the sidecar cache
- ExtractSubtitlesVTTMulti: distrust output when ffmpeg is killed by signal (45-min timeout on a too-big remux) — a truncated WebVTT passed the len>0 check and got cached as a silently-incomplete track until the media mtime changed. Skip all output on signal-kill; keep it on a clean non-zero exit. - stream handlers: read the sidecar cache BEFORE the ffmpegPath guard so a pre-warmed sub/thumbnail still serves if ffmpeg was removed after the cache was filled. - scan: log when the prewarm is skipped because ffmpeg is unavailable (matches the daemon; CLAUDE.md wants bootstrap to log on every branch). - unexport sidecarDir/subtitleCachePath/thumbnailCachePath (no external callers). - prewarm: surface a sample error in the summary so a systemic ffmpeg failure is distinguishable from one corrupt file. - add unit tests: codec whitelist, cache paths, mtime freshness, atomic write, thumb-position dedup.
This commit is contained in:
parent
1c8cc1c409
commit
bc6f85bf39
6 changed files with 228 additions and 37 deletions
36
internal/library/prewarm_test.go
Normal file
36
internal/library/prewarm_test.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package library
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/torrentclaw/unarr/internal/library/mediainfo"
|
||||
)
|
||||
|
||||
func itemWithDuration(d float64) LibraryItem {
|
||||
return LibraryItem{
|
||||
FilePath: "/m/x.mkv",
|
||||
MediaInfo: &mediainfo.MediaInfo{Video: &mediainfo.VideoInfo{Duration: d}},
|
||||
}
|
||||
}
|
||||
|
||||
func TestThumbPositions(t *testing.T) {
|
||||
// Known duration → fractions (0.1/0.3/0.5/0.7/0.9) rounded to whole seconds.
|
||||
if got := thumbPositions(itemWithDuration(1000)); !reflect.DeepEqual(got, []float64{100, 300, 500, 700, 900}) {
|
||||
t.Errorf("dur=1000 → %v, want [100 300 500 700 900]", got)
|
||||
}
|
||||
|
||||
// Unknown duration (no video info) → fixed fallback offsets.
|
||||
if got := thumbPositions(itemWithDuration(0)); !reflect.DeepEqual(got, []float64{30, 120, 300, 600, 1200}) {
|
||||
t.Errorf("dur=0 → %v, want fallback", got)
|
||||
}
|
||||
if got := thumbPositions(LibraryItem{FilePath: "/m/x.mkv"}); !reflect.DeepEqual(got, []float64{30, 120, 300, 600, 1200}) {
|
||||
t.Errorf("nil MediaInfo → %v, want fallback", got)
|
||||
}
|
||||
|
||||
// Very short clip → multiple fractions round to the same second; deduped.
|
||||
// dur=2: round(0.2,0.6,1.0,1.4,1.8) = 0,1,1,1,2 → [0 1 2].
|
||||
if got := thumbPositions(itemWithDuration(2)); !reflect.DeepEqual(got, []float64{0, 1, 2}) {
|
||||
t.Errorf("dur=2 → %v, want [0 1 2] (deduped)", got)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue