use std::path::PathBuf;
use clap::{Parser, Subcommand, ValueEnum};
use clap_complete::Shell;
#[derive(Parser)]
#[command(
name = "framesmith",
version,
about = "CLI util for controlling Samsung Frame TVs"
)]
pub struct HostlessCli {
#[command(subcommand)]
pub command: HostlessCommand,
#[arg(long, global = true)]
pub json: bool,
#[arg(short, long, global = true)]
pub verbose: bool,
}
#[derive(Subcommand)]
pub enum HostlessCommand {
Discover,
Completions {
shell: Option<Shell>,
},
}
#[derive(Subcommand)]
pub enum ServerCommand {
Start,
Stop,
Restart,
Status,
TailLogs,
}
#[derive(Parser)]
#[command(name = "framesmith", version, about = "Control Samsung Frame TVs")]
pub struct HostCli {
pub host: String,
#[command(subcommand)]
pub command: HostCommand,
#[arg(short = 't', long = "auth-token-file", global = true, default_value_os_t = default_token_path())]
pub auth_token_file: PathBuf,
#[arg(long, global = true, default_value_t = 5)]
pub timeout: u64,
#[arg(long, global = true)]
pub json: bool,
#[arg(short, long, global = true)]
pub verbose: bool,
#[arg(long, global = true)]
pub direct: bool,
}
fn default_token_path() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".framesmith")
.join("token")
}
#[derive(Subcommand)]
pub enum HostCommand {
Auth {
#[command(subcommand)]
sub: Option<AuthCommand>,
},
Info,
Art {
#[command(subcommand)]
sub: ArtCommand,
},
Display {
#[command(subcommand)]
sub: DisplayCommand,
},
Motion {
#[command(subcommand)]
sub: MotionCommand,
},
Remote {
button: RemoteButton,
},
Server {
#[command(subcommand)]
sub: ServerCommand,
},
}
#[derive(Clone, Subcommand)]
pub enum AuthCommand {
Verify,
Reset,
}
#[derive(Subcommand)]
pub enum ArtCommand {
List,
ShowInfo {
content_id: Option<String>,
},
Select {
content_id: String,
},
Upload {
file: PathBuf,
#[arg(long, conflicts_with = "replace_selected")]
select: bool,
#[arg(long, conflicts_with = "select")]
replace_selected: bool,
#[arg(long)]
canvas: Option<String>,
},
Delete {
#[arg(required = true)]
content_ids: Vec<String>,
},
Thumbnail {
content_id: String,
#[arg(short)]
o: PathBuf,
},
Favorite {
content_id: String,
state: OnOff,
},
Matte {
#[command(subcommand)]
sub: MatteCommand,
},
Filter {
#[command(subcommand)]
sub: FilterCommand,
},
Mode {
#[command(subcommand)]
sub: ModeCommand,
},
Slideshow {
#[command(subcommand)]
sub: SlideshowCommand,
},
}
#[derive(Subcommand)]
pub enum MatteCommand {
List,
Set {
content_id: String,
matte_id: String,
#[arg(long)]
portrait: Option<String>,
},
}
#[derive(Subcommand)]
pub enum FilterCommand {
List,
Set {
content_id: String,
filter_id: String,
},
}
#[derive(Subcommand)]
pub enum ModeCommand {
On,
Off,
Status,
}
#[derive(Subcommand)]
pub enum SlideshowCommand {
On {
#[arg(long)]
duration: Option<u64>,
#[arg(long)]
shuffle: bool,
#[arg(long)]
category: Option<SlideshowCategoryValue>,
},
Off,
Status,
Configure {
#[arg(long)]
duration: Option<u64>,
#[arg(long)]
shuffle: Option<OnOff>,
#[arg(long)]
category: Option<SlideshowCategoryValue>,
},
}
#[derive(Clone, ValueEnum)]
pub enum SlideshowCategoryValue {
MyPictures,
Favorites,
}
#[derive(Subcommand)]
pub enum DisplayCommand {
Brightness {
value: Option<u8>,
},
ColorTemp {
value: Option<i8>,
},
Rotation,
AutoBrightness {
state: OnOff,
},
}
#[derive(Subcommand)]
pub enum MotionCommand {
Timer {
value: MotionTimerValue,
},
Sensitivity {
value: MotionSensitivityValue,
},
}
#[derive(Clone, ValueEnum)]
pub enum MotionTimerValue {
Off,
#[value(name = "5")]
Min5,
#[value(name = "15")]
Min15,
#[value(name = "30")]
Min30,
#[value(name = "60")]
Min60,
#[value(name = "120")]
Min120,
#[value(name = "240")]
Min240,
}
#[derive(Clone, ValueEnum)]
pub enum MotionSensitivityValue {
Low,
Medium,
High,
}
#[derive(Clone, ValueEnum)]
pub enum OnOff {
On,
Off,
}
#[derive(Clone, ValueEnum)]
pub enum RemoteButton {
Power,
PowerOff,
Sleep,
Home,
Menu,
Source,
Enter,
Back,
Return,
Up,
Down,
Left,
Right,
VolUp,
VolDown,
Mute,
ChUp,
ChDown,
ChList,
Play,
Pause,
Stop,
Rewind,
FastForward,
Info,
Guide,
Tools,
Caption,
#[value(name = "0")]
Num0,
#[value(name = "1")]
Num1,
#[value(name = "2")]
Num2,
#[value(name = "3")]
Num3,
#[value(name = "4")]
Num4,
#[value(name = "5")]
Num5,
#[value(name = "6")]
Num6,
#[value(name = "7")]
Num7,
#[value(name = "8")]
Num8,
#[value(name = "9")]
Num9,
Red,
Green,
Yellow,
Blue,
Ambient,
PictureSize,
Hdmi1,
Hdmi2,
Hdmi3,
Hdmi4,
}
impl RemoteButton {
#[allow(dead_code)]
pub fn to_library_type(&self) -> framesmith::RemoteControlButton {
use framesmith::RemoteControlButton::*;
match self {
Self::Power => Power,
Self::PowerOff => PowerOff,
Self::Sleep => Sleep,
Self::Home => Home,
Self::Menu => Menu,
Self::Source => Source,
Self::Enter => Enter,
Self::Back => Back,
Self::Return => Return,
Self::Up => Up,
Self::Down => Down,
Self::Left => Left,
Self::Right => Right,
Self::VolUp => VolumeUp,
Self::VolDown => VolumeDown,
Self::Mute => Mute,
Self::ChUp => ChannelUp,
Self::ChDown => ChannelDown,
Self::ChList => ChannelList,
Self::Play => Play,
Self::Pause => Pause,
Self::Stop => Stop,
Self::Rewind => Rewind,
Self::FastForward => FastForward,
Self::Info => Info,
Self::Guide => Guide,
Self::Tools => Tools,
Self::Caption => Caption,
Self::Num0 => Number0,
Self::Num1 => Number1,
Self::Num2 => Number2,
Self::Num3 => Number3,
Self::Num4 => Number4,
Self::Num5 => Number5,
Self::Num6 => Number6,
Self::Num7 => Number7,
Self::Num8 => Number8,
Self::Num9 => Number9,
Self::Red => Red,
Self::Green => Green,
Self::Yellow => Yellow,
Self::Blue => Blue,
Self::Ambient => Ambient,
Self::PictureSize => PictureSize,
Self::Hdmi1 => Hdmi1,
Self::Hdmi2 => Hdmi2,
Self::Hdmi3 => Hdmi3,
Self::Hdmi4 => Hdmi4,
}
}
pub fn to_ipc_string(&self) -> &'static str {
match self {
Self::Power => "power",
Self::PowerOff => "power-off",
Self::Sleep => "sleep",
Self::Home => "home",
Self::Menu => "menu",
Self::Source => "source",
Self::Enter => "enter",
Self::Back => "back",
Self::Return => "return",
Self::Up => "up",
Self::Down => "down",
Self::Left => "left",
Self::Right => "right",
Self::VolUp => "vol-up",
Self::VolDown => "vol-down",
Self::Mute => "mute",
Self::ChUp => "ch-up",
Self::ChDown => "ch-down",
Self::ChList => "ch-list",
Self::Play => "play",
Self::Pause => "pause",
Self::Stop => "stop",
Self::Rewind => "rewind",
Self::FastForward => "fast-forward",
Self::Info => "info",
Self::Guide => "guide",
Self::Tools => "tools",
Self::Caption => "caption",
Self::Num0 => "0",
Self::Num1 => "1",
Self::Num2 => "2",
Self::Num3 => "3",
Self::Num4 => "4",
Self::Num5 => "5",
Self::Num6 => "6",
Self::Num7 => "7",
Self::Num8 => "8",
Self::Num9 => "9",
Self::Red => "red",
Self::Green => "green",
Self::Yellow => "yellow",
Self::Blue => "blue",
Self::Ambient => "ambient",
Self::PictureSize => "picture-size",
Self::Hdmi1 => "hdmi1",
Self::Hdmi2 => "hdmi2",
Self::Hdmi3 => "hdmi3",
Self::Hdmi4 => "hdmi4",
}
}
}
#[derive(Parser)]
#[command(name = "framesmith")]
pub struct CompletionCli {
#[command(subcommand)]
pub command: CompletionCommand,
}
#[derive(Subcommand)]
pub enum CompletionCommand {
Discover,
Completions {
shell: Option<Shell>,
},
Server {
#[command(subcommand)]
sub: ServerCommand,
},
Auth {
#[command(subcommand)]
sub: Option<AuthCommand>,
},
Info,
Art {
#[command(subcommand)]
sub: ArtCommand,
},
Display {
#[command(subcommand)]
sub: DisplayCommand,
},
Motion {
#[command(subcommand)]
sub: MotionCommand,
},
Remote {
button: RemoteButton,
},
}