index : gmss.git

ascending towards madness

use std::path::PathBuf;

use chrono::{DateTime, Local, Utc};
use clap::Parser;
use screenshots::{image::ImageBuffer, Screen};

mod cli;

fn main() {
    let args = cli::Args::parse();

    capture_all(args.out, args.filename_format.unwrap_or_default());
}

fn capture_all(out_dir: String, filename_format: String) {
    let mut screens = Screen::all().unwrap_or_else(|err| {
        eprintln!("there was an error retrieving screens: {:?}", err);
        vec![]
    });

    screens.sort_by(|first, second| first.display_info.x.cmp(&second.display_info.x));

    let captures: Vec<_> = screens
        .iter()
        .filter_map(|screen| screen.capture().ok())
        .collect();

    let dimensions = captures
        .iter()
        .fold(ImageDimensions::default(), |t, buf| ImageDimensions {
            x: t.x + buf.width(),
            y: t.y.max(buf.height()),
        });

    let mut img = ImageBuffer::new(dimensions.x, dimensions.y);

    captures
        .iter()
        .fold(ImageDimensions::default(), |offset, buf| {
            for (x, y, pixel) in buf.enumerate_pixels() {
                img.put_pixel(offset.x + x, y, *pixel);
            }
            ImageDimensions {
                x: offset.x + buf.width(),
                y: offset.y,
            }
        });

    if !img.is_empty() {
        let timestamp: DateTime<Local> = Utc::now().with_timezone(&Local);

        let mut path = PathBuf::from(out_dir);
        if path.is_dir() {
            path = path.join(timestamp.format(&filename_format).to_string());
        }

        match img.save(generate_filename(&path)) {
            Ok(_) => println!("screenshot saved successfully!"),
            Err(err) => println!("there was an error saving the image: {:?}", err),
        }
    }
}

#[derive(Default)]
struct ImageDimensions {
    pub x: u32,
    pub y: u32,
}

impl std::fmt::Display for ImageDimensions {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("({}, {})", self.x, self.y))
    }
}

fn generate_filename(filename: &PathBuf) -> PathBuf {
    let mut index = 0;
    let mut new_filename = filename.clone();

    let extension = filename
        .extension()
        .map(|ext| format!(".{}", ext.to_string_lossy()))
        .unwrap_or_default();

    while new_filename.exists() {
        index += 1;
        new_filename.set_file_name(format!(
            "{}_{}{}",
            filename.file_stem().unwrap().to_string_lossy(),
            index,
            extension
        ));
    }

    new_filename
}