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
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.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"
|
12
README.md
12
README.md
|
@ -1,3 +1,13 @@
|
||||||
# emoji-gen
|
# emoji-gen
|
||||||
|
|
||||||
A script written in Rust to generate a ZIP with right formating for a emoji pack.
|
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