mirror of
https://firefish.dev/firefish/emoji-gen.git
synced 2024-09-19 11:50:21 -06:00
I need to clean this later
This commit is contained in:
parent
150373b60a
commit
0d6cc660ca
5 changed files with 221 additions and 1 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -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
4
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"editor.tabCompletion": "on",
|
||||
"diffEditor.codeLens": true
|
||||
}
|
16
Cargo.toml
Normal file
16
Cargo.toml
Normal 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"
|
10
README.md
10
README.md
|
@ -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
185
src/main.rs
Normal 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(())
|
||||
}
|
Loading…
Reference in a new issue