mirror of https://github.com/sgoudham/uwuifyy.git
Port over code from uwuify
parent
808b7d8f8a
commit
876c6a8646
@ -0,0 +1,71 @@
|
|||||||
|
use clap::{ArgGroup, ErrorKind, IntoApp, Parser};
|
||||||
|
|
||||||
|
use crate::uwuify::UwUify;
|
||||||
|
|
||||||
|
mod uwuify;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
#[clap(group(ArgGroup::new("uwu").required(true).args(& ["text", "infile"]),))]
|
||||||
|
struct Args {
|
||||||
|
/// Text to uwu'ify
|
||||||
|
#[clap(short, long, required_unless_present_all = ["infile", "outfile"], display_order = 1)]
|
||||||
|
text: Option<String>,
|
||||||
|
|
||||||
|
/// The file to uwu'ify
|
||||||
|
#[clap(short, long, parse(from_os_str), conflicts_with = "text", requires = "outfile", value_name = "FILE", display_order = 2)]
|
||||||
|
infile: Option<std::path::PathBuf>,
|
||||||
|
|
||||||
|
/// The file to output uwu'ified text
|
||||||
|
#[clap(short, long, value_name = "FILE", display_order = 3)]
|
||||||
|
outfile: Option<String>,
|
||||||
|
|
||||||
|
/// The modifier to determine how many words to be uwu'ified
|
||||||
|
#[clap(short, long, value_name = "VALUE", default_value = "1", validator = is_between_zero_and_one, display_order = 4)]
|
||||||
|
words: f32,
|
||||||
|
|
||||||
|
/// The modifier for uwu faces e.g hello -> hewwo
|
||||||
|
#[clap(short, long, value_name = "VALUE", default_value = "0.05", validator = is_between_zero_and_one, display_order = 5)]
|
||||||
|
faces: f32,
|
||||||
|
|
||||||
|
/// The modifier for actions e.g *shuffles over*
|
||||||
|
#[clap(short, long, value_name = "VALUE", default_value = "0.125", validator = is_between_zero_and_one, display_order = 6)]
|
||||||
|
actions: f32,
|
||||||
|
|
||||||
|
/// The modifier for stutters e.g b-baka!
|
||||||
|
#[clap(short, long, value_name = "VALUE", default_value = "0.225", validator = is_between_zero_and_one, display_order = 7)]
|
||||||
|
stutters: f32,
|
||||||
|
|
||||||
|
/// Flag to enable/disable random uwu'ifying
|
||||||
|
#[clap(short, long, display_order = 8)]
|
||||||
|
random: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
let matches = Args::into_app().get_matches();
|
||||||
|
|
||||||
|
let supplied_at_runtime = modifiers_supplied_at_runtime(matches.occurrences_of("faces"), matches.occurrences_of("actions"), matches.occurrences_of("stutters"));
|
||||||
|
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.uwuify() {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => {
|
||||||
|
let mut app = Args::into_app();
|
||||||
|
app.error(ErrorKind::DisplayHelp, err.to_string()).exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_between_zero_and_one(input: &str) -> Result<(), String> {
|
||||||
|
let value = match input.parse::<f32>() {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(_) => return Err(String::from("The value must be a decimal number"))
|
||||||
|
};
|
||||||
|
|
||||||
|
if (0.0..=1.0).contains(&value) { return Ok(()); }
|
||||||
|
Err(String::from("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
|
||||||
|
}
|
@ -0,0 +1,203 @@
|
|||||||
|
use std::io::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<(), Error> {
|
||||||
|
// Handle Text
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
let uwu_text = self.uwuify_sentence(&self.text);
|
||||||
|
|
||||||
|
// Handle Text Output
|
||||||
|
if !self.output.is_empty() {
|
||||||
|
let mut uwu_out_file = match UwUOutFile::new(&self.output) {
|
||||||
|
Ok(uwu_out_file) => uwu_out_file,
|
||||||
|
Err(err) => return Err(err)
|
||||||
|
};
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
|
||||||
|
uwu_progress_bar.update_progess(uwu_text.len());
|
||||||
|
uwu_progress_bar.finish("UwU'ifying Complete!");
|
||||||
|
} else {
|
||||||
|
println!("{}", uwu_text);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle File I/O
|
||||||
|
let mut uwu_in_file = match UwUInFile::new(&self.input) {
|
||||||
|
Ok(uwu_in_file) => uwu_in_file,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
let mut uwu_out_file = match UwUOutFile::new(&self.output) {
|
||||||
|
Ok(uwu_out_file) => uwu_out_file,
|
||||||
|
Err(err) => return Err(err)
|
||||||
|
};
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
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*",
|
||||||
|
];
|
@ -0,0 +1,80 @@
|
|||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
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