mod batch;
mod cli;
mod error;
mod info;
mod processing;
mod walrus;
use batch::batch_compress_images;
use clap::Parser;
use cli::{Args, Commands};
use error::Result;
use info::{get_image_info, print_detailed_info};
use processing::{compress_image, CompressionOptions};
use rayon::ThreadPoolBuilder;
use std::path::Path;
use walrus::{upload_to_walrus_sync, WalrusOptions};
fn main() -> Result<()> {
let args = Args::parse();
match args.command {
Commands::Compress {
input,
output,
quality,
width,
height,
format,
threads,
} => {
setup_thread_pool(threads);
let options = CompressionOptions::new(quality, width, height, format)?;
compress_image(input, output, options)?;
}
Commands::Batch {
input,
output,
quality,
width,
height,
format,
threads,
recursive,
} => {
setup_thread_pool(threads);
let options = CompressionOptions::new(quality, width, height, format)?;
batch_compress_images(input, output, options, recursive)?;
}
Commands::Upload {
input,
aggregator_url,
publisher_url,
epochs,
temp,
} => {
upload_image_to_walrus(&input, aggregator_url, publisher_url, epochs, temp)?;
}
Commands::Info { input } => {
show_image_info(&input)?;
}
}
Ok(())
}
fn setup_thread_pool(threads: Option<usize>) {
if let Some(num_threads) = threads {
ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.unwrap_or_else(|e| {
eprintln!("Warning: Failed to set thread pool size: {}", e);
});
}
}
fn upload_image_to_walrus(
input_path: &Path,
aggregator_url: Option<String>,
publisher_url: Option<String>,
epochs: Option<u64>,
temp: bool,
) -> Result<()> {
println!("📤 Uploading to Walrus: {:?}", input_path);
if !input_path.exists() {
return Err(error::CompressionError::FileNotFound(
input_path.to_path_buf(),
));
}
let final_epochs = if temp {
Some(1) } else {
epochs
};
let options = WalrusOptions::new(aggregator_url, publisher_url, final_epochs);
println!("🔗 Aggregator URL: {}", options.aggregator_url);
println!("🔗 Publisher URL: {}", options.publisher_url);
println!("⏰ Epochs: {:?}", options.epochs);
let blob_id = upload_to_walrus_sync(input_path, &options)?;
println!("✅ Upload successful!");
println!("🆔 Blob ID: {}", blob_id);
let access_url = build_walrus_access_url(&options.aggregator_url, &blob_id);
println!("🌐 Access URL: {}", access_url);
if temp {
println!("⏰ Temporary file: Will expire after 1 epoch (~24 hours)");
println!("🔄 Use without -t flag for longer storage");
}
if let Ok(metadata) = std::fs::metadata(input_path) {
println!("📊 File size: {} bytes", metadata.len());
}
println!("💡 You can use the blob ID to retrieve the file later");
Ok(())
}
fn build_walrus_access_url(aggregator_url: &str, blob_id: &str) -> String {
if aggregator_url.ends_with('/') {
format!("{}v1/blobs/{}", aggregator_url, blob_id)
} else {
format!("{}/v1/blobs/{}", aggregator_url, blob_id)
}
}
fn show_image_info(input_path: &Path) -> Result<()> {
println!("📋 Getting info for: {:?}", input_path);
if !input_path.exists() {
return Err(error::CompressionError::FileNotFound(
input_path.to_path_buf(),
));
}
get_image_info(input_path)?;
print_detailed_info(input_path)?;
Ok(())
}