Skip to main content

screen_record/
cli.rs

1use std::path::PathBuf;
2
3use clap::{Parser, ValueEnum};
4
5#[derive(Debug, Clone, Parser)]
6#[command(
7    name = "screen-record",
8    version,
9    about = "Record a single window or display on macOS (12+) or Linux (X11/Wayland portal)."
10)]
11pub struct Cli {
12    /// Capture a single window screenshot and exit.
13    #[arg(long)]
14    pub screenshot: bool,
15
16    /// Use the system portal picker (Linux Wayland) instead of X11 selectors.
17    #[arg(long)]
18    pub portal: bool,
19
20    /// Print selectable windows as TSV and exit.
21    #[arg(long)]
22    pub list_windows: bool,
23
24    /// Print selectable displays as TSV and exit.
25    #[arg(long)]
26    pub list_displays: bool,
27
28    /// Print selectable apps as TSV and exit.
29    #[arg(long)]
30    pub list_apps: bool,
31
32    /// Check capture prerequisites (macOS permission or X11/ffmpeg availability) and exit.
33    #[arg(long)]
34    pub preflight: bool,
35
36    /// Best-effort permission request (macOS) or prerequisite check (X11), then exit.
37    #[arg(long)]
38    pub request_permission: bool,
39
40    /// Record a specific window id (from --list-windows).
41    #[arg(long, value_name = "id")]
42    pub window_id: Option<u32>,
43
44    /// Select a window by app/owner name (case-insensitive substring).
45    #[arg(long, value_name = "name")]
46    pub app: Option<String>,
47
48    /// Narrow --app selection by window title substring.
49    #[arg(long, value_name = "name", requires = "app")]
50    pub window_name: Option<String>,
51
52    /// Record the frontmost window on the current Space.
53    #[arg(long)]
54    pub active_window: bool,
55
56    /// Record the primary display.
57    #[arg(long)]
58    pub display: bool,
59
60    /// Record a specific display id (from --list-displays).
61    #[arg(long, value_name = "id")]
62    pub display_id: Option<u32>,
63
64    /// Record for N seconds.
65    #[arg(long, value_name = "seconds")]
66    pub duration: Option<u64>,
67
68    /// Control audio capture.
69    #[arg(long, value_enum, default_value_t = AudioMode::Off)]
70    pub audio: AudioMode,
71
72    /// Output file path.
73    #[arg(long, value_name = "path")]
74    pub path: Option<PathBuf>,
75
76    /// Write recording metadata JSON to this path.
77    #[arg(long, value_name = "path")]
78    pub metadata_out: Option<PathBuf>,
79
80    /// Write diagnostics manifest JSON and sidecar artifacts for recording mode.
81    #[arg(long, value_name = "path")]
82    pub diagnostics_out: Option<PathBuf>,
83
84    /// Explicit container selection. Overrides extension.
85    #[arg(long, value_enum)]
86    pub format: Option<ContainerFormat>,
87
88    /// Screenshot output image format. Overrides extension.
89    #[arg(long, value_enum)]
90    pub image_format: Option<ImageFormat>,
91
92    /// Output directory for screenshot mode when --path is omitted.
93    #[arg(long, value_name = "path")]
94    pub dir: Option<PathBuf>,
95
96    /// Skip publishing a new screenshot when the capture hash stays within threshold.
97    #[arg(long)]
98    pub if_changed: bool,
99
100    /// Optional baseline image path for --if-changed comparisons.
101    #[arg(long, value_name = "path", requires = "if_changed")]
102    pub if_changed_baseline: Option<PathBuf>,
103
104    /// Maximum allowed hash-distance bits before capture is considered changed.
105    #[arg(
106        long,
107        value_name = "bits",
108        value_parser = clap::value_parser!(u32).range(0..=64),
109        requires = "if_changed"
110    )]
111    pub if_changed_threshold: Option<u32>,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
115pub enum AudioMode {
116    Off,
117    System,
118    Mic,
119    Both,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
123pub enum ContainerFormat {
124    Mov,
125    Mp4,
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
129pub enum ImageFormat {
130    Png,
131    #[value(alias = "jpeg")]
132    Jpg,
133    Webp,
134}