main
1package cli
2
3import (
4 "context"
5 "fmt"
6
7 "github.com/crash/upvs/internal/config"
8 "github.com/crash/upvs/internal/output"
9 "github.com/crash/upvs/internal/pipeline"
10 "github.com/spf13/cobra"
11)
12
13var renderCmd = &cobra.Command{
14 Use: "render",
15 Short: "Generate timelapse video",
16 Long: "Render downloaded clips into a timelapse video using FFmpeg.",
17 RunE: runRender,
18}
19
20func init() {
21 renderCmd.Flags().StringVar(&dateStr, "date", "", "Target date YYYY-MM-DD (required)")
22 renderCmd.Flags().IntVar(&cfg.TargetSecs, "target", config.DefaultTargetSecs, "Target output duration in seconds")
23 renderCmd.Flags().IntVar(&cfg.FPS, "fps", config.DefaultFPS, "Output frame rate")
24 renderCmd.Flags().IntVar(&cfg.CRF, "crf", config.DefaultCRF, "FFmpeg CRF quality (0-51, lower=better)")
25 renderCmd.Flags().StringVar(&cfg.Preset, "preset", config.DefaultPreset, "FFmpeg preset (ultrafast to veryslow)")
26 renderCmd.MarkFlagRequired("date")
27}
28
29func runRender(cmd *cobra.Command, args []string) error {
30 // Parse date
31 date, err := config.ParseDate(dateStr)
32 if err != nil {
33 return err
34 }
35 cfg.Date = date
36
37 // Validate required fields
38 if cfg.Camera == "" {
39 return config.ErrMissingCamera
40 }
41 if cfg.OutDir == "" {
42 return config.ErrMissingOutDir
43 }
44
45 // Create layout
46 layout := output.NewLayout(cfg.OutDir, cfg.Camera, cfg.DateString())
47
48 // Run render
49 ctx := context.Background()
50 result, err := pipeline.Render(ctx, layout, pipeline.RenderConfig{
51 TargetSecs: cfg.TargetSecs,
52 FPS: cfg.FPS,
53 CRF: cfg.CRF,
54 Preset: cfg.Preset,
55 MinSpeedMult: cfg.MinSpeedMult,
56 MaxSpeedMult: cfg.MaxSpeedMult,
57 })
58 if err != nil {
59 return err
60 }
61
62 fmt.Printf("Render complete!\n")
63 fmt.Printf(" Output: %s\n", result.OutputPath)
64 fmt.Printf(" Speed factor: %.2fx\n", result.SpeedFactor)
65 fmt.Printf(" Duration: %.1f seconds\n", result.OutputDuration)
66 fmt.Printf(" Clips: %d/%d\n", result.Metadata.ValidClips, result.Metadata.TotalClips)
67
68 return nil
69}