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/crash/upvs/internal/protect"
11	"github.com/spf13/cobra"
12)
13
14var dateStr string
15
16var scanCmd = &cobra.Command{
17	Use:   "scan",
18	Short: "Enumerate events and create clip index",
19	Long:  "Scan a day's events from UniFi Protect and write clip_index.json.",
20	RunE:  runScan,
21}
22
23func init() {
24	scanCmd.Flags().StringVar(&dateStr, "date", "", "Target date YYYY-MM-DD (required)")
25	scanCmd.MarkFlagRequired("date")
26}
27
28func runScan(cmd *cobra.Command, args []string) error {
29	// Parse date
30	date, err := config.ParseDate(dateStr)
31	if err != nil {
32		return err
33	}
34	cfg.Date = date
35
36	// Validate required fields for scan
37	if cfg.Host == "" {
38		return config.ErrMissingHost
39	}
40	if cfg.Username == "" || cfg.Password == "" {
41		return config.ErrMissingCredentials
42	}
43	if cfg.Camera == "" {
44		return config.ErrMissingCamera
45	}
46	if cfg.OutDir == "" {
47		return config.ErrMissingOutDir
48	}
49
50	// Create layout and ensure directories
51	layout := output.NewLayout(cfg.OutDir, cfg.Camera, cfg.DateString())
52	err = layout.EnsureDirs()
53	if err != nil {
54		return err
55	}
56
57	// Create client
58	var opts []protect.ClientOption
59	if cfg.TLSInsecure {
60		opts = append(opts, protect.WithTLSInsecure())
61	}
62	if cfg.DirectAPI {
63		opts = append(opts, protect.WithDirectAPI())
64	}
65	client := protect.NewClient(cfg.Host, opts...)
66
67	// Login
68	ctx := context.Background()
69	err = client.Login(ctx, cfg.Username, cfg.Password)
70	if err != nil {
71		return fmt.Errorf("login: %w", err)
72	}
73
74	// Run scan
75	result, err := pipeline.Scan(ctx, client, layout, cfg.Camera, cfg.Date)
76	if err != nil {
77		return err
78	}
79
80	fmt.Printf("Scan complete: %d events for camera %s (%s)\n",
81		result.EventCount, result.Camera.Name, result.Camera.ID)
82	fmt.Printf("Clip index: %s\n", layout.ClipIndexPath())
83
84	return nil
85}