asciiframe 2.0.0

Convert any video to a stream of ASCII frames
Documentation
#![forbid(unsafe_code)]
#![warn(warnings)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
use std::{fs::File, io::Write, path::Path, thread::sleep, time::Duration};

use clap::Parser;
use terminal_size::{terminal_size, Height, Width};

mod cli;
use cli::Args;

fn render_to_stdout(fin: &Path, width: i32, height: i32) -> asciiframe::Result<()> {
	asciiframe::render(fin, width, height, |frame| {
		println!("{esc}c", esc = 27 as char);
		println!("{}", frame.data);

		let time_d = 1.0 / f32::from(frame.fps);
		if frame.elapsed < time_d {
			sleep(Duration::from_millis(
				((time_d - frame.elapsed) * 1000.0) as u64,
			));
		}

		Ok(())
	})
}

fn render_to_file(fin: &Path, width: i32, height: i32, fout: &Path) -> asciiframe::Result<()> {
	let mut fout = File::create(fout)?;
	fout.write_all(
		"#!/bin/bash\n# This file was auto-generated by asciiframe\necho -en '\x1b[2J' \n"
			.as_bytes(),
	)?;

	asciiframe::render(fin, width, height, |frame| {
		fout.write_all(
			format!(
				"echo '{}'\nsleep {}\necho '\u{001b}[0;0H' \n",
				frame.data,
				1.0 / f32::from(frame.fps),
			)
			.as_bytes(),
		)?;

		Ok(())
	})
}

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

	let (Width(w), Height(h)) = terminal_size().unwrap_or((Width(256), Height(256)));
	let width = i32::from(w);
	let height = i32::from(h);

	let result = if let Some(path) = args.output {
		render_to_file(&args.file, width, height, &path)
	} else {
		render_to_stdout(&args.file, width, height)
	};

	match result {
		Err(error) => {
			println!("{error}");
			std::process::exit(1);
		}
		Ok(()) => {
			std::process::exit(0);
		}
	}
}