mirror of
https://firefish.dev/firefish/emoji-gen.git
synced 2024-09-19 03:40:22 -06:00
Adding timestamp, editorconfig, update README, LICENSE (BSD as previously)
This commit is contained in:
parent
32e99bae10
commit
583d3645ca
7 changed files with 121 additions and 84 deletions
21
.editorconfig
Normal file
21
.editorconfig
Normal file
|
@ -0,0 +1,21 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.rs]
|
||||
max_line_length = 100
|
||||
|
||||
[*.md]
|
||||
# double whitespace at end of line
|
||||
# denotes a line break in Markdown
|
||||
trim_trailing_whitespace = false
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -13,9 +13,3 @@ Cargo.lock
|
|||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
|
||||
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "emoji-gen"
|
||||
description = "Emoji import file generator for Firefish"
|
||||
license = "MIT"
|
||||
license = "BSD"
|
||||
readme = "README.md"
|
||||
homepage = "https://git.joinfirefish.org/firefish/emoji-gen"
|
||||
repository = "https://git.joinfirefish.org/firefish/emoji-gen"
|
||||
authors = ["cutestnekoaqua <waterdev@galaxcrow.de>", "Mehdi Benadel <mehdi.benadel@gmail.com>"]
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -29,6 +29,8 @@ env_logger = "0.10.0"
|
|||
log = "0.4.19"
|
||||
indicatif = {version = "0.17.5", features = ["rayon"]}
|
||||
rayon = "1.7.0"
|
||||
datetime = "0.5.2"
|
||||
chrono = "0.4.26"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.10.0"
|
||||
|
|
17
LICENSE
17
LICENSE
|
@ -1,17 +0,0 @@
|
|||
Permission is hereby granted, without written agreement and without
|
||||
license or royalty fees, to use, copy, modify, and distribute this
|
||||
software and its documentation for any purpose, provided that the
|
||||
above copyright notice and the following two paragraphs appear in
|
||||
all copies of this software.
|
||||
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
28
LICENSE.md
Normal file
28
LICENSE.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# BSD 3-Clause License
|
||||
|
||||
_Copyright (c) 2023 April John, Mehdi Benadel_
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
13
README.md
13
README.md
|
@ -7,7 +7,14 @@ A script written in Rust to generate a ZIP with right formating for a emoji pack
|
|||
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"]
|
||||
git clone https://git.joinfirefish.org/firefish/emoji-gen.git
|
||||
|
||||
cargo install --path .
|
||||
|
||||
# To create an import zip from an emoji folder
|
||||
emoji-gen local --folder <emoji_folder> [--output <output_zip_file>]
|
||||
|
||||
# To create an import zip from a remote instance
|
||||
emoji-gen crawl --host https://firefish.social [--output <output_zip_file>]
|
||||
```
|
||||
upload the zip file to Firefish and import it.
|
||||
upload the zip file to Firefish and import it.
|
||||
|
|
114
src/main.rs
114
src/main.rs
|
@ -26,18 +26,20 @@ use zip::write::FileOptions;
|
|||
use env_logger;
|
||||
use log::{debug, warn, error};
|
||||
|
||||
use chrono::Local;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Option
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
command: Command,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Command {
|
||||
/// Help message for read.
|
||||
Local {
|
||||
/// Create a zip from a local folder
|
||||
Local {
|
||||
/// Output file path
|
||||
#[arg(short = 'o', long = "output", default_value_t = String::from("generated_emojis"))]
|
||||
outputFilepath: String,
|
||||
|
@ -45,25 +47,25 @@ enum Command {
|
|||
/// Folder with the custom emojis to generate the pack from.
|
||||
#[arg(short, long)]
|
||||
folder: String,
|
||||
|
||||
|
||||
/// Origin Host of the emoji
|
||||
#[arg(short = 'h', long = "host", default_value_t = String::from("https://git.joinfirefish.org/firefish/emoji-gen"))]
|
||||
originHost: String,
|
||||
|
||||
|
||||
/// Name for the pack
|
||||
#[arg(short, long, default_value_t = ("Custom").to_string())]
|
||||
group: String,
|
||||
},
|
||||
/// Help message for write.
|
||||
Crawl {
|
||||
},
|
||||
/// Create a zip from a remote instance content
|
||||
Crawl {
|
||||
/// Output file path
|
||||
#[arg(short = 'o', long = "output", default_value_t = String::from("generated_emojis"))]
|
||||
outputFilepath: String,
|
||||
|
||||
/// Host to crawl emojis from
|
||||
#[arg(short = 'h', long = "host", default_value_t = String::from("https://firefish.social"))]
|
||||
#[arg(short, long)]
|
||||
host: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -78,9 +80,9 @@ struct Meta {
|
|||
}
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct EmojiResponse {
|
||||
shortcode: Option<String>,
|
||||
url: Option<String>,
|
||||
static_url: String,
|
||||
shortcode: Option<String>,
|
||||
url: Option<String>,
|
||||
static_url: String,
|
||||
category: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -100,24 +102,24 @@ struct EmojiData {
|
|||
|
||||
fn getTypename(typeEnum: imghdr::Type) -> &'static str {
|
||||
return match typeEnum {
|
||||
imghdr::Type::Gif => "gif",
|
||||
imghdr::Type::Tiff => "tiff",
|
||||
imghdr::Type::Rast => "rast",
|
||||
imghdr::Type::Xbm => "xbm",
|
||||
imghdr::Type::Jpeg => "jpg",
|
||||
imghdr::Type::Bmp => "bmp",
|
||||
imghdr::Type::Png => "png",
|
||||
imghdr::Type::Webp => "webp",
|
||||
imghdr::Type::Exr => "exr",
|
||||
imghdr::Type::Avif => "avif",
|
||||
imghdr::Type::Bgp => "bgp",
|
||||
imghdr::Type::Bmp => "bmp",
|
||||
imghdr::Type::Exr => "exr",
|
||||
imghdr::Type::Flif => "flif",
|
||||
imghdr::Type::Gif => "gif",
|
||||
imghdr::Type::Ico => "ico",
|
||||
imghdr::Type::Jpeg => "jpg",
|
||||
imghdr::Type::Pbm => "pbm",
|
||||
imghdr::Type::Pgm => "pgm",
|
||||
imghdr::Type::Png => "png",
|
||||
imghdr::Type::Ppm => "ppm",
|
||||
imghdr::Type::Rast => "rast",
|
||||
imghdr::Type::Rgb => "rgb",
|
||||
imghdr::Type::Rgbe => "rgbe",
|
||||
imghdr::Type::Flif => "flif",
|
||||
imghdr::Type::Ico => "ico",
|
||||
imghdr::Type::Avif => "avif",
|
||||
imghdr::Type::Tiff => "tiff",
|
||||
imghdr::Type::Webp => "webp",
|
||||
imghdr::Type::Xbm => "xbm",
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -180,7 +182,7 @@ fn process(
|
|||
hostUrl = host;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
generate_meta(
|
||||
hostUrl,
|
||||
emojis,
|
||||
|
@ -197,7 +199,7 @@ fn process(
|
|||
|
||||
fn prepare_zip_filepath (outputFilepath: String) -> Result<PathBuf, EmojiGenError> {
|
||||
let mut zipFilepath = PathBuf::from(outputFilepath.as_str());
|
||||
|
||||
|
||||
zipFilepath.set_extension("zip");
|
||||
|
||||
if zipFilepath.exists() {
|
||||
|
@ -212,10 +214,10 @@ fn get_host_emojis(host: &Url, tmpFolder: &Path) -> Result<Vec<Emoji>, EmojiGenE
|
|||
println!("Getting all the fine emojis from Url '{}'...", host.as_str());
|
||||
|
||||
let hostUrl = &host.join("/api/v1/custom_emojis").unwrap();
|
||||
|
||||
let emojis = match reqwest::blocking::get(hostUrl.clone()) {
|
||||
Ok(response) => match response.json::<Vec<EmojiResponse>>() {
|
||||
Ok(emojiRes) => {
|
||||
|
||||
let emojis = match reqwest::blocking::get(hostUrl.clone()) {
|
||||
Ok(response) => match response.json::<Vec<EmojiResponse>>() {
|
||||
Ok(emojiRes) => {
|
||||
let emojos: Vec<EmojiResponse> = emojiRes;
|
||||
let iter = emojos.iter();
|
||||
Ok(iter.progress_count(emojos.len() as u64).map(| res |
|
||||
|
@ -227,12 +229,12 @@ fn get_host_emojis(host: &Url, tmpFolder: &Path) -> Result<Vec<Emoji>, EmojiGenE
|
|||
)
|
||||
).filter_map(|r| r.ok()).collect::<Vec<Emoji>>())
|
||||
},
|
||||
Err(_) => {
|
||||
Err(_) => {
|
||||
Err(report!(EmojiGenError::ImageFetchingFailed)
|
||||
.attach_printable(format!("Could not get emoji list from url '{}'.", hostUrl.as_str())))
|
||||
},
|
||||
},
|
||||
Err(_) => {
|
||||
Err(_) => {
|
||||
Err(report!(EmojiGenError::ImageFetchingFailed)
|
||||
.attach_printable(format!("Could not get response from url '{}'.", hostUrl.as_str())))
|
||||
},
|
||||
|
@ -245,12 +247,12 @@ fn get_host_emoji_data(fileUrl: Url, name: String, category: String, tmpFolder:
|
|||
debug!("{}", fileUrl.to_string());
|
||||
|
||||
let newFilename = get_image_from_url(&fileUrl, tmpFolder, name.clone())?;
|
||||
|
||||
|
||||
let data: EmojiData = EmojiData{
|
||||
name: name,
|
||||
category: category.to_string(),
|
||||
aliases: Vec::<String>::new()};
|
||||
|
||||
|
||||
Ok(Emoji {
|
||||
downloaded: true,
|
||||
fileName: newFilename,
|
||||
|
@ -259,13 +261,13 @@ fn get_host_emoji_data(fileUrl: Url, name: String, category: String, tmpFolder:
|
|||
}
|
||||
|
||||
fn get_image_from_url(fileUrl: &Url, tmpFolder: &Path, filename: String) -> Result<String, EmojiGenError> {
|
||||
|
||||
|
||||
let img_bytes = &reqwest::blocking::get(fileUrl.clone())
|
||||
.map_err(|_|
|
||||
report!(EmojiGenError::ImageFetchingFailed)
|
||||
.attach_printable(format!("Could not get image file from url '{}'.", fileUrl.as_str()))
|
||||
)?.bytes().unwrap();
|
||||
|
||||
|
||||
let mut tmpFilepath: PathBuf = tmpFolder.join(filename);
|
||||
|
||||
match imghdr::from_bytes(img_bytes) {
|
||||
|
@ -274,7 +276,7 @@ fn get_image_from_url(fileUrl: &Url, tmpFolder: &Path, filename: String) -> Resu
|
|||
};
|
||||
|
||||
println!("Creating image file at path '{}'...", tmpFilepath.display());
|
||||
|
||||
|
||||
let mut imageFile = File::create(tmpFilepath.as_os_str())
|
||||
.map_err(|_|
|
||||
report!(EmojiGenError::ImageFetchingFailed)
|
||||
|
@ -307,7 +309,7 @@ fn get_local_emojis(folder: &Path, group: String, tmpFolder: &Path) -> Result<Ve
|
|||
}?;
|
||||
|
||||
println!("Getting all the fine emojis from folder '{}'...", folder.display());
|
||||
|
||||
|
||||
let mut emojis = Vec::<Emoji>::new();
|
||||
|
||||
let iter = WalkDir::new(folder).into_iter();
|
||||
|
@ -327,7 +329,7 @@ fn get_local_emojis(folder: &Path, group: String, tmpFolder: &Path) -> Result<Ve
|
|||
}
|
||||
|
||||
let filename = file.path().file_name().unwrap();
|
||||
|
||||
|
||||
println!("Checking file '{}'...", filename.to_string_lossy());
|
||||
|
||||
let image = imghdr::from_file(file.path())
|
||||
|
@ -335,7 +337,7 @@ fn get_local_emojis(folder: &Path, group: String, tmpFolder: &Path) -> Result<Ve
|
|||
report!(EmojiGenError::ImageFetchingFailed)
|
||||
.attach_printable(format!("Could not get image at path '{}'.", file.path().display()))
|
||||
)?;
|
||||
|
||||
|
||||
if image.is_none() {
|
||||
if filename.to_ascii_uppercase() == "LICENSE" || filename.to_ascii_uppercase() == "LICENSE.md" {
|
||||
get_image_from_path(&file.path(), tmpFolder).map_err(|err| warn!("{}", err)).unwrap();
|
||||
|
@ -343,7 +345,7 @@ fn get_local_emojis(folder: &Path, group: String, tmpFolder: &Path) -> Result<Ve
|
|||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
match get_local_emoji_data(file, group.clone().into(), tmpFolder) {
|
||||
Ok(emoji) => {
|
||||
emojis.push(emoji);
|
||||
|
@ -360,17 +362,17 @@ fn get_local_emojis(folder: &Path, group: String, tmpFolder: &Path) -> Result<Ve
|
|||
|
||||
fn get_local_emoji_data(file: DirEntry, original_category: Rc<String>, tmpFolder: &Path) -> Result<Emoji, EmojiGenError> {
|
||||
debug!("{}", file.path().display());
|
||||
|
||||
|
||||
let fileName = String::from(file.file_name().to_str().unwrap());
|
||||
let name = String::from(file.path().file_stem().unwrap().to_str().unwrap()).replace(&[' ', '-'][..], "_");
|
||||
|
||||
get_image_from_path(&file.path(), tmpFolder)?;
|
||||
|
||||
|
||||
let data = EmojiData{
|
||||
name: name,
|
||||
category: original_category.to_string(),
|
||||
aliases: Vec::<String>::new()};
|
||||
|
||||
|
||||
Ok(Emoji {
|
||||
downloaded: true,
|
||||
fileName,
|
||||
|
@ -379,7 +381,7 @@ fn get_local_emoji_data(file: DirEntry, original_category: Rc<String>, tmpFolder
|
|||
}
|
||||
|
||||
fn get_image_from_path(filePath: &Path, tmpFolder: &Path) -> Result<(), EmojiGenError> {
|
||||
|
||||
|
||||
let filename = filePath.file_name().unwrap();
|
||||
let img_data = std::fs::read(filePath.as_os_str())
|
||||
.map_err(|_|
|
||||
|
@ -388,7 +390,7 @@ fn get_image_from_path(filePath: &Path, tmpFolder: &Path) -> Result<(), EmojiGe
|
|||
)?;
|
||||
|
||||
let img_bytes = img_data.as_slice();
|
||||
|
||||
|
||||
let imageFilePath = &tmpFolder.join(filename);
|
||||
let mut imageFile = File::create(imageFilePath)
|
||||
.map_err(|_|
|
||||
|
@ -413,7 +415,7 @@ fn generate_meta(
|
|||
let meta = Meta {
|
||||
metaVersion: 1,
|
||||
host: host,
|
||||
exportedAt: "".to_string(),
|
||||
exportedAt: Local::now().to_rfc3339(),
|
||||
emojis: emojis,
|
||||
};
|
||||
|
||||
|
@ -451,10 +453,10 @@ fn zip(
|
|||
return Err(report!(EmojiGenError::ZipCreationFailed)
|
||||
.attach_printable(format!("Could not find folder '{}'.", src_dir.display())))
|
||||
}
|
||||
|
||||
|
||||
println!("Creating zip file at path '{}'...", dst_file.display());
|
||||
|
||||
let zipFile = &File::create(dst_file).map_err(|_|
|
||||
|
||||
let zipFile = &File::create(dst_file).map_err(|_|
|
||||
report!(EmojiGenError::ZipCreationFailed)
|
||||
.attach_printable(format!("Could not create file '{}'.", dst_file.display()))
|
||||
)?;
|
||||
|
@ -465,15 +467,15 @@ fn zip(
|
|||
|
||||
let iter = WalkDir::new(src_dir).into_iter();
|
||||
let count = WalkDir::new(src_dir).into_iter().count() as u64;
|
||||
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
for entryRes in iter.progress_count(count) {
|
||||
let entry = entryRes.map_err(|_|
|
||||
let entry = entryRes.map_err(|_|
|
||||
report!(EmojiGenError::ZipCreationFailed)
|
||||
.attach_printable(format!("Could get path to a file in folder '{}'.", src_dir.display()))
|
||||
)?;
|
||||
let path = entry.path();
|
||||
let name = path.strip_prefix(src_dir).map_err(|_|
|
||||
let name = path.strip_prefix(src_dir).map_err(|_|
|
||||
report!(EmojiGenError::ZipCreationFailed)
|
||||
.attach_printable(format!("Could not strip prefix on file path '{}'.", path.display()))
|
||||
)?;
|
||||
|
@ -492,7 +494,7 @@ fn zip(
|
|||
report!(EmojiGenError::ZipCreationFailed)
|
||||
.attach_printable(format!("Could not read file '{}'.", path.display()))
|
||||
)?;
|
||||
|
||||
|
||||
f.read_to_end(&mut buffer)
|
||||
.map_err(|_|
|
||||
report!(EmojiGenError::ZipCreationFailed)
|
||||
|
@ -522,4 +524,4 @@ fn zip(
|
|||
.attach_printable(format!("Could not close zip file '{:?}'.", zipFile))
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue