I need to clean this later

This commit is contained in:
cutestnekoaqua 2023-01-07 21:27:40 +01:00
parent 150373b60a
commit 0d6cc660ca
No known key found for this signature in database
GPG key ID: 6BF0964A5069C1E0
5 changed files with 221 additions and 1 deletions

5
.gitignore vendored
View file

@ -14,3 +14,8 @@ Cargo.lock
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# Added by cargo
/target

4
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"editor.tabCompletion": "on",
"diffEditor.codeLens": true
}

16
Cargo.toml Normal file
View file

@ -0,0 +1,16 @@
[package]
name = "emoji-gen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.0.32", features = ["derive"] }
clap_complete = "4.0.7"
walkdir = "2"
debug_print = "1.0.0"
imghdr = "0.7.0"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
zip = "0.6.3"

View file

@ -1,3 +1,13 @@
# emoji-gen
A script written in Rust to generate a ZIP with right formating for a emoji pack.
### Usage
Put all emojis you want to import in a folder, use subfolders for different groups.
```a
cargo install emoji-gen
emoji-gen --folder . [optionally add --group "GroupName"]
```
upload the zip file to calckey and import it.

185
src/main.rs Normal file
View file

@ -0,0 +1,185 @@
use std::fs::File;
use std::fs::create_dir;
use std::io::Read;
use std::io::Seek;
use std::io::Write;
use std::rc::Rc;
use clap::Parser;
use clap::builder::OsStr;
use debug_print::debug_println;
use walkdir::WalkDir;
use walkdir::DirEntry;
use serde::{Deserialize, Serialize};
use serde_json::Result;
use zip::result::ZipError;
use zip::write::FileOptions;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Folder with the custom emojis to generate the pack from.
#[arg(short, long)]
folder: String,
/// Name for the pack
#[arg(short, long, default_value_t = ("Custom".to_string()))]
group: String,
}
#[derive(Serialize, Deserialize)]
struct Meta {
metaVersion: i8,
host: String,
/**
* Date and time representation returned by ECMAScript `Date.prototype.toString`.
*/
exportedAt: String,
emojis: Vec<Emoji>,
}
#[derive(Serialize, Deserialize)]
struct Emoji {
downloaded: bool,
fileName: String,
emoji: EmojiData,
}
#[derive(Serialize, Deserialize)]
struct EmojiData {
name: String,
category: String,
aliases: Vec<String>
}
fn main() {
let args = Args::parse();
let mut emojis = Vec::<Emoji>::new();
let group = Rc::new(args.group);
for result in WalkDir::new(args.folder).into_iter() {
if let Err(_) = result {
continue;
}
let opt_file = result.ok();
if opt_file.is_none() {
continue;
}
let file = opt_file.unwrap();
if !file.metadata().unwrap().is_file() {
continue;
}
let subcat = file.path().to_string_lossy()
.replace(file.path().file_name().unwrap().to_string_lossy().to_string().as_str(), "")
.replace("/", "")
.replace(".", "");
debug_println!("{}", file.path().file_name().unwrap().to_str().unwrap());
let emoji = owoifier(file, group.clone(), subcat);
if emoji.is_some() {
emojis.push(emoji.unwrap());
}
}
let meta = Meta {
metaVersion: 1,
host: "https://github.com/waterdev/owoifier".to_string(),
exportedAt: "".to_string(),
emojis: emojis,
};
let json = serde_json::to_string(&meta).unwrap();
let mut file = File::create("meta.json").unwrap();
write!(file, "{}", json);
zip(".", "../generated_emotes.zip");
println!("✅ Done! Importable ZIP file under '../generated_emotes.zip'");
}
fn owoifier(file: DirEntry, original_category: Rc<String>, subcategory: String) -> Option<Emoji> {
debug_println!("{}", file.path().display());
let path = file.path();
let image = imghdr::from_file(file.path()).unwrap();
if image.is_none() {
return None
}
let mut name = file.file_name().to_ascii_lowercase().into_string().unwrap();
name = str::replace(&name, file.path().extension().unwrap().to_string_lossy().to_string().as_str(), "");
name = str::replace(&name, " ", "_");
name = str::replace(&name, "-", "_");
name = str::replace(&name, ".", "");
let data = EmojiData{
name: name,
category: original_category.to_string() + " - " + subcategory.as_str(),
aliases: Vec::<String>::new()};
Some(Emoji {
downloaded: true,
fileName: path.to_string_lossy().into(),
emoji: data
})
}
fn zip(
src_dir: &str,
dst_file: &str,
) -> zip::result::ZipResult<()> {
if !std::path::Path::new(src_dir).is_dir() {
return Err(ZipError::FileNotFound);
}
let path = std::path::Path::new(dst_file);
let file = File::create(path).unwrap();
let walkdir = WalkDir::new(src_dir);
let it = walkdir.into_iter();
zip_dir(&mut it.filter_map(|e| e.ok()), src_dir, file, zip::CompressionMethod::Deflated)?;
Ok(())
}
fn zip_dir<T>(
it: &mut dyn Iterator<Item = DirEntry>,
prefix: &str,
writer: T,
method: zip::CompressionMethod,
) -> zip::result::ZipResult<()>
where
T: Write + Seek,
{
let mut zip = zip::ZipWriter::new(writer);
let options = FileOptions::default()
.compression_method(method)
.unix_permissions(0o755);
let mut buffer = Vec::new();
for entry in it {
let path = entry.path();
let name = path.strip_prefix(std::path::Path::new(prefix)).unwrap();
// Write file or directory explicitly
// Some unzip tools unzip files with directory paths correctly, some do not!
if path.is_file() {
debug_println!("adding file {:?} as {:?} ...", path, name);
#[allow(deprecated)]
zip.start_file_from_path(name, options)?;
let mut f = File::open(path)?;
f.read_to_end(&mut buffer)?;
zip.write_all(&*buffer)?;
buffer.clear();
} else if !name.as_os_str().is_empty() {
// Only if not root! Avoids path spec / warning
// and mapname conversion failed error on unzip
debug_println!("adding dir {:?} as {:?} ...", path, name);
#[allow(deprecated)]
zip.add_directory_from_path(name, options)?;
}
}
zip.finish()?;
Ok(())
}