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
+23
View File
@@ -51,6 +51,29 @@ func TestFSRoundTrip(t *testing.T) {
}
}
func TestFSOpen(t *testing.T) {
ctx := context.Background()
fs := newTestFS(t)
key := "objects/abc/original.mp4"
data := []byte("streamed video bytes")
if err := fs.Put(ctx, key, bytes.NewReader(data), int64(len(data)), "video/mp4"); err != nil {
t.Fatalf("put: %v", err)
}
rc, err := fs.Open(ctx, key)
if err != nil {
t.Fatalf("open: %v", err)
}
got, err := io.ReadAll(rc)
rc.Close()
if err != nil || !bytes.Equal(got, data) {
t.Fatalf("open read = %q err=%v, want %q", got, err, data)
}
if _, err := fs.Open(ctx, "objects/missing/original.mp4"); !errors.Is(err, ErrObjectNotFound) {
t.Fatalf("open missing err = %v, want ErrObjectNotFound", err)
}
}
func TestFSPathTraversalRejected(t *testing.T) {
ctx := context.Background()
fs := newTestFS(t)