fetch functions complete
This commit is contained in:
		
							parent
							
								
									0df646844a
								
							
						
					
					
						commit
						a4f32ff5b1
					
				
							
								
								
									
										1014
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1014
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										13
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Cargo.toml
									
									
									
									
									
								
							| 
						 | 
					@ -5,11 +5,12 @@ edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
clap = { version = "4.5.4", features = ["derive"] }
 | 
					clap = { version = "4.5.4", features = ["derive"] }
 | 
				
			||||||
 | 
					crossterm = "0.27.0"
 | 
				
			||||||
# clap = "2.0.0"
 | 
					 | 
				
			||||||
rand = { version = "0.8.4", features = ["small_rng"] }
 | 
					 | 
				
			||||||
serde_json = "1.0"
 | 
					 | 
				
			||||||
rust-embed = "8.3.0"
 | 
					 | 
				
			||||||
ctrlc = "3.4.4"
 | 
					ctrlc = "3.4.4"
 | 
				
			||||||
 | 
					dirs = "5.0.1"
 | 
				
			||||||
 | 
					image = "0.25.1"
 | 
				
			||||||
 | 
					rand = { version = "0.8.4", features = ["small_rng"] }
 | 
				
			||||||
reqwest = { version = "0.11", features = ["json", "blocking"] }
 | 
					reqwest = { version = "0.11", features = ["json", "blocking"] }
 | 
				
			||||||
zip = "0.5"
 | 
					rust-embed = "8.3.0"
 | 
				
			||||||
 | 
					serde_json = "1.0.115"
 | 
				
			||||||
 | 
					zip = "0.6.6"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ struct Args {
 | 
				
			||||||
    name: String,
 | 
					    name: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // big
 | 
					    // big
 | 
				
			||||||
    /// Show a larger version of the sprite
 | 
					    /// Show a bigger version of the sprite
 | 
				
			||||||
    #[arg(short, long, default_value_t = false)]
 | 
					    #[arg(short, long, default_value_t = false)]
 | 
				
			||||||
    big: bool,
 | 
					    big: bool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,90 +0,0 @@
 | 
				
			||||||
// this fetches the sprites and downloads to the user's local machine
 | 
					 | 
				
			||||||
// https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: pass in url as argument and use it
 | 
					 | 
				
			||||||
// for now, we use this as default
 | 
					 | 
				
			||||||
const TARGET_URL: &str = "https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip";
 | 
					 | 
				
			||||||
const WORKING_DIRECTORY: &str = "/tmp/rustmon/";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    // // create a working directory for the program to use
 | 
					 | 
				
			||||||
    // match create_working_directory() {
 | 
					 | 
				
			||||||
    //     Ok(_) => (),
 | 
					 | 
				
			||||||
    //     Err(e) => eprintln!("Error creating working directory: {}", e),
 | 
					 | 
				
			||||||
    // }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // match download_colorscripts_archive(TARGET_URL) {
 | 
					 | 
				
			||||||
    //     Ok(_) => (),
 | 
					 | 
				
			||||||
    //     Err(e) => eprintln!("Error downloading file: {}", e),
 | 
					 | 
				
			||||||
    // }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO: extract here as default unless specified in flags
 | 
					 | 
				
			||||||
    extract_colorscripts_archive(std::path::Path::new(WORKING_DIRECTORY)).unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn create_working_directory() -> std::io::Result<()> {
 | 
					 | 
				
			||||||
    println!("Creating working directory at {}...", WORKING_DIRECTORY);
 | 
					 | 
				
			||||||
    std::fs::create_dir(WORKING_DIRECTORY)?;
 | 
					 | 
				
			||||||
    return Ok(());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn download_colorscripts_archive(target_url: &str) -> Result<(), Box<dyn std::error::Error>> {
 | 
					 | 
				
			||||||
    println!("Fetching colorscripts archive...");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let response = reqwest::blocking::get(target_url)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut dest = std::fs::File::create(format!("{}colorscripts.zip", WORKING_DIRECTORY))?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let response_body = response.error_for_status()?.bytes()?;
 | 
					 | 
				
			||||||
    std::io::copy(&mut response_body.as_ref(), &mut dest)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    println!("Downloaded pokesprite.zip");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return Ok(());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn extract_colorscripts_archive(extract_location: &std::path::Path) -> zip::result::ZipResult<()> {
 | 
					 | 
				
			||||||
    // let archive_file = std::fs::File::open(&archive_path)?;
 | 
					 | 
				
			||||||
    let archive_file = std::fs::File::open(std::path::Path::new(
 | 
					 | 
				
			||||||
        format!("{}colorscripts.zip", WORKING_DIRECTORY).as_str(),
 | 
					 | 
				
			||||||
    ))?;
 | 
					 | 
				
			||||||
    let mut archive = zip::read::ZipArchive::new(std::io::BufReader::new(archive_file))?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for i in 0..archive.len() {
 | 
					 | 
				
			||||||
        let mut file = archive.by_index(i)?;
 | 
					 | 
				
			||||||
        let file_path = std::path::Path::new(file.name());
 | 
					 | 
				
			||||||
        let parent_dir = file_path
 | 
					 | 
				
			||||||
            .parent()
 | 
					 | 
				
			||||||
            .and_then(std::path::Path::file_name)
 | 
					 | 
				
			||||||
            .and_then(std::ffi::OsStr::to_str)
 | 
					 | 
				
			||||||
            .unwrap_or("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (file
 | 
					 | 
				
			||||||
            .name()
 | 
					 | 
				
			||||||
            .starts_with("pokesprite-master/pokemon-gen8/regular/")
 | 
					 | 
				
			||||||
            && parent_dir == "regular")
 | 
					 | 
				
			||||||
            || (file
 | 
					 | 
				
			||||||
                .name()
 | 
					 | 
				
			||||||
                .starts_with("pokesprite-master/pokemon-gen8/shiny/")
 | 
					 | 
				
			||||||
                && parent_dir == "shiny")
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            let file_name = file_path
 | 
					 | 
				
			||||||
                .file_name()
 | 
					 | 
				
			||||||
                .and_then(std::ffi::OsStr::to_str)
 | 
					 | 
				
			||||||
                .unwrap_or("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let outpath = extract_location.join(parent_dir).join(file_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if !file.name().ends_with('/') {
 | 
					 | 
				
			||||||
                if let Some(p) = outpath.parent() {
 | 
					 | 
				
			||||||
                    if !p.exists() {
 | 
					 | 
				
			||||||
                        std::fs::create_dir_all(&p)?;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                let mut outfile = std::fs::File::create(&outpath)?;
 | 
					 | 
				
			||||||
                std::io::copy(&mut file, &mut outfile)?;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										4
									
								
								src/constants.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/constants.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					pub const TARGET_URL: &str =
 | 
				
			||||||
 | 
					    "https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip";
 | 
				
			||||||
 | 
					pub const WORKING_DIRECTORY: &str = "/tmp/rustmon/";
 | 
				
			||||||
 | 
					pub const EXTRACT_DESTINATION: &str = "~/.local/share/rustmon/";
 | 
				
			||||||
							
								
								
									
										349
									
								
								src/fetch.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								src/fetch.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,349 @@
 | 
				
			||||||
 | 
					use image::GenericImageView;
 | 
				
			||||||
 | 
					use std::io::Write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn fetch(extract_destination: &std::path::Path, silent: bool) {
 | 
				
			||||||
 | 
					    // prep working directory
 | 
				
			||||||
 | 
					    match create_working_directory() {
 | 
				
			||||||
 | 
					        Ok(_) => (),
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("Error creating working directory: {}", e),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // download colorscripts archive
 | 
				
			||||||
 | 
					    match download_colorscripts_archive(crate::constants::TARGET_URL) {
 | 
				
			||||||
 | 
					        Ok(_) => (),
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("Error downloading colorscripts archive: {}", e),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // extract colorscripts archive
 | 
				
			||||||
 | 
					    // now we have the raw images
 | 
				
			||||||
 | 
					    match extract_colorscripts_archive() {
 | 
				
			||||||
 | 
					        Ok(_) => (),
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("Error extracting colorscripts archive: {}", e),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // crop images to content
 | 
				
			||||||
 | 
					    match crop_all_images_in_directory() {
 | 
				
			||||||
 | 
					        Ok(_) => (),
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("Error cropping images: {}", e),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // convert images to unicode, both small and big
 | 
				
			||||||
 | 
					    match convert_images_to_ascii(extract_destination, silent) {
 | 
				
			||||||
 | 
					        Ok(_) => (),
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("Error converting images to ASCII: {}", e),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // cleanup
 | 
				
			||||||
 | 
					    match cleanup() {
 | 
				
			||||||
 | 
					        Ok(_) => (),
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("Error cleaning up: {}", e),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn create_working_directory() -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    println!(
 | 
				
			||||||
 | 
					        "Creating working directory at {}...",
 | 
				
			||||||
 | 
					        &crate::constants::WORKING_DIRECTORY
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    // create intermediate directories also
 | 
				
			||||||
 | 
					    std::fs::create_dir(&crate::constants::WORKING_DIRECTORY)?;
 | 
				
			||||||
 | 
					    println!("Created working directory");
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn download_colorscripts_archive(target_url: &str) -> Result<(), Box<dyn std::error::Error>> {
 | 
				
			||||||
 | 
					    println!("Fetching colorscripts archive...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let response = reqwest::blocking::get(target_url)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut dest = std::fs::File::create(format!(
 | 
				
			||||||
 | 
					        "{}pokesprite.zip",
 | 
				
			||||||
 | 
					        &crate::constants::WORKING_DIRECTORY
 | 
				
			||||||
 | 
					    ))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let response_body = response.error_for_status()?.bytes()?;
 | 
				
			||||||
 | 
					    std::io::copy(&mut response_body.as_ref(), &mut dest)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Downloaded colorscripts archive");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn extract_colorscripts_archive() -> zip::result::ZipResult<()> {
 | 
				
			||||||
 | 
					    println!("Extracting colorscripts archive...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let archive_file = std::fs::File::open(std::path::Path::new(
 | 
				
			||||||
 | 
					        format!("{}pokesprite.zip", &crate::constants::WORKING_DIRECTORY).as_str(),
 | 
				
			||||||
 | 
					    ))?;
 | 
				
			||||||
 | 
					    let mut archive = zip::read::ZipArchive::new(std::io::BufReader::new(archive_file))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // iterate over every single file in the archive
 | 
				
			||||||
 | 
					    for i in 0..archive.len() {
 | 
				
			||||||
 | 
					        let mut file = archive.by_index(i)?;
 | 
				
			||||||
 | 
					        let file_path = std::path::Path::new(file.name());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let parent_dir = file_path
 | 
				
			||||||
 | 
					            .parent()
 | 
				
			||||||
 | 
					            .and_then(std::path::Path::file_name)
 | 
				
			||||||
 | 
					            .and_then(std::ffi::OsStr::to_str)
 | 
				
			||||||
 | 
					            .unwrap_or("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // check if the file is a in the correct directory that is NOT a directory
 | 
				
			||||||
 | 
					        if (file
 | 
				
			||||||
 | 
					            .name()
 | 
				
			||||||
 | 
					            .starts_with("pokesprite-master/pokemon-gen8/regular/")
 | 
				
			||||||
 | 
					            && parent_dir == "regular")
 | 
				
			||||||
 | 
					            || (file
 | 
				
			||||||
 | 
					                .name()
 | 
				
			||||||
 | 
					                .starts_with("pokesprite-master/pokemon-gen8/shiny/")
 | 
				
			||||||
 | 
					                && parent_dir == "shiny")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let file_name = file_path
 | 
				
			||||||
 | 
					                .file_name()
 | 
				
			||||||
 | 
					                .and_then(std::ffi::OsStr::to_str)
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let outpath = std::path::Path::new(&crate::constants::WORKING_DIRECTORY)
 | 
				
			||||||
 | 
					                .join("raw_images")
 | 
				
			||||||
 | 
					                .join(parent_dir)
 | 
				
			||||||
 | 
					                .join(file_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if !file.name().ends_with('/') {
 | 
				
			||||||
 | 
					                if let Some(p) = outpath.parent() {
 | 
				
			||||||
 | 
					                    if !p.exists() {
 | 
				
			||||||
 | 
					                        std::fs::create_dir_all(&p)?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                let mut outfile = std::fs::File::create(&outpath)?;
 | 
				
			||||||
 | 
					                std::io::copy(&mut file, &mut outfile)?;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Extracted colorscripts archive");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn crop_all_images_in_directory() -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    println!("Cropping images...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // make sure the cropped_images directory exists
 | 
				
			||||||
 | 
					    std::fs::create_dir_all(
 | 
				
			||||||
 | 
					        std::path::Path::new(crate::constants::WORKING_DIRECTORY).join("cropped_images"),
 | 
				
			||||||
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // do for both regular and shiny subdirectories
 | 
				
			||||||
 | 
					    for subdirectory in ["regular", "shiny"].iter() {
 | 
				
			||||||
 | 
					        let input_subdirectory_path = std::path::Path::new(crate::constants::WORKING_DIRECTORY)
 | 
				
			||||||
 | 
					            .join("raw_images")
 | 
				
			||||||
 | 
					            .join(subdirectory);
 | 
				
			||||||
 | 
					        let output_subdirectory_path = std::path::Path::new(crate::constants::WORKING_DIRECTORY)
 | 
				
			||||||
 | 
					            .join("cropped_images")
 | 
				
			||||||
 | 
					            .join(subdirectory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::fs::create_dir_all(&output_subdirectory_path)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for entry in std::fs::read_dir(&input_subdirectory_path)? {
 | 
				
			||||||
 | 
					            let entry = entry?;
 | 
				
			||||||
 | 
					            let path = entry.path();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let output_path = output_subdirectory_path.join(path.file_name().unwrap());
 | 
				
			||||||
 | 
					            crop_to_content(&path, &output_path).unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Cropped images");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn crop_to_content(
 | 
				
			||||||
 | 
					    input_path: &std::path::Path,
 | 
				
			||||||
 | 
					    output_path: &std::path::Path,
 | 
				
			||||||
 | 
					) -> image::ImageResult<image::DynamicImage> {
 | 
				
			||||||
 | 
					    // load the image
 | 
				
			||||||
 | 
					    let img = image::open(input_path)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let (width, height) = img.dimensions();
 | 
				
			||||||
 | 
					    let mut min_x = width;
 | 
				
			||||||
 | 
					    let mut min_y = height;
 | 
				
			||||||
 | 
					    let mut max_x = 0;
 | 
				
			||||||
 | 
					    let mut max_y = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for y in 0..height {
 | 
				
			||||||
 | 
					        for x in 0..width {
 | 
				
			||||||
 | 
					            let pixel = img.get_pixel(x, y);
 | 
				
			||||||
 | 
					            if pixel[3] != 0 {
 | 
				
			||||||
 | 
					                // if pixel is not transparent
 | 
				
			||||||
 | 
					                if x < min_x {
 | 
				
			||||||
 | 
					                    min_x = x;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if y < min_y {
 | 
				
			||||||
 | 
					                    min_y = y;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if x > max_x {
 | 
				
			||||||
 | 
					                    max_x = x;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if y > max_y {
 | 
				
			||||||
 | 
					                    max_y = y;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let cropped_width = max_x - min_x + 1;
 | 
				
			||||||
 | 
					    let cropped_height = max_y - min_y + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut cropped_img: image::ImageBuffer<image::Rgba<u8>, Vec<u8>> =
 | 
				
			||||||
 | 
					        image::ImageBuffer::new(cropped_width, cropped_height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for y in 0..cropped_height {
 | 
				
			||||||
 | 
					        for x in 0..cropped_width {
 | 
				
			||||||
 | 
					            let pixel = img.get_pixel(x + min_x, y + min_y);
 | 
				
			||||||
 | 
					            cropped_img.put_pixel(x, y, pixel);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let cropped_img = image::DynamicImage::ImageRgba8(cropped_img);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // write the cropped image
 | 
				
			||||||
 | 
					    cropped_img.save(output_path)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(cropped_img);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn convert_images_to_ascii(
 | 
				
			||||||
 | 
					    output_directory_path: &std::path::Path,
 | 
				
			||||||
 | 
					    silent: bool,
 | 
				
			||||||
 | 
					) -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    println!("Extract destination: {:?}", output_directory_path);
 | 
				
			||||||
 | 
					    println!("Converting images to ASCII...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::fs::create_dir_all(output_directory_path)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for size in ["small", "big"].iter() {
 | 
				
			||||||
 | 
					        for subdirectory in ["regular", "shiny"].iter() {
 | 
				
			||||||
 | 
					            let input_subdirectory_path =
 | 
				
			||||||
 | 
					                std::path::PathBuf::from(crate::constants::WORKING_DIRECTORY)
 | 
				
			||||||
 | 
					                    .join("cropped_images")
 | 
				
			||||||
 | 
					                    .join(subdirectory);
 | 
				
			||||||
 | 
					            let output_subdirectory_path = output_directory_path
 | 
				
			||||||
 | 
					                .join("colorscripts")
 | 
				
			||||||
 | 
					                .join(size)
 | 
				
			||||||
 | 
					                .join(subdirectory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::fs::create_dir_all(&output_subdirectory_path)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for entry in std::fs::read_dir(&input_subdirectory_path)? {
 | 
				
			||||||
 | 
					                let entry = entry?;
 | 
				
			||||||
 | 
					                let path = entry.path();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if path.is_file() {
 | 
				
			||||||
 | 
					                    let img = image::open(&path).unwrap();
 | 
				
			||||||
 | 
					                    let ascii_art = if *size == "small" {
 | 
				
			||||||
 | 
					                        convert_image_to_unicode_small(&img)
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        convert_image_to_unicode_big(&img)
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // print for fun
 | 
				
			||||||
 | 
					                    if silent == false {
 | 
				
			||||||
 | 
					                        println!("{}", ascii_art);
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let output_path = output_subdirectory_path.join(path.file_stem().unwrap());
 | 
				
			||||||
 | 
					                    let mut file = std::fs::File::create(output_path)?;
 | 
				
			||||||
 | 
					                    file.write_all(ascii_art.as_bytes())?;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Converted images to ASCII");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn convert_image_to_unicode_small(img: &image::DynamicImage) -> String {
 | 
				
			||||||
 | 
					    let mut unicode_sprite = String::new();
 | 
				
			||||||
 | 
					    let (width, height) = img.dimensions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for y in (0..height).step_by(2) {
 | 
				
			||||||
 | 
					        for x in 0..width {
 | 
				
			||||||
 | 
					            let upper_pixel = img.get_pixel(x, y);
 | 
				
			||||||
 | 
					            let lower_pixel = if y + 1 < height {
 | 
				
			||||||
 | 
					                img.get_pixel(x, y + 1)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                upper_pixel // Fallback to upper pixel if there's no lower pixel.
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if upper_pixel[3] == 0 && lower_pixel[3] == 0 {
 | 
				
			||||||
 | 
					                unicode_sprite.push(' ');
 | 
				
			||||||
 | 
					            } else if upper_pixel[3] == 0 {
 | 
				
			||||||
 | 
					                unicode_sprite.push_str(&get_color_escape_code(lower_pixel, false));
 | 
				
			||||||
 | 
					                unicode_sprite.push('▄');
 | 
				
			||||||
 | 
					            } else if lower_pixel[3] == 0 {
 | 
				
			||||||
 | 
					                unicode_sprite.push_str(&get_color_escape_code(upper_pixel, false));
 | 
				
			||||||
 | 
					                unicode_sprite.push('▀');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                unicode_sprite.push_str(&get_color_escape_code(upper_pixel, false));
 | 
				
			||||||
 | 
					                unicode_sprite.push_str(&get_color_escape_code(lower_pixel, true));
 | 
				
			||||||
 | 
					                unicode_sprite.push('▀');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            unicode_sprite.push_str("\x1b[0m"); // Reset ANSI code after each character
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        unicode_sprite.push('\n'); // New line for each row, plus reset might be added here too if colors extend beyond.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return unicode_sprite;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn convert_image_to_unicode_big(img: &image::DynamicImage) -> String {
 | 
				
			||||||
 | 
					    let mut unicode_sprite = String::new();
 | 
				
			||||||
 | 
					    let (width, height) = img.dimensions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for y in 0..height {
 | 
				
			||||||
 | 
					        for x in 0..width {
 | 
				
			||||||
 | 
					            let pixel = img.get_pixel(x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if pixel[3] == 0 {
 | 
				
			||||||
 | 
					                unicode_sprite.push_str("  ");
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                unicode_sprite.push_str(&get_color_escape_code(pixel, false));
 | 
				
			||||||
 | 
					                unicode_sprite.push_str("██");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        unicode_sprite.push('\n');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return unicode_sprite;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_color_escape_code(pixel: image::Rgba<u8>, background: bool) -> String {
 | 
				
			||||||
 | 
					    if pixel[3] == 0 {
 | 
				
			||||||
 | 
					        return format!("{}", crossterm::style::ResetColor);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let color = crossterm::style::Color::Rgb {
 | 
				
			||||||
 | 
					        r: pixel[0],
 | 
				
			||||||
 | 
					        g: pixel[1],
 | 
				
			||||||
 | 
					        b: pixel[2],
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if background {
 | 
				
			||||||
 | 
					        format!("{}", crossterm::style::SetBackgroundColor(color))
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        format!("{}", crossterm::style::SetForegroundColor(color))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn cleanup() -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    println!("Cleaning up...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::fs::remove_dir_all(std::path::Path::new(crate::constants::WORKING_DIRECTORY))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Cleaned up");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Ok(());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					pub mod constants;
 | 
				
			||||||
 | 
					pub mod fetch;
 | 
				
			||||||
							
								
								
									
										336
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										336
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
					@ -1,279 +1,99 @@
 | 
				
			||||||
use rand::Rng;
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// set global constants
 | 
					/*
 | 
				
			||||||
#[derive(rust_embed::RustEmbed)]
 | 
					# Arguments
 | 
				
			||||||
#[folder = "colorscripts/"]
 | 
					 | 
				
			||||||
struct ColorScriptsDir;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const POKEMON_JSON: &str = std::include_str!("../pokemon.json");
 | 
					## Fetch
 | 
				
			||||||
 | 
					- `fetch` - Fetch the latest colorscripts from the repository
 | 
				
			||||||
 | 
					- `silent` - Don't print colorscripts to the console when generating
 | 
				
			||||||
 | 
					- `extract_destination` - eXtract the colorscripts archive to a specified location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const REGULAR_SUBDIR: &str = "regular";
 | 
					## Print
 | 
				
			||||||
const SHINY_SUBDIR: &str = "shiny";
 | 
					- `name` - Select pokemon by name
 | 
				
			||||||
 | 
					- `big` - Show a bigger version of the sprite
 | 
				
			||||||
 | 
					- `list` - Show a list of all pokemon names
 | 
				
			||||||
 | 
					- `no-title` - Do not display pokemon name
 | 
				
			||||||
 | 
					- `shiny` - Show the shiny version of the sprite
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LARGE_SUBDIR: &str = "large";
 | 
					/// Pokemon Colorscripts written in Rust
 | 
				
			||||||
const SMALL_SUBDIR: &str = "small";
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					#[command(version, about, long_about = None)]
 | 
				
			||||||
 | 
					struct Args {
 | 
				
			||||||
 | 
					    // fetch
 | 
				
			||||||
 | 
					    /// Fetch the latest colorscripts from the repository
 | 
				
			||||||
 | 
					    #[arg(short, long, default_value_t = false)]
 | 
				
			||||||
 | 
					    fetch: bool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SHINY_RATE: f64 = 1.0 / 128.0;
 | 
					    // silent
 | 
				
			||||||
 | 
					    /// Don't print colorscripts to the console when generating
 | 
				
			||||||
 | 
					    #[arg(long = "silent", default_value_t = false)]
 | 
				
			||||||
 | 
					    silent: bool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GENERATIONS: [(&str, (u32, u32)); 8] = [
 | 
					    // extract destination
 | 
				
			||||||
    ("1", (1, 151)),
 | 
					    /// eXtract the colorscripts archive to a specified location
 | 
				
			||||||
    ("2", (152, 251)),
 | 
					    #[arg(short = 'x', long = "extract", default_value_t = String::from(""))]
 | 
				
			||||||
    ("3", (252, 386)),
 | 
					    extract_destination: String,
 | 
				
			||||||
    ("4", (387, 493)),
 | 
					    /*
 | 
				
			||||||
    ("5", (494, 649)),
 | 
					    // big
 | 
				
			||||||
    ("6", (650, 721)),
 | 
					    /// Show a bigger version of the sprite
 | 
				
			||||||
    ("7", (722, 809)),
 | 
					    #[arg(short, long, default_value_t = false)]
 | 
				
			||||||
    ("8", (810, 898)),
 | 
					    big: bool,
 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn print_file(filepath: &str) -> std::io::Result<()> {
 | 
					    // list
 | 
				
			||||||
    return ColorScriptsDir::get(filepath)
 | 
					    /// Show a list of all pokemon names
 | 
				
			||||||
        .map(|file| {
 | 
					    #[arg(short, long, default_value_t = false)]
 | 
				
			||||||
            let content = std::str::from_utf8(file.data.as_ref()).unwrap();
 | 
					    list: bool,
 | 
				
			||||||
            println!("{}", content);
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        .ok_or(std::io::Error::new(
 | 
					 | 
				
			||||||
            std::io::ErrorKind::NotFound,
 | 
					 | 
				
			||||||
            "File not found",
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn list_pokemon_names() {
 | 
					    // name
 | 
				
			||||||
    let pokemon_json: serde_json::Value = serde_json::from_str(POKEMON_JSON).unwrap();
 | 
					    /// Select pokemon by name
 | 
				
			||||||
 | 
					    #[arg(short = 'a', long, default_value_t = String::from(""))]
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut count = 0;
 | 
					    // no-title
 | 
				
			||||||
 | 
					    // NOTE: clap will convert the kebab-case to snake_case
 | 
				
			||||||
 | 
					    // very smart!
 | 
				
			||||||
 | 
					    // ...but very annoying for beginners
 | 
				
			||||||
 | 
					    /// Do not display pokemon name
 | 
				
			||||||
 | 
					    #[arg(long, default_value_t = false)]
 | 
				
			||||||
 | 
					    no_title: bool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if let serde_json::Value::Array(array) = pokemon_json {
 | 
					    // shiny
 | 
				
			||||||
        for pokemon in array {
 | 
					    /// Show the shiny version of the sprite
 | 
				
			||||||
            if let Some(name) = pokemon.get("name") {
 | 
					    #[arg(short, long, default_value_t = false)]
 | 
				
			||||||
                if let serde_json::Value::String(name_str) = name {
 | 
					 | 
				
			||||||
                    println!("{}", name_str);
 | 
					 | 
				
			||||||
                    count += 1;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    println!("-------------------");
 | 
					 | 
				
			||||||
    println!("Total: {} Pokémons", count);
 | 
					 | 
				
			||||||
    println!("Use the --name flag to view a specific Pokémon");
 | 
					 | 
				
			||||||
    println!("Tip: Use `grep` to search for a specific Pokémon");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn show_pokemon_by_name(
 | 
					 | 
				
			||||||
    name: &str,
 | 
					 | 
				
			||||||
    show_title: bool,
 | 
					 | 
				
			||||||
    shiny: bool,
 | 
					    shiny: bool,
 | 
				
			||||||
    is_large: bool,
 | 
					    */
 | 
				
			||||||
    form: Option<&str>,
 | 
					 | 
				
			||||||
) -> std::io::Result<()> {
 | 
					 | 
				
			||||||
    // set variables
 | 
					 | 
				
			||||||
    let color_subdir = if shiny { SHINY_SUBDIR } else { REGULAR_SUBDIR };
 | 
					 | 
				
			||||||
    let size_subdir = if is_large { LARGE_SUBDIR } else { SMALL_SUBDIR };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pokemon_json: serde_json::Value = serde_json::from_str(POKEMON_JSON)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pokemon_names: Vec<&str> = pokemon_json
 | 
					 | 
				
			||||||
        .as_array()
 | 
					 | 
				
			||||||
        .unwrap()
 | 
					 | 
				
			||||||
        .iter()
 | 
					 | 
				
			||||||
        .map(|pokemon| pokemon["name"].as_str().unwrap())
 | 
					 | 
				
			||||||
        .collect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if !pokemon_names.contains(&name) {
 | 
					 | 
				
			||||||
        println!("Invalid pokemon {}", name);
 | 
					 | 
				
			||||||
        std::process::exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut name = name.to_string();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if let Some(form) = form {
 | 
					 | 
				
			||||||
        let forms: Vec<&str> = pokemon_json
 | 
					 | 
				
			||||||
            .as_array()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .iter()
 | 
					 | 
				
			||||||
            .filter(|pokemon| pokemon["name"].as_str().unwrap() == name)
 | 
					 | 
				
			||||||
            .flat_map(|pokemon| pokemon["forms"].as_array().unwrap().iter())
 | 
					 | 
				
			||||||
            .map(|form| form.as_str().unwrap())
 | 
					 | 
				
			||||||
            .collect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let alternate_forms: Vec<&str> =
 | 
					 | 
				
			||||||
            forms.iter().filter(|&f| *f != "regular").cloned().collect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if alternate_forms.contains(&form) {
 | 
					 | 
				
			||||||
            name.push_str(&format!("-{}", form));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            println!("Invalid form '{}' for pokemon {}", form, name);
 | 
					 | 
				
			||||||
            if alternate_forms.is_empty() {
 | 
					 | 
				
			||||||
                println!("No alternate forms available for {}", name);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                println!("Available alternate forms are");
 | 
					 | 
				
			||||||
                for form in alternate_forms {
 | 
					 | 
				
			||||||
                    println!("- {}", form);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            std::process::exit(1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if show_title {
 | 
					 | 
				
			||||||
        if shiny {
 | 
					 | 
				
			||||||
            println!("{} (shiny)", name);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            println!("{}", name);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Construct the embedded file path
 | 
					 | 
				
			||||||
    let file_path = format!("{}/{}/{}", size_subdir, color_subdir, name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Use the adjusted function to print file contents from embedded resources
 | 
					 | 
				
			||||||
    print_file(&file_path)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return Ok(());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn show_random_pokemon(
 | 
					 | 
				
			||||||
    generations: &str,
 | 
					 | 
				
			||||||
    show_title: bool,
 | 
					 | 
				
			||||||
    shiny: bool,
 | 
					 | 
				
			||||||
    is_large: bool,
 | 
					 | 
				
			||||||
) -> std::io::Result<()> {
 | 
					 | 
				
			||||||
    let mut rng = rand::thread_rng();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let start_gen = if generations.is_empty() {
 | 
					 | 
				
			||||||
        "1"
 | 
					 | 
				
			||||||
    } else if generations.contains(",") {
 | 
					 | 
				
			||||||
        let gens: Vec<&str> = generations.split(",").collect();
 | 
					 | 
				
			||||||
        let gen = gens[rng.gen_range(0..gens.len())];
 | 
					 | 
				
			||||||
        gen
 | 
					 | 
				
			||||||
    } else if generations.contains("-") {
 | 
					 | 
				
			||||||
        let gens: Vec<&str> = generations.split("-").collect();
 | 
					 | 
				
			||||||
        gens[0]
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        generations
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pokemon_json: serde_json::Value = serde_json::from_str(POKEMON_JSON)?;
 | 
					 | 
				
			||||||
    let pokemon: Vec<String> = pokemon_json
 | 
					 | 
				
			||||||
        .as_array()
 | 
					 | 
				
			||||||
        .unwrap()
 | 
					 | 
				
			||||||
        .iter()
 | 
					 | 
				
			||||||
        .map(|p| p["name"].as_str().unwrap().to_string())
 | 
					 | 
				
			||||||
        .collect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let generations_map: std::collections::HashMap<_, _> = GENERATIONS.iter().cloned().collect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if let Some((start_idx, end_idx)) = generations_map.get(start_gen) {
 | 
					 | 
				
			||||||
        let random_idx = rng.gen_range(*start_idx..=*end_idx);
 | 
					 | 
				
			||||||
        let random_pokemon = &pokemon[random_idx as usize - 1];
 | 
					 | 
				
			||||||
        let shiny = if !shiny {
 | 
					 | 
				
			||||||
            rng.gen::<f64>() <= SHINY_RATE
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            shiny
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        show_pokemon_by_name(random_pokemon, show_title, shiny, is_large, None)?;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        println!("Invalid generation '{}'", generations);
 | 
					 | 
				
			||||||
        std::process::exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return Ok(());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(target_os = "windows")]
 | 
					 | 
				
			||||||
fn pause() {
 | 
					 | 
				
			||||||
    use std::io::{self, Read, Write};
 | 
					 | 
				
			||||||
    let mut stdout = io::stdout();
 | 
					 | 
				
			||||||
    let mut stdin = io::stdin();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    stdout.write_all(b"Press any key to continue...").unwrap();
 | 
					 | 
				
			||||||
    stdout.flush().unwrap();
 | 
					 | 
				
			||||||
    stdin.read(&mut [0]).unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(not(target_os = "windows"))]
 | 
					 | 
				
			||||||
fn pause() {
 | 
					 | 
				
			||||||
    // do literally nothing
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let matches = clap::App::new("rustmon")
 | 
					    let args = argument_validation();
 | 
				
			||||||
        .about("CLI utility to print out unicode image of a pokemon in your shell")
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("list")
 | 
					 | 
				
			||||||
                .short("l")
 | 
					 | 
				
			||||||
                .long("list")
 | 
					 | 
				
			||||||
                .help("Print list of all pokemon"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("name")
 | 
					 | 
				
			||||||
                .short("n")
 | 
					 | 
				
			||||||
                .long("name")
 | 
					 | 
				
			||||||
                .value_name("POKEMON NAME")
 | 
					 | 
				
			||||||
                .help("Select pokemon by name. Generally spelled like in the games."),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("form")
 | 
					 | 
				
			||||||
                .short("f")
 | 
					 | 
				
			||||||
                .long("form")
 | 
					 | 
				
			||||||
                .value_name("FORM")
 | 
					 | 
				
			||||||
                .help("Show an alternate form of a pokemon"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("no-title")
 | 
					 | 
				
			||||||
                .long("no-title")
 | 
					 | 
				
			||||||
                .help("Do not display pokemon name"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("shiny")
 | 
					 | 
				
			||||||
                .short("s")
 | 
					 | 
				
			||||||
                .long("shiny")
 | 
					 | 
				
			||||||
                .help("Show the shiny version of the pokemon instead"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("big")
 | 
					 | 
				
			||||||
                .short("b")
 | 
					 | 
				
			||||||
                .long("big")
 | 
					 | 
				
			||||||
                .help("Show a larger version of the sprite"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .arg(
 | 
					 | 
				
			||||||
            clap::Arg::with_name("random")
 | 
					 | 
				
			||||||
                .short("r")
 | 
					 | 
				
			||||||
                .long("random")
 | 
					 | 
				
			||||||
                .value_name("GENERATION")
 | 
					 | 
				
			||||||
                .help("Show a random pokemon. This flag can optionally be followed by a generation number or range (1-8) to show random pokemon from a specific generation or range of generations. The generations can be provided as a continuous range (eg. 1-3) or as a list of generations (1,3,6)"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .after_help("P.S. Use the minimon command for a minimalistic version of this tool")
 | 
					 | 
				
			||||||
        .get_matches();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if matches.is_present("list") {
 | 
					    if args.fetch == true {
 | 
				
			||||||
        list_pokemon_names();
 | 
					        // get data directory
 | 
				
			||||||
    } else if matches.is_present("name") {
 | 
					        let data_directory = match dirs::data_dir() {
 | 
				
			||||||
        let name = matches.value_of("name").unwrap();
 | 
					            Some(dir) => dir.join("rustmon"),
 | 
				
			||||||
        let no_title = matches.is_present("no-title");
 | 
					            None => {
 | 
				
			||||||
        let shiny = matches.is_present("shiny");
 | 
					                println!("Data directory not found");
 | 
				
			||||||
        let big = matches.is_present("big");
 | 
					 | 
				
			||||||
        let form = matches.value_of("form");
 | 
					 | 
				
			||||||
        show_pokemon_by_name(name, !no_title, shiny, big, form).unwrap();
 | 
					 | 
				
			||||||
    } else if matches.is_present("random") {
 | 
					 | 
				
			||||||
        let random = matches.value_of("random").unwrap_or("");
 | 
					 | 
				
			||||||
        let no_title = matches.is_present("no-title");
 | 
					 | 
				
			||||||
        let shiny = matches.is_present("shiny");
 | 
					 | 
				
			||||||
        let big = matches.is_present("big");
 | 
					 | 
				
			||||||
        if matches.is_present("form") {
 | 
					 | 
				
			||||||
            println!("--form flag unexpected with --random");
 | 
					 | 
				
			||||||
                std::process::exit(1);
 | 
					                std::process::exit(1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        show_random_pokemon(random, !no_title, shiny, big).unwrap();
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // decicde whether to use the default data directory or the one specified by the user
 | 
				
			||||||
 | 
					        // if the user specifies a directory, use that
 | 
				
			||||||
 | 
					        let extract_destination = if args.extract_destination.is_empty() {
 | 
				
			||||||
 | 
					            data_directory
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
        // show random pokemon by default with support for other flags
 | 
					            std::path::PathBuf::from(&args.extract_destination)
 | 
				
			||||||
        let no_title = matches.is_present("no-title");
 | 
					        };
 | 
				
			||||||
        let shiny = matches.is_present("shiny");
 | 
					
 | 
				
			||||||
        let big = matches.is_present("big");
 | 
					        rustmon::fetch::fetch(&extract_destination, args.silent);
 | 
				
			||||||
        show_random_pokemon("", !no_title, shiny, big).unwrap();
 | 
					    } else {
 | 
				
			||||||
 | 
					        println!("print deez nuts");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // pause the program before exiting only for windows
 | 
					fn argument_validation() -> Args {
 | 
				
			||||||
    pause();
 | 
					    let args = Args::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return args;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue