use clap::{Parser, Subcommand, ValueEnum};
#[derive(Debug, Clone, ValueEnum)]
pub enum Format {
Srt,
Vtt,
Ass,
Ssa,
#[value(name = "microdvd")]
MicroDvd,
#[value(name = "subviewer")]
SubViewer,
}
impl Format {
pub fn from_ext(path: &str) -> Option<Self> {
let lower = path.to_lowercase();
if lower.ends_with(".srt") {
Some(Format::Srt)
} else if lower.ends_with(".vtt") {
Some(Format::Vtt)
} else if lower.ends_with(".ass") {
Some(Format::Ass)
} else if lower.ends_with(".ssa") {
Some(Format::Ssa)
} else if lower.ends_with(".sub") {
Some(Format::MicroDvd)
} else {
None
}
}
}
impl std::fmt::Display for Format {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Format::Srt => write!(f, "srt"),
Format::Vtt => write!(f, "vtt"),
Format::Ass => write!(f, "ass"),
Format::Ssa => write!(f, "ssa"),
Format::MicroDvd => write!(f, "microdvd"),
Format::SubViewer => write!(f, "subviewer"),
}
}
}
#[derive(Parser)]
#[command(name = "subtitler")]
#[command(about = "Subtitle toolkit: parse, convert, validate, and edit subtitles in SRT, WebVTT, and ASS/SSA formats.")]
#[command(version)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
Parse(ParseArgs),
Convert(ConvertArgs),
Validate(ValidateArgs),
Edit(EditArgs),
Info(InfoArgs),
Detect(DetectArgs),
}
#[derive(clap::Args)]
pub struct ParseArgs {
pub input: String,
#[arg(short, long)]
pub format: Option<Format>,
#[arg(short, long)]
pub json: bool,
}
#[derive(clap::Args)]
pub struct ConvertArgs {
pub input: String,
pub output: String,
#[arg(short, long)]
pub from: Option<Format>,
#[arg(short, long)]
pub to: Option<Format>,
#[arg(long)]
pub fps: Option<f64>,
#[arg(long, allow_hyphen_values = true)]
pub shift: Option<i64>,
}
#[derive(clap::Args)]
pub struct ValidateArgs {
pub input: String,
#[arg(long, default_value = "42")]
pub max_chars: usize,
#[arg(long, default_value = "5000")]
pub max_gap: u64,
#[arg(long, default_value = "25.0")]
pub max_cps: f64,
#[arg(long)]
pub basic: bool,
#[arg(short, long)]
pub json: bool,
}
#[derive(clap::Args)]
pub struct EditArgs {
pub input: String,
#[arg(short, long)]
pub output: String,
#[arg(long)]
pub sort: bool,
#[arg(long, allow_hyphen_values = true)]
pub shift: Option<i64>,
#[arg(long)]
pub merge: Option<u64>,
#[arg(long)]
pub split: Option<usize>,
#[arg(long, value_names = &["FROM_FPS", "TO_FPS"], number_of_values = 2)]
pub transform_fps: Option<Vec<f64>>,
#[arg(short, long)]
pub from: Option<Format>,
#[arg(short, long)]
pub to: Option<Format>,
}
#[derive(clap::Args)]
pub struct InfoArgs {
pub input: String,
}
#[derive(clap::Args)]
pub struct DetectArgs {
pub input: String,
}