use viuer for mcstat image output.

This commit is contained in:
LordMZTE 2021-04-29 13:03:33 +02:00
parent 27517a6994
commit 5068996284
3 changed files with 52 additions and 104 deletions

View file

@ -8,7 +8,6 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.40" anyhow = "1.0.40"
asciify = "0.1.6"
base64 = "0.13.0" base64 = "0.13.0"
clap = "2.33.3" clap = "2.33.3"
image = "0.23.14" image = "0.23.14"
@ -19,6 +18,7 @@ structopt = "0.3.21"
term_size = "0.3.2" term_size = "0.3.2"
termcolor = "1.1.2" termcolor = "1.1.2"
unicode-width = "0.1.8" unicode-width = "0.1.8"
viuer = "0.4.0"
[dependencies.async-minecraft-ping] [dependencies.async-minecraft-ping]
git = "https://github.com/LordMZTE/async-minecraft-ping.git" git = "https://github.com/LordMZTE/async-minecraft-ping.git"

View file

@ -3,7 +3,6 @@ extern crate smart_default;
use crate::output::Table; use crate::output::Table;
use anyhow::{anyhow, bail, Context}; use anyhow::{anyhow, bail, Context};
use asciify::AsciiBuilder;
use image::{DynamicImage, ImageFormat}; use image::{DynamicImage, ImageFormat};
use itertools::Itertools; use itertools::Itertools;
use std::io::Cursor; use std::io::Cursor;
@ -27,22 +26,6 @@ macro_rules! none_if_empty {
}}; }};
} }
pub struct AsciiConfig {
pub size: Option<u32>,
pub colored: bool,
pub deep: bool,
pub invert: bool,
}
impl AsciiConfig {
pub fn apply(&self, mut builder: AsciiBuilder) -> AsciiBuilder {
if let Some(n) = self.size {
builder = builder.set_resize((n * 2, n))
}
builder.set_deep(self.deep).set_invert(self.invert)
}
}
pub fn remove_formatting(s: &str) -> String { pub fn remove_formatting(s: &str) -> String {
let chars = s.char_indices().rev(); let chars = s.char_indices().rev();
let mut buf = s.to_owned(); let mut buf = s.to_owned();

View file

@ -1,21 +1,12 @@
use anyhow::{Context, Result}; use anyhow::{anyhow, Context, Result};
use asciify::AsciiBuilder;
use async_minecraft_ping::{ConnectionConfig, ServerDescription, StatusResponse}; use async_minecraft_ping::{ConnectionConfig, ServerDescription, StatusResponse};
use itertools::Itertools; use itertools::Itertools;
use structopt::StructOpt; use structopt::StructOpt;
use termcolor::{Buffer, BufferWriter, ColorChoice, WriteColor};
use time::{Duration, Instant}; use time::{Duration, Instant};
use tokio::time; use tokio::time;
use mcstat::{ use mcstat::{get_table, none_if_empty, output::Table, parse_base64_image, remove_formatting};
get_table,
none_if_empty,
output::Table,
parse_base64_image,
remove_formatting,
AsciiConfig,
};
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt( #[structopt(
@ -62,35 +53,24 @@ struct Opt {
#[structopt(long, help = "displays forge mod channels if the server sends them")] #[structopt(long, help = "displays forge mod channels if the server sends them")]
channels: bool, channels: bool,
#[structopt(long, short, help = "print the server's favicon as ASCII art")] #[structopt(long, short, help = "print the server's favicon to stdout")]
image: bool, image: bool,
#[structopt(
long,
short = "c",
requires = "image",
help = "print the server's favicon with color"
)]
color: bool,
#[structopt(short, requires = "image", help = "size of the favicon ascii art")] #[structopt(short, requires = "image", help = "size of the favicon ascii art")]
size: Option<u32>, size: Option<u32>,
}
#[structopt( impl Opt {
long, fn get_viuer_conf(&self) -> viuer::Config {
short, let size = self.size.unwrap_or(16);
requires = "image", viuer::Config {
help = "print the ascii art favicon with more diverse chars" transparent: true,
)] absolute_offset: false,
deep: bool, width: Some(size * 2),
height: Some(size),
#[structopt( ..viuer::Config::default()
long, }
short = "n", }
requires = "image",
help = "inverts ascii art favicon"
)]
invert: bool,
} }
#[tokio::main] #[tokio::main]
@ -132,23 +112,6 @@ async fn main() -> Result<()> {
let response = serde_json::from_str::<StatusResponse>(&raw_response)?; let response = serde_json::from_str::<StatusResponse>(&raw_response)?;
// endregion // endregion
// region Image
let mut image = None;
if let (Some(favicon), true) = (&response.favicon, opt.image) {
// The image parsing and asciifying is done while the table is printing
image = Some(tokio::spawn(asciify_base64_image(
favicon.clone(),
AsciiConfig {
size: Some(opt.size.unwrap_or(16)),
colored: opt.color,
deep: opt.deep,
invert: opt.invert,
},
)));
}
// endregion
// region printing // region printing
// if the server has mods, and the user hasn't used the -m argument, notify // if the server has mods, and the user hasn't used the -m argument, notify
// that. // that.
@ -165,45 +128,47 @@ async fn main() -> Result<()> {
) )
.stdout()?; .stdout()?;
if let Some(img) = image { if let (Some(img), true) = (response.favicon, opt.image) {
println!("\n{}", img.await??); let decoded = parse_base64_image(img)?;
viuer::print(&decoded, &opt.get_viuer_conf())
.map_err(|e| anyhow!("Failed to print favicon: {}", e))?;
} }
// endregion // endregion
Ok(()) Ok(())
} }
/// returns the asciifyed image from base64 // returns the asciifyed image from base64
/// returns Err if the base64 image is invalid // returns Err if the base64 image is invalid
async fn asciify_base64_image(favicon: String, config: AsciiConfig) -> Result<String> { // async fn asciify_base64_image(favicon: String, config: AsciiConfig) ->
let image = parse_base64_image(favicon)?; // Result<String> { let image = parse_base64_image(favicon)?;
//
let builder = config.apply(AsciiBuilder::new_from_image(image)); // let builder = config.apply(AsciiBuilder::new_from_image(image));
//
let mut buf = if config.colored { // let mut buf = if config.colored {
// this does not write to stdout but just gets the correct color // this does not write to stdout but just gets the correct color
// information for stdout // information for stdout
let mut buf = BufferWriter::stdout(ColorChoice::Always).buffer(); // let mut buf = BufferWriter::stdout(ColorChoice::Always).buffer();
builder.to_stream_colored(&mut buf); // builder.to_stream_colored(&mut buf);
buf // buf
} else { // } else {
let mut buf = Buffer::no_color(); // let mut buf = Buffer::no_color();
builder.to_stream(&mut buf); // builder.to_stream(&mut buf);
buf // buf
}; // };
// reset color // reset color
buf.reset()?; // buf.reset()?;
//
let bytes = buf.as_slice().to_vec(); // let bytes = buf.as_slice().to_vec();
//
// only check utf8 format in debug mode // only check utf8 format in debug mode
#[cfg(debug_assertions)] // #[cfg(debug_assertions)]
let out = String::from_utf8(bytes).expect("asciifyed image is invalid utf8"); // let out = String::from_utf8(bytes).expect("asciifyed image is invalid utf8");
// bytes should always be valid utf8 // bytes should always be valid utf8
#[cfg(not(debug_assertions))] // #[cfg(not(debug_assertions))]
let out = unsafe { String::from_utf8_unchecked(bytes) }; // let out = unsafe { String::from_utf8_unchecked(bytes) };
//
Ok(out) // Ok(out)
} // }
fn format_table( fn format_table(
response: &StatusResponse, response: &StatusResponse,