main
Raw Download raw file
 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}