mirror of https://github.com/sgoudham/uwuifyy.git
Merge pull request #2 from StratusFearMe21/main
commit
51c590d0b9
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
|||||||
|
pub const FACES_SIZE: usize = 14;
|
||||||
|
pub const FACES: [&[u8]; FACES_SIZE] = [
|
||||||
|
b"OwO",
|
||||||
|
b"UwU",
|
||||||
|
b">w<",
|
||||||
|
b"^w^",
|
||||||
|
b"^-^",
|
||||||
|
b":3",
|
||||||
|
b"x3",
|
||||||
|
b"xDD",
|
||||||
|
b";;w;;",
|
||||||
|
b">_<",
|
||||||
|
b">_>",
|
||||||
|
b"^.^",
|
||||||
|
b":33",
|
||||||
|
b"uWu",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const ACTIONS_SIZE: usize = 17;
|
||||||
|
pub const ACTIONS: [&[u8]; ACTIONS_SIZE] = [
|
||||||
|
b"*notices bulge*",
|
||||||
|
b"*cries*",
|
||||||
|
b"*hugs tightly*",
|
||||||
|
b"*screams*",
|
||||||
|
b"*looks away*",
|
||||||
|
b"*blushes*",
|
||||||
|
b"*sweats*",
|
||||||
|
b"*cuddles you*",
|
||||||
|
b"*moans*",
|
||||||
|
b"*giggles shyly*",
|
||||||
|
b"*looks at you*",
|
||||||
|
b"*twerks*",
|
||||||
|
b"*sighs*",
|
||||||
|
b"*leans over*",
|
||||||
|
b"*pokes you*",
|
||||||
|
b"*teleports behind you*",
|
||||||
|
b"*shuffles closer*",
|
||||||
|
];
|
@ -0,0 +1,212 @@
|
|||||||
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
use linkify::{LinkFinder, LinkKind};
|
||||||
|
use rand::{Rng, RngCore, SeedableRng};
|
||||||
|
use rand_xoshiro::{Xoshiro256Plus, Xoshiro256PlusPlus};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Error, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use constants::ACTIONS;
|
||||||
|
use constants::ACTIONS_SIZE;
|
||||||
|
use constants::FACES;
|
||||||
|
use constants::FACES_SIZE;
|
||||||
|
|
||||||
|
mod constants;
|
||||||
|
|
||||||
|
macro_rules! progress_bar {
|
||||||
|
() => {{
|
||||||
|
let progress_bar = ProgressBar::new_spinner();
|
||||||
|
progress_bar.set_style(
|
||||||
|
ProgressStyle::default_spinner().template("{spinner:.green} [{elapsed_precise}] {msg}"),
|
||||||
|
);
|
||||||
|
progress_bar.enable_steady_tick(100);
|
||||||
|
|
||||||
|
progress_bar
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UwUify<'a> {
|
||||||
|
text: &'a str,
|
||||||
|
input: &'a str,
|
||||||
|
output: &'a str,
|
||||||
|
words: f64,
|
||||||
|
faces: f64,
|
||||||
|
actions: f64,
|
||||||
|
stutters: f64,
|
||||||
|
floating_rng: Xoshiro256Plus,
|
||||||
|
int_rng: Xoshiro256PlusPlus,
|
||||||
|
linkify: LinkFinder,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Default for UwUify<'a> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
text: "",
|
||||||
|
input: "",
|
||||||
|
output: "",
|
||||||
|
words: 1.0,
|
||||||
|
faces: 0.05,
|
||||||
|
actions: 0.125,
|
||||||
|
stutters: 0.225,
|
||||||
|
floating_rng: Xoshiro256Plus::seed_from_u64(69),
|
||||||
|
int_rng: Xoshiro256PlusPlus::seed_from_u64(420),
|
||||||
|
linkify: LinkFinder::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UwUify<'a> {
|
||||||
|
pub fn new(
|
||||||
|
text: Option<&'a str>,
|
||||||
|
infile: Option<&'a str>,
|
||||||
|
outfile: Option<&'a str>,
|
||||||
|
words: Option<&'a str>,
|
||||||
|
faces: Option<&'a str>,
|
||||||
|
actions: Option<&'a str>,
|
||||||
|
stutters: Option<&'a str>,
|
||||||
|
random: bool,
|
||||||
|
) -> UwUify<'a> {
|
||||||
|
// I dislike this
|
||||||
|
|
||||||
|
let mut linkify = LinkFinder::new();
|
||||||
|
linkify.kinds(&[LinkKind::Email, LinkKind::Url]);
|
||||||
|
linkify.url_must_have_scheme(false);
|
||||||
|
let mut uwuify = UwUify {
|
||||||
|
text: text.unwrap_or_default(),
|
||||||
|
input: infile.unwrap_or_default(),
|
||||||
|
output: outfile.unwrap_or_default(),
|
||||||
|
linkify,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if random {
|
||||||
|
uwuify.floating_rng = Xoshiro256Plus::seed_from_u64(rand::rngs::OsRng.next_u64());
|
||||||
|
uwuify.int_rng = Xoshiro256PlusPlus::seed_from_u64(rand::rngs::OsRng.next_u64());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(words) = words {
|
||||||
|
uwuify.words = words.parse::<f64>().unwrap();
|
||||||
|
}
|
||||||
|
if let Some(faces) = faces {
|
||||||
|
uwuify.faces = faces.parse::<f64>().unwrap();
|
||||||
|
}
|
||||||
|
if let Some(actions) = actions {
|
||||||
|
uwuify.actions = actions.parse::<f64>().unwrap();
|
||||||
|
}
|
||||||
|
if let Some(stutters) = stutters {
|
||||||
|
uwuify.stutters = stutters.parse::<f64>().unwrap();
|
||||||
|
}
|
||||||
|
uwuify
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uwuify(&mut self) -> Result<(), Error> {
|
||||||
|
// Handle Text
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
// Handle Text Output
|
||||||
|
if !self.output.is_empty() {
|
||||||
|
if Path::new(&self.output).exists() {
|
||||||
|
return Err(Error::new(
|
||||||
|
std::io::ErrorKind::AlreadyExists,
|
||||||
|
format!("File '{}' already exists, aborting operation", &self.output),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut uwu_out_file = BufWriter::new(File::create(&self.output)?);
|
||||||
|
let uwu_progress_bar = progress_bar!();
|
||||||
|
self.uwuify_sentence(self.text, &mut uwu_out_file)?;
|
||||||
|
|
||||||
|
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let stdout = std::io::stdout();
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let mut out = BufWriter::new(stdout.lock());
|
||||||
|
#[cfg(test)]
|
||||||
|
let mut out = std::io::sink();
|
||||||
|
self.uwuify_sentence(self.text, &mut out)?;
|
||||||
|
#[cfg(not(test))]
|
||||||
|
out.write_all(b"\n")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle File I/O
|
||||||
|
if Path::new(&self.output).exists() {
|
||||||
|
return Err(Error::new(
|
||||||
|
std::io::ErrorKind::AlreadyExists,
|
||||||
|
format!("File '{}' already exists, aborting operation", &self.output),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let uwu_progress_bar = progress_bar!();
|
||||||
|
self.uwuify_sentence(
|
||||||
|
unsafe {
|
||||||
|
std::str::from_utf8_unchecked(
|
||||||
|
memmap::Mmap::map(&File::open(&self.input)?)?.as_ref(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&mut BufWriter::new(File::create(&self.output)?),
|
||||||
|
)?;
|
||||||
|
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uwuify_sentence<T: Write>(
|
||||||
|
&mut self,
|
||||||
|
text: &str,
|
||||||
|
out: &mut T,
|
||||||
|
) -> Result<(), std::io::Error> {
|
||||||
|
text.lines().try_for_each(|line| {
|
||||||
|
line.split_whitespace()
|
||||||
|
.map(|f| f.as_bytes())
|
||||||
|
.try_for_each(|word| {
|
||||||
|
let random_value = self.floating_rng.gen_range(0.0..1.0);
|
||||||
|
|
||||||
|
if random_value <= self.faces {
|
||||||
|
out.write_all(FACES[self.int_rng.gen_range(0..FACES_SIZE)])?;
|
||||||
|
out.write_all(b" ")?;
|
||||||
|
} else if random_value <= self.actions {
|
||||||
|
out.write_all(ACTIONS[self.int_rng.gen_range(0..ACTIONS_SIZE)])?;
|
||||||
|
out.write_all(b" ")?;
|
||||||
|
} else if random_value <= self.stutters {
|
||||||
|
(0..self.int_rng.gen_range(1..2))
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|_| {
|
||||||
|
match word[0] {
|
||||||
|
b'L' | b'R' => out.write_all(b"W"),
|
||||||
|
b'l' | b'r' => out.write_all(b"w"),
|
||||||
|
b => out.write_all(&[b]),
|
||||||
|
}?;
|
||||||
|
out.write_all(b"-")
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self
|
||||||
|
.linkify
|
||||||
|
.links(unsafe { std::str::from_utf8_unchecked(word) })
|
||||||
|
.count()
|
||||||
|
> 0
|
||||||
|
|| random_value > self.words
|
||||||
|
{
|
||||||
|
out.write_all(word)?;
|
||||||
|
} else {
|
||||||
|
(0..word.len()).try_for_each(|index| match word[index] {
|
||||||
|
b'L' | b'R' => out.write_all(b"W"),
|
||||||
|
b'l' | b'r' => out.write_all(b"w"),
|
||||||
|
b'E' | b'e' | b'A' | b'I' | b'O' | b'U' | b'a' | b'i' | b'o' | b'u' => {
|
||||||
|
match word.get(index - 1).unwrap_or(&word[0]) {
|
||||||
|
b'N' | b'n' => out.write_all(&[b'y', word[index]]),
|
||||||
|
_ => out.write_all(&[word[index]]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b => out.write_all(&[b]),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
out.write_all(b" ")
|
||||||
|
})?;
|
||||||
|
out.write_all(b"\n")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,71 +1,136 @@
|
|||||||
use clap::{ArgGroup, ErrorKind, IntoApp, Parser};
|
use clap::{Arg, ArgGroup, ErrorKind};
|
||||||
|
|
||||||
use crate::uwuify::UwUify;
|
use uwuifyy::UwUify;
|
||||||
|
|
||||||
mod uwuify;
|
macro_rules! app {
|
||||||
|
() => {
|
||||||
#[derive(Parser)]
|
clap::App::new(env!("CARGO_PKG_NAME"))
|
||||||
#[clap(author, version, about, long_about = None)]
|
.author(env!("CARGO_PKG_AUTHORS"))
|
||||||
#[clap(group(ArgGroup::new("uwu").required(true).args(& ["text", "infile"]),))]
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
struct Args {
|
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||||
/// Text to uwu'ify
|
.long_about(None)
|
||||||
#[clap(short, long, required_unless_present_all = ["infile", "outfile"], display_order = 1)]
|
.group(
|
||||||
text: Option<String>,
|
ArgGroup::new("uwu")
|
||||||
|
.required(true)
|
||||||
/// The file to uwu'ify
|
.args(&["text", "infile"]),
|
||||||
#[clap(short, long, parse(from_os_str), conflicts_with = "text", requires = "outfile", value_name = "FILE", value_hint = clap::ValueHint::FilePath, display_order = 2)]
|
)
|
||||||
infile: Option<std::path::PathBuf>,
|
.arg(
|
||||||
|
Arg::new("text")
|
||||||
/// The file to output uwu'ified text
|
.help("Text to uwu'ify")
|
||||||
#[clap(short, long, value_name = "FILE", value_hint = clap::ValueHint::FilePath, display_order = 3)]
|
.short('t')
|
||||||
outfile: Option<String>,
|
.long("text")
|
||||||
|
.value_name("TEXT")
|
||||||
/// The modifier to determine how many words to be uwu'ified
|
.required_unless_present_all(["infile", "outfile"])
|
||||||
#[clap(short, long, value_name = "VALUE", default_value = "1", validator = is_between_zero_and_one, display_order = 4)]
|
.display_order(1),
|
||||||
words: f32,
|
)
|
||||||
|
.arg(
|
||||||
/// The modifier for uwu faces e.g hello -> hewwo
|
Arg::new("infile")
|
||||||
#[clap(short, long, value_name = "VALUE", default_value = "0.05", validator = is_between_zero_and_one, display_order = 5)]
|
.help("The file to uwu'ify")
|
||||||
faces: f32,
|
.short('i')
|
||||||
|
.long("infile")
|
||||||
/// The modifier for actions e.g *shuffles over*
|
.conflicts_with("text")
|
||||||
#[clap(short, long, value_name = "VALUE", default_value = "0.125", validator = is_between_zero_and_one, display_order = 6)]
|
.requires("outfile")
|
||||||
actions: f32,
|
.value_name("FILE")
|
||||||
|
.value_hint(clap::ValueHint::FilePath)
|
||||||
/// The modifier for stutters e.g b-baka!
|
.display_order(2),
|
||||||
#[clap(short, long, value_name = "VALUE", default_value = "0.225", validator = is_between_zero_and_one, display_order = 7)]
|
)
|
||||||
stutters: f32,
|
.arg(
|
||||||
|
Arg::new("outfile")
|
||||||
|
.help("The file to output uwu'ified text")
|
||||||
|
.short('o')
|
||||||
|
.long("outfile")
|
||||||
|
.value_name("FILE")
|
||||||
|
.value_hint(clap::ValueHint::FilePath)
|
||||||
|
.display_order(3),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("words")
|
||||||
|
.help("The modifier to determine how many words to be uwu'ified")
|
||||||
|
.short('w')
|
||||||
|
.long("words")
|
||||||
|
.value_name("VALUE")
|
||||||
|
.default_value("1")
|
||||||
|
.validator(is_between_zero_and_one)
|
||||||
|
.display_order(4),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("faces")
|
||||||
|
.help("The modifier for uwu faces e.g hello -> hewwo")
|
||||||
|
.short('f')
|
||||||
|
.long("faces")
|
||||||
|
.value_name("VALUE")
|
||||||
|
.default_value("0.05")
|
||||||
|
.validator(is_between_zero_and_one)
|
||||||
|
.display_order(5),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("actions")
|
||||||
|
.help("The modifier for actions e.g *shuffles over*")
|
||||||
|
.short('a')
|
||||||
|
.long("actions")
|
||||||
|
.value_name("VALUE")
|
||||||
|
.default_value("0.125")
|
||||||
|
.validator(is_between_zero_and_one)
|
||||||
|
.display_order(6),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("stutters")
|
||||||
|
.help("The modifier for stutters e.g b-baka!")
|
||||||
|
.short('s')
|
||||||
|
.long("stutters")
|
||||||
|
.value_name("VALUE")
|
||||||
|
.default_value("0.225")
|
||||||
|
.validator(is_between_zero_and_one)
|
||||||
|
.display_order(7),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("random")
|
||||||
|
.help("Flag to enable/disable random uwu'ifying")
|
||||||
|
.short('r')
|
||||||
|
.long("random")
|
||||||
|
.display_order(8),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Flag to enable/disable random uwu'ifying
|
macro_rules! clap_panic {
|
||||||
#[clap(short, long, display_order = 8)]
|
($e:expr) => {
|
||||||
random: bool,
|
app!().error(ErrorKind::DisplayHelp, $e).exit()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
std::panic::set_hook(Box::new(|info| {
|
||||||
let matches = Args::into_app().get_matches();
|
clap_panic!(info);
|
||||||
|
}));
|
||||||
|
let matches = app!().get_matches();
|
||||||
|
|
||||||
let supplied_at_runtime = modifiers_supplied_at_runtime(matches.occurrences_of("faces"), matches.occurrences_of("actions"), matches.occurrences_of("stutters"));
|
// panicing here ensures that the error is passed to the hook above instead of to stdout.
|
||||||
let uwuify = UwUify::new(args.text, args.infile, args.outfile, supplied_at_runtime, args.words, args.faces, args.actions, args.stutters, args.random);
|
match UwUify::new(
|
||||||
match uwuify.uwuify() {
|
matches.value_of("text"),
|
||||||
Ok(_) => (),
|
matches.value_of("infile"),
|
||||||
Err(err) => {
|
matches.value_of("outfile"),
|
||||||
let mut app = Args::into_app();
|
matches.value_of("words"),
|
||||||
app.error(ErrorKind::DisplayHelp, err.to_string()).exit();
|
matches.value_of("faces"),
|
||||||
}
|
matches.value_of("actions"),
|
||||||
}
|
matches.value_of("stutters"),
|
||||||
|
matches.is_present("random"),
|
||||||
|
)
|
||||||
|
.uwuify()
|
||||||
|
{
|
||||||
|
Err(e) => clap_panic!(e),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_between_zero_and_one(input: &str) -> Result<(), String> {
|
fn is_between_zero_and_one(input: &str) -> Result<(), &'static str> {
|
||||||
let value = match input.parse::<f32>() {
|
let value = match input.parse::<f32>() {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(_) => return Err(String::from("The value must be a decimal number"))
|
Err(_) => return Err("The value must be a decimal number"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (0.0..=1.0).contains(&value) { return Ok(()); }
|
if (0.0..=1.0).contains(&value) {
|
||||||
Err(String::from("The value must be between 0.0 and 1.0"))
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err("The value must be between 0.0 and 1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modifiers_supplied_at_runtime(faces_occurrences: u64, actions_occurrences: u64, stutters_occurrences: u64) -> bool {
|
|
||||||
faces_occurrences > 0 || actions_occurrences > 0 || stutters_occurrences > 0
|
|
||||||
}
|
|
@ -1,212 +0,0 @@
|
|||||||
use std::error::Error;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use linkify::{LinkFinder, LinkKind};
|
|
||||||
|
|
||||||
use crate::uwuify::constants::ACTIONS;
|
|
||||||
use crate::uwuify::constants::ACTIONS_SIZE;
|
|
||||||
use crate::uwuify::constants::FACES;
|
|
||||||
use crate::uwuify::constants::FACES_SIZE;
|
|
||||||
use crate::uwuify::io::{UwUInFile, UwUOutFile};
|
|
||||||
use crate::uwuify::progress_bar::UwUProgressBar;
|
|
||||||
use crate::uwuify::seeder::UwUSeeder;
|
|
||||||
|
|
||||||
mod constants;
|
|
||||||
mod seeder;
|
|
||||||
mod progress_bar;
|
|
||||||
mod io;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Modifiers {
|
|
||||||
supplied_at_runtime: bool,
|
|
||||||
words: f32,
|
|
||||||
faces: f32,
|
|
||||||
actions: f32,
|
|
||||||
stutters: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UwUify {
|
|
||||||
text: String,
|
|
||||||
input: PathBuf,
|
|
||||||
output: String,
|
|
||||||
modifiers: Modifiers,
|
|
||||||
random: bool,
|
|
||||||
linkify: LinkFinder,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UwUify {
|
|
||||||
pub fn new(text: Option<String>,
|
|
||||||
infile: Option<PathBuf>,
|
|
||||||
outfile: Option<String>,
|
|
||||||
supplied_at_runtime: bool,
|
|
||||||
words: f32,
|
|
||||||
faces: f32,
|
|
||||||
actions: f32,
|
|
||||||
stutters: f32,
|
|
||||||
random: bool) -> UwUify { // I dislike this
|
|
||||||
|
|
||||||
let mut linkify = LinkFinder::new();
|
|
||||||
linkify.kinds(&[LinkKind::Email, LinkKind::Url]);
|
|
||||||
linkify.url_must_have_scheme(false);
|
|
||||||
|
|
||||||
UwUify {
|
|
||||||
text: text.unwrap_or_default(),
|
|
||||||
input: infile.unwrap_or_default(),
|
|
||||||
output: outfile.unwrap_or_default(),
|
|
||||||
modifiers: Modifiers { supplied_at_runtime, words, faces, actions, stutters },
|
|
||||||
random,
|
|
||||||
linkify,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uwuify(&self) -> Result<(), Box<dyn Error>> {
|
|
||||||
// Handle Text
|
|
||||||
if !self.text.is_empty() {
|
|
||||||
let uwu_text = self.uwuify_sentence(&self.text);
|
|
||||||
|
|
||||||
// Handle Text Output
|
|
||||||
if !self.output.is_empty() {
|
|
||||||
if UwUOutFile::exists(&self.output) {
|
|
||||||
return Err(format!("File '{}' already exists, aborting operation", &self.output).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut uwu_out_file = match UwUOutFile::new(&self.output) {
|
|
||||||
Ok(uwu_out_file) => uwu_out_file,
|
|
||||||
Err(err) => return Err(err.into())
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut uwu_progress_bar = UwUProgressBar::new(uwu_text.len() as u64);
|
|
||||||
|
|
||||||
match uwu_out_file.write_string(&uwu_text) {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
uwu_progress_bar.update_progess(uwu_text.len());
|
|
||||||
uwu_progress_bar.finish("UwU'ifying Complete!");
|
|
||||||
} else {
|
|
||||||
println!("{}", uwu_text);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Handle File I/O
|
|
||||||
if UwUOutFile::exists(&self.output) {
|
|
||||||
return Err(format!("File '{}' already exists, aborting operation", &self.output).into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut uwu_in_file = match UwUInFile::new(&self.input) {
|
|
||||||
Ok(uwu_in_file) => uwu_in_file,
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
let mut uwu_out_file = match UwUOutFile::new(&self.output) {
|
|
||||||
Ok(uwu_out_file) => uwu_out_file,
|
|
||||||
Err(err) => return Err(err.into())
|
|
||||||
};
|
|
||||||
let mut uwu_progress_bar = UwUProgressBar::new(uwu_in_file.get_file_bytes());
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let bytes_read_in = match uwu_in_file.read_until_newline() {
|
|
||||||
Ok(bytes_read_in) => bytes_read_in,
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
if bytes_read_in == 0 { break; }
|
|
||||||
|
|
||||||
let utf8_str = uwu_in_file.get_buffer_as_utf8_str();
|
|
||||||
let uwu_sentence = self.uwuify_sentence(&utf8_str);
|
|
||||||
match uwu_out_file.write_string_with_newline(&uwu_sentence) {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
uwu_progress_bar.update_progess(bytes_read_in);
|
|
||||||
uwu_in_file.clear_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
uwu_progress_bar.finish("UwU'ifying Complete!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uwuify_sentence(&self, text: &str) -> String {
|
|
||||||
text
|
|
||||||
.split_whitespace()
|
|
||||||
.map(|word| {
|
|
||||||
let uwu_word = self.uwuify_word(word.to_string());
|
|
||||||
self.uwuify_spaces(uwu_word)
|
|
||||||
})
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uwuify_word(&self, word: String) -> String {
|
|
||||||
if self.linkify.links(&word).count() > 0 {
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut seeder = UwUSeeder::new(&word, self.random);
|
|
||||||
if seeder.random() > self.modifiers.words { return word; }
|
|
||||||
|
|
||||||
let word_bytes = word.as_bytes();
|
|
||||||
let uwu_text_count = word.len();
|
|
||||||
let mut uwu_text = String::new();
|
|
||||||
|
|
||||||
for index in 0..uwu_text_count {
|
|
||||||
let previous_previous_char = *word_bytes.get(index - 2).unwrap_or_else(|| &word_bytes[0]) as char;
|
|
||||||
let previous_char = *word_bytes.get(index - 1).unwrap_or_else(|| &word_bytes[0]) as char;
|
|
||||||
let current_char = word_bytes[index] as char;
|
|
||||||
|
|
||||||
match current_char {
|
|
||||||
'L' | 'R' => uwu_text.push('W'),
|
|
||||||
'l' | 'r' => uwu_text.push('w'),
|
|
||||||
'E' | 'e' => match previous_char {
|
|
||||||
'N' | 'n' => uwu_text.push_str(format!("y{}", current_char).as_str()),
|
|
||||||
'v' => match previous_previous_char {
|
|
||||||
'o' => {
|
|
||||||
uwu_text.pop();
|
|
||||||
uwu_text.pop();
|
|
||||||
uwu_text.push_str("uv");
|
|
||||||
}
|
|
||||||
_ => uwu_text.push(current_char)
|
|
||||||
}
|
|
||||||
_ => uwu_text.push(current_char)
|
|
||||||
}
|
|
||||||
'A' | 'I' | 'O' | 'U' | 'a' | 'i' | 'o' | 'u' => match previous_char {
|
|
||||||
'N' | 'n' => uwu_text.push_str(format!("y{}", current_char).as_str()),
|
|
||||||
_ => uwu_text.push(current_char)
|
|
||||||
}
|
|
||||||
_ => uwu_text.push(current_char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uwu_text
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uwuify_spaces(&self, mut word: String) -> String {
|
|
||||||
let mut seeder = UwUSeeder::new(&word, self.random);
|
|
||||||
let random_value = seeder.random();
|
|
||||||
|
|
||||||
if !self.modifiers.supplied_at_runtime {
|
|
||||||
if random_value <= self.modifiers.faces {
|
|
||||||
word = format!("{} {}", FACES[seeder.random_int(0, FACES_SIZE)], word);
|
|
||||||
} else if random_value <= self.modifiers.actions {
|
|
||||||
word = format!("{} {}", ACTIONS[seeder.random_int(0, ACTIONS_SIZE)], word);
|
|
||||||
} else if random_value <= self.modifiers.stutters {
|
|
||||||
let first_char_stutter = format!("{}-", word.chars().next().unwrap());
|
|
||||||
word = format!("{}{}", first_char_stutter.repeat(seeder.random_int(1, 2)), word);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if random_value <= self.modifiers.stutters {
|
|
||||||
let first_char_stutter = format!("{}-", word.chars().next().unwrap());
|
|
||||||
word = format!("{}{}", first_char_stutter.repeat(seeder.random_int(1, 2)), word);
|
|
||||||
}
|
|
||||||
if random_value <= self.modifiers.faces {
|
|
||||||
word = format!("{} {}", FACES[seeder.random_int(0, FACES_SIZE)], word);
|
|
||||||
}
|
|
||||||
if random_value <= self.modifiers.actions {
|
|
||||||
word = format!("{} {}", ACTIONS[seeder.random_int(0, ACTIONS_SIZE)], word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
word
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
pub const FACES_SIZE: i32 = 15;
|
|
||||||
pub const FACES: [&str; FACES_SIZE as usize] = [
|
|
||||||
"OwO",
|
|
||||||
"UwU",
|
|
||||||
">w<",
|
|
||||||
"^w^",
|
|
||||||
"ÚwÚ",
|
|
||||||
"^-^",
|
|
||||||
":3",
|
|
||||||
"x3",
|
|
||||||
"xDD",
|
|
||||||
";;w;;",
|
|
||||||
">_<",
|
|
||||||
">_>",
|
|
||||||
"^.^",
|
|
||||||
":33",
|
|
||||||
"uWu",
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const ACTIONS_SIZE: i32 = 17;
|
|
||||||
pub const ACTIONS: [&str; ACTIONS_SIZE as usize] = [
|
|
||||||
"*notices bulge*",
|
|
||||||
"*cries*",
|
|
||||||
"*hugs tightly*",
|
|
||||||
"*screams*",
|
|
||||||
"*looks away*",
|
|
||||||
"*blushes*",
|
|
||||||
"*sweats*",
|
|
||||||
"*cuddles you*",
|
|
||||||
"*moans*",
|
|
||||||
"*giggles shyly*",
|
|
||||||
"*looks at you*",
|
|
||||||
"*twerks*",
|
|
||||||
"*sighs*",
|
|
||||||
"*leans over*",
|
|
||||||
"*pokes you*",
|
|
||||||
"*teleports behind you*",
|
|
||||||
"*shuffles closer*",
|
|
||||||
];
|
|
@ -1,80 +0,0 @@
|
|||||||
use std::fs::File;
|
|
||||||
use std::io::{BufRead, BufReader, BufWriter, Error, Write};
|
|
||||||
use std::path::{Path};
|
|
||||||
|
|
||||||
pub struct UwUInFile {
|
|
||||||
file_bytes: u64,
|
|
||||||
reader: BufReader<File>,
|
|
||||||
buffer: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct UwUOutFile {
|
|
||||||
writer: BufWriter<File>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UwUInFile {
|
|
||||||
pub fn new(path: &Path) -> Result<UwUInFile, Error> {
|
|
||||||
let file = match File::open(path) {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(err) => return Err(err)
|
|
||||||
};
|
|
||||||
let file_metadata = match file.metadata() {
|
|
||||||
Ok(file_metadata) => file_metadata,
|
|
||||||
Err(err) => return Err(err)
|
|
||||||
};
|
|
||||||
let file_bytes = file_metadata.len();
|
|
||||||
let reader = BufReader::new(file);
|
|
||||||
let buffer = Vec::new();
|
|
||||||
|
|
||||||
Ok(UwUInFile { file_bytes, reader, buffer })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_until_newline(&mut self) -> Result<usize, Error> {
|
|
||||||
match self.reader.read_until(b'\n', &mut self.buffer) {
|
|
||||||
Ok(byte_vec) => Ok(byte_vec),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_buffer_as_utf8_str(&self) -> String {
|
|
||||||
String::from_utf8_lossy(&self.buffer).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_buffer(&mut self) {
|
|
||||||
self.buffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_file_bytes(&self) -> u64 {
|
|
||||||
self.file_bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UwUOutFile {
|
|
||||||
pub fn new(path: &str) -> Result<UwUOutFile, Error> {
|
|
||||||
let file = match File::create(path) {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(err) => return Err(err)
|
|
||||||
};
|
|
||||||
let writer = BufWriter::new(file);
|
|
||||||
|
|
||||||
Ok(UwUOutFile { writer })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exists(path: &str) -> bool {
|
|
||||||
Path::new(path).exists()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_string_with_newline(&mut self, write_str: &str) -> Result<(), Error> {
|
|
||||||
match self.writer.write_all(format!("{}\n", write_str).as_bytes()) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_string(&mut self, write_str: &str) -> Result<(), Error> {
|
|
||||||
match self.writer.write_all(write_str.as_bytes()) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
use indicatif::{ProgressBar, ProgressStyle};
|
|
||||||
|
|
||||||
pub struct UwUProgressBar {
|
|
||||||
downloaded_bytes: u64,
|
|
||||||
progress_bar: ProgressBar,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UwUProgressBar {
|
|
||||||
pub fn new(file_total_bytes: u64) -> UwUProgressBar {
|
|
||||||
let progress_bar = ProgressBar::new(file_total_bytes);
|
|
||||||
progress_bar.set_style(ProgressStyle::default_bar()
|
|
||||||
.template("{spinner:.green} [{elapsed_precise}] [{bar:60.cyan/blue}] {bytes}/{total_bytes} ({eta}) {msg}")
|
|
||||||
.progress_chars("#>-"));
|
|
||||||
|
|
||||||
UwUProgressBar {
|
|
||||||
downloaded_bytes: 0,
|
|
||||||
progress_bar,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_progess(&mut self, bytes_read_in: usize) {
|
|
||||||
self.downloaded_bytes += bytes_read_in as u64;
|
|
||||||
self.progress_bar.set_position(self.downloaded_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(&self, message: &'static str) {
|
|
||||||
self.progress_bar.finish_with_message(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
use rand::{Rng, rngs::ThreadRng, thread_rng};
|
|
||||||
use rand_pcg::Pcg32;
|
|
||||||
use rand_seeder::Seeder;
|
|
||||||
|
|
||||||
pub struct UwUSeeder {
|
|
||||||
seeder: Pcg32,
|
|
||||||
rng: ThreadRng,
|
|
||||||
random: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UwUSeeder {
|
|
||||||
pub fn new(word: &str, random: bool) -> UwUSeeder {
|
|
||||||
UwUSeeder {
|
|
||||||
seeder: Seeder::from(word).make_rng(),
|
|
||||||
rng: thread_rng(),
|
|
||||||
random,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn random(&mut self) -> f32 {
|
|
||||||
if self.random {
|
|
||||||
self.rng.gen_range(0.0..1.0)
|
|
||||||
} else {
|
|
||||||
self.seeder.gen_range(0.0..1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn random_int(&mut self, min: i32, max: i32) -> usize {
|
|
||||||
if self.random {
|
|
||||||
self.rng.gen_range(min..max) as usize
|
|
||||||
} else {
|
|
||||||
self.seeder.gen_range(min..max) as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue