Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use clap::{Parser, Subcommand};

use crate::commands::asset::AssetArgs;
use crate::commands::project::ProjectArgs;
use crate::commands::upload::UploadArgs;

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -42,6 +43,7 @@ pub struct Cli {
#[derive(Subcommand, Debug)]
pub enum Command {
Asset(AssetArgs),
Project(ProjectArgs),
Upload(UploadArgs),
}

Expand Down
4 changes: 4 additions & 0 deletions src/commands/asset/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use clap::{Args, Subcommand};

mod list;
mod set_anonymous_read;

pub use list::{run as list_run, ListArgs};
pub use set_anonymous_read::{run as set_anonymous_read_run, SetAnonymousReadArgs};

#[derive(Args, Debug)]
pub struct AssetArgs {
Expand All @@ -13,5 +15,7 @@ pub struct AssetArgs {
#[derive(Subcommand, Debug)]
pub enum AssetCommand {
List(ListArgs),
/// Set anonymous read permission for an asset (allow unauthenticated read).
SetAnonymousRead(SetAnonymousReadArgs),
}

60 changes: 60 additions & 0 deletions src/commands/asset/set_anonymous_read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use clap::Args;
use tellers_api_client::models::AssetVisibilityRequest;

use crate::commands::api_config;

#[derive(Args, Debug)]
pub struct SetAnonymousReadArgs {
/// Asset ID to set anonymous read for
pub asset_id: String,

/// Set anonymous read to true or false (default: true).
#[arg(long, default_value_t = true, value_parser = clap::value_parser!(bool))]
pub allow: bool,

#[arg(long, env = "TELLERS_API_KEY", hide = true)]
pub api_key: Option<String>,

#[arg(long, env = "TELLERS_AUTH_BEARER", hide = true)]
pub auth_bearer: Option<String>,
}

pub fn run(args: SetAnonymousReadArgs) -> Result<(), String> {
let base = api_config::get_api_base();
let api_key = api_config::get_api_key(args.api_key)?;
let bearer = api_config::get_bearer_header(args.auth_bearer);

let url = format!(
"{}/asset/{}/visibility",
base.trim_end_matches('/'),
args.asset_id
);
let body = AssetVisibilityRequest::new(args.allow);

tokio::runtime::Runtime::new()
.map_err(|e| format!("failed to start runtime: {}", e))?
.block_on(async move {
let client = reqwest::Client::new();
let mut req = client
.put(&url)
.json(&body)
.header("x-api-key", &api_key);
if let Some(ref b) = bearer {
req = req.header("authorization", b);
}
let resp = req.send().await.map_err(|e| format!("request failed: {}", e))?;
let status = resp.status();
if !status.is_success() {
let text = resp.text().await.unwrap_or_default();
return Err(format!(
"set_anonymous_read failed; http_status: {}; response: {}",
status, text
));
}
println!(
"anonymous_read set to {} for asset {}",
args.allow, args.asset_id
);
Ok(())
})
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod api_config;
pub mod asset;
pub mod prompt;
pub mod project;
pub mod upload;
92 changes: 92 additions & 0 deletions src/commands/project/export.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use clap::Args;
use tellers_api_client::apis::accepts_api_key_api as api;

use crate::commands::api_config;

#[derive(Args, Debug)]
pub struct ExportArgs {
/// Project ID to export
#[arg(value_name = "PROJECT_ID")]
pub project_id: String,

/// Renditions to export (360p, 480p, 720p, 1080p, 1440p, 4k). Default 1080p when omitted.
#[arg(long = "rendition", short = 'r', value_name = "RESOLUTION")]
pub renditions: Vec<String>,

#[arg(long, env = "TELLERS_API_KEY")]
pub api_key: Option<String>,

#[arg(long, env = "TELLERS_AUTH_BEARER")]
pub auth_bearer: Option<String>,
}

const ALLOWED_RENDITIONS: &[&str] = &["360p", "480p", "720p", "1080p", "1440p", "4k"];

fn parse_rendition(s: &str) -> Result<String, String> {
let v = s.trim().to_lowercase();
if ALLOWED_RENDITIONS.contains(&v.as_str()) {
Ok(v)
} else {
Err(format!(
"Invalid rendition '{}'; allowed: {}",
s,
ALLOWED_RENDITIONS.join(", ")
))
}
}

pub fn run(args: ExportArgs) -> Result<(), String> {
let cfg = api_config::create_config();
let api_key = api_config::get_api_key(args.api_key)?;
let bearer_header = api_config::get_bearer_header(args.auth_bearer);

let rendition_strs: Vec<String> = if args.renditions.is_empty() {
vec!["1080p".to_string()]
} else {
args.renditions
.iter()
.flat_map(|s| s.split(',').map(|s| s.trim().to_string()))
.filter(|s| !s.is_empty())
.collect()
};

let renditions: Vec<String> = rendition_strs
.iter()
.map(|s| parse_rendition(s))
.collect::<Result<Vec<_>, _>>()?;

tokio::runtime::Runtime::new()
.map_err(|e| format!("failed to start runtime: {}", e))?
.block_on(async move {
let resp = api::export_project_project_project_id_export_post(
&cfg,
&args.project_id,
renditions,
Some(&api_key),
bearer_header.as_deref(),
)
.await
.map_err(|e| {
let mut m = format!("export failed: {}", e);
match &e {
tellers_api_client::apis::Error::Reqwest(req_err) => {
if let Some(status) = req_err.status() {
m.push_str(&format!("; http_status: {}", status));
}
}
tellers_api_client::apis::Error::ResponseError(resp) => {
m.push_str(&format!("; http_status: {}", resp.status));
if !resp.content.is_empty() {
m.push_str(&format!("; response: {}", resp.content));
}
}
_ => {}
}
m
})?;

println!("task_id: {}", resp.task_id);
println!("asset_id: {}", resp.asset_id);
Ok(())
})
}
17 changes: 17 additions & 0 deletions src/commands/project/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use clap::{Args, Subcommand};

mod export;

pub use export::{run as export_run, ExportArgs};

#[derive(Args, Debug)]
pub struct ProjectArgs {
#[command(subcommand)]
pub command: ProjectCommand,
}

#[derive(Subcommand, Debug)]
pub enum ProjectCommand {
/// Export project to MP4 at one or more resolutions (optionally into a project folder).
Export(ExportArgs),
}
16 changes: 16 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ fn main() {
std::process::exit(1);
}
}
commands::asset::AssetCommand::SetAnonymousRead(args) => {
if let Err(error) = commands::asset::set_anonymous_read_run(args) {
eprintln!("error: {}", error);
std::process::exit(1);
}
}
}
}
Some(cli::Command::Project(project_args)) => {
match project_args.command {
commands::project::ProjectCommand::Export(export_args) => {
if let Err(error) = commands::project::export_run(export_args) {
eprintln!("error: {}", error);
std::process::exit(1);
}
}
}
}
Some(cli::Command::Upload(upload_args)) => {
Expand Down
Loading
Loading