feat(video): add video upload with remux/transcode playback

Add video as a media kind in photos: streaming upload with per-kind
limits, ffprobe metadata, poster frame reusing the image variant
pipeline, and a playback object (remux when web-compatible, else
h264/yuv420p/aac transcode). Video jobs run on a separate pool with a
long lease. Frontend gains a video viewer, grid badge/duration and
video upload.
This commit is contained in:
iu
2026-10-11 20:37:53 +03:00
parent d059d042f0
commit d38ede0201
52 changed files with 2717 additions and 82 deletions
+24
View File
@@ -7,7 +7,9 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
"galo/internal/config"
"galo/internal/storage"
"galo/internal/video"
)
func TestWorkerGeneratesVariantsAndCollects(t *testing.T) {
@@ -140,6 +142,28 @@ func TestWorkerConcurrencySequentialAtOne(t *testing.T) {
}
}
func TestProcessVideoJobsSkipsWithoutTools(t *testing.T) {
// With no toolchain the video pass must return before touching the store,
// so a nil service is safe here.
w := NewWorker(&Service{}, time.Second, 10, time.Minute, 2)
w.processVideoJobs(context.Background())
}
func TestSetVideoConfiguresPool(t *testing.T) {
tools := video.Detect(config.Video{FFmpegPath: "definitely-missing-xyz", FFprobePath: "definitely-missing-xyz"})
w := &Worker{}
w.SetVideo(tools, 2)
if w.videoConc != 2 {
t.Fatalf("video concurrency = %d, want 2", w.videoConc)
}
if w.videoLease != videoJobLease {
t.Fatalf("video lease = %v, want %v", w.videoLease, videoJobLease)
}
if tools.Available() {
t.Fatal("missing toolchain should be unavailable")
}
}
func countObjects(t *testing.T, ctx context.Context, pool *pgxpool.Pool, ids []string) int {
t.Helper()
var n int