use clap::{Parser, Subcommand, ValueEnum};
#[derive(Parser)]
#[command(
name = "suno",
version,
about = "Suno AI music generation CLI — v5.5 support"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub quiet: bool,
}
#[derive(Subcommand)]
pub enum Commands {
Generate(GenerateArgs),
Describe(DescribeArgs),
Lyrics(LyricsArgs),
Extend(ExtendArgs),
Concat(ConcatArgs),
Cover(CoverArgs),
Remaster(RemasterArgs),
Stems(StemsArgs),
Info(InfoArgs),
Persona(PersonaArgs),
List(ListArgs),
Search(SearchArgs),
Status(StatusArgs),
Download(DownloadArgs),
Delete(DeleteArgs),
Set(SetArgs),
Publish(PublishArgs),
TimedLyrics(TimedLyricsArgs),
Credits,
Models,
Auth(AuthArgs),
Config(ConfigArgs),
AgentInfo,
}
#[derive(clap::Args)]
pub struct GenerateArgs {
#[arg(short, long)]
pub title: Option<String>,
#[arg(long)]
pub tags: Option<String>,
#[arg(long)]
pub exclude: Option<String>,
#[arg(short, long, conflicts_with = "lyrics_file")]
pub lyrics: Option<String>,
#[arg(long)]
pub lyrics_file: Option<String>,
#[arg(short, long, default_value = "v5.5")]
pub model: ModelVersion,
#[arg(long)]
pub vocal: Option<VocalGender>,
#[arg(long)]
pub weirdness: Option<f64>,
#[arg(long)]
pub style_influence: Option<f64>,
#[arg(long)]
pub variation: Option<VariationCategory>,
#[arg(long)]
pub instrumental: bool,
#[arg(short, long)]
pub wait: bool,
#[arg(long)]
pub download: Option<String>,
#[arg(long)]
pub token: Option<String>,
#[arg(long)]
pub persona: Option<String>,
}
#[derive(clap::Args)]
pub struct DescribeArgs {
#[arg(short, long)]
pub prompt: String,
#[arg(long)]
pub tags: Option<String>,
#[arg(short, long, default_value = "v5.5")]
pub model: ModelVersion,
#[arg(long)]
pub vocal: Option<VocalGender>,
#[arg(long)]
pub weirdness: Option<f64>,
#[arg(long)]
pub style_influence: Option<f64>,
#[arg(long)]
pub instrumental: bool,
#[arg(short, long)]
pub wait: bool,
#[arg(long)]
pub download: Option<String>,
#[arg(long)]
pub persona: Option<String>,
}
#[derive(clap::Args)]
pub struct LyricsArgs {
#[arg(short, long)]
pub prompt: String,
}
#[derive(clap::Args)]
pub struct ExtendArgs {
pub clip_id: String,
#[arg(long)]
pub at: f64,
#[arg(long)]
pub lyrics: Option<String>,
#[arg(long)]
pub tags: Option<String>,
#[arg(short, long)]
pub wait: bool,
}
#[derive(clap::Args)]
pub struct ConcatArgs {
pub clip_id: String,
#[arg(short, long)]
pub wait: bool,
}
#[derive(clap::Args)]
pub struct CoverArgs {
pub clip_id: String,
#[arg(long)]
pub tags: Option<String>,
#[arg(short, long, default_value = "v5.5")]
pub model: ModelVersion,
#[arg(short, long)]
pub wait: bool,
#[arg(long)]
pub download: Option<String>,
}
#[derive(clap::Args)]
pub struct RemasterArgs {
pub clip_id: String,
#[arg(long, default_value = "v5.5")]
pub model: RemasterModel,
#[arg(short, long)]
pub wait: bool,
#[arg(long)]
pub download: Option<String>,
}
#[derive(clap::Args)]
pub struct InfoArgs {
pub id: String,
}
#[derive(clap::Args)]
pub struct PersonaArgs {
pub id: String,
}
#[derive(clap::Args)]
pub struct StemsArgs {
pub clip_id: String,
#[arg(short, long)]
pub wait: bool,
}
#[derive(clap::Args)]
pub struct ListArgs {
#[arg(short, long, default_value = "0")]
pub page: u32,
}
#[derive(clap::Args)]
pub struct SearchArgs {
pub query: String,
}
#[derive(clap::Args)]
pub struct DeleteArgs {
pub ids: Vec<String>,
#[arg(short = 'y', long)]
pub yes: bool,
}
#[derive(clap::Args)]
pub struct StatusArgs {
pub ids: Vec<String>,
}
#[derive(clap::Args)]
pub struct DownloadArgs {
pub ids: Vec<String>,
#[arg(short, long, default_value = ".")]
pub output: String,
#[arg(long)]
pub video: bool,
}
#[derive(clap::Args)]
pub struct SetArgs {
pub id: String,
#[arg(long)]
pub title: Option<String>,
#[arg(long)]
pub lyrics: Option<String>,
#[arg(long)]
pub lyrics_file: Option<String>,
#[arg(long)]
pub caption: Option<String>,
#[arg(long)]
pub remove_cover: bool,
}
#[derive(clap::Args)]
pub struct PublishArgs {
pub ids: Vec<String>,
#[arg(long)]
pub private: bool,
}
#[derive(clap::Args)]
pub struct TimedLyricsArgs {
pub id: String,
#[arg(long)]
pub lrc: bool,
}
#[derive(clap::Args)]
pub struct AuthArgs {
#[arg(long)]
pub login: bool,
#[arg(long)]
pub jwt: Option<String>,
#[arg(long)]
pub cookie: Option<String>,
#[arg(long)]
pub device: Option<String>,
}
#[derive(clap::Args)]
pub struct ConfigArgs {
#[command(subcommand)]
pub action: ConfigAction,
}
#[derive(Subcommand)]
pub enum ConfigAction {
Show,
Set { key: String, value: String },
Check,
}
#[derive(ValueEnum, Clone, Debug, Default)]
pub enum ModelVersion {
#[value(name = "v5.5")]
#[default]
V55,
#[value(name = "v5")]
V5,
#[value(name = "v4.5+")]
V45Plus,
#[value(name = "v4.5")]
V45,
#[value(name = "v4")]
V4,
#[value(name = "v3.5")]
V35,
#[value(name = "v3")]
V3,
#[value(name = "v2")]
V2,
}
impl ModelVersion {
pub fn to_api_key(&self) -> &'static str {
match self {
Self::V55 => "chirp-fenix",
Self::V5 => "chirp-crow",
Self::V45Plus => "chirp-bluejay",
Self::V45 => "chirp-auk",
Self::V4 => "chirp-v4",
Self::V35 => "chirp-v3-5",
Self::V3 => "chirp-v3-0",
Self::V2 => "chirp-v2-xxl-alpha",
}
}
pub fn display_name(&self) -> &'static str {
match self {
Self::V55 => "v5.5",
Self::V5 => "v5",
Self::V45Plus => "v4.5+",
Self::V45 => "v4.5",
Self::V4 => "v4",
Self::V35 => "v3.5",
Self::V3 => "v3",
Self::V2 => "v2",
}
}
}
#[derive(ValueEnum, Clone, Debug)]
pub enum VocalGender {
Male,
Female,
}
#[derive(ValueEnum, Clone, Debug)]
pub enum VariationCategory {
High,
Normal,
Subtle,
}
impl VariationCategory {
pub fn to_api_value(&self) -> &'static str {
match self {
Self::High => "high",
Self::Normal => "normal",
Self::Subtle => "subtle",
}
}
}
#[derive(ValueEnum, Clone, Debug, Default)]
pub enum RemasterModel {
#[value(name = "v5.5")]
#[default]
V55,
#[value(name = "v5")]
V5,
#[value(name = "v4.5+")]
V45Plus,
}
impl RemasterModel {
pub fn to_api_key(&self) -> &'static str {
match self {
Self::V55 => "chirp-flounder",
Self::V5 => "chirp-carp",
Self::V45Plus => "chirp-bass",
}
}
}