tetratto-core 16.0.2

The core behind Tetratto
Documentation
use serde::{Serialize, Deserialize};
use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp};
pub use buckets_core::model::*;

#[derive(Serialize, Deserialize)]
pub struct CustomEmoji {
    pub id: usize,
    pub created: usize,
    pub owner: usize,
    pub community: usize,
    pub upload_id: usize,
    pub name: String,
    pub is_animated: bool,
}

pub type EmojiParserResult = Vec<(String, usize, String)>;

impl CustomEmoji {
    /// Create a new [`CustomEmoji`].
    pub fn new(
        owner: usize,
        community: usize,
        upload_id: usize,
        name: String,
        is_animated: bool,
    ) -> Self {
        Self {
            id: Snowflake::new().to_string().parse::<usize>().unwrap(),
            created: unix_epoch_timestamp(),
            owner,
            community,
            upload_id,
            name,
            is_animated,
        }
    }

    /// Replace emojis in the given input string.
    pub fn replace(input: &str) -> String {
        let res = Self::parse(input);
        let mut out = input.to_string();

        for emoji in res {
            if emoji.1 == 0 {
                out = out.replace(
                    &emoji.0,
                    match emoji.2.as_str() {
                        "100" => "💯",
                        "thumbs_up" => "👍",
                        "thumbs_down" => "👎",
                        _ => match emojis::get_by_shortcode(&emoji.2) {
                            Some(e) => e.as_str(),
                            None => &emoji.0,
                        },
                    },
                );
            } else {
                out = out.replace(
                    &emoji.0,
                    &format!(
                        "<img class=\"emoji\" src=\"/api/v1/communities/{}/emojis/{}\" />",
                        emoji.1, emoji.2
                    ),
                );
            }
        }

        out
    }

    /// Parse text for emojis.
    ///
    /// Another "great" parser, just like the mentions parser.
    ///
    /// # Returns
    /// `(capture, community id, emoji name)`
    pub fn parse(input: &str) -> EmojiParserResult {
        let mut out = Vec::new();
        let mut buffer: String = String::new();

        let mut escape: bool = false;
        let mut in_emoji: bool = false;

        let mut chars = input.chars();
        while let Some(char) = chars.next() {
            if char == '\\' && !escape {
                escape = true;
                continue;
            } else if char == ':' && !escape {
                let mut community_id: String = String::new();
                let mut accepting_community_id_chars: bool = true;
                let mut emoji_name: String = String::new();

                for (char_count, char) in (0_u32..).zip(chars.by_ref()) {
                    if (char == ':') | (char == ' ') {
                        in_emoji = false;
                        break;
                    }

                    if char.is_ascii_digit() && accepting_community_id_chars {
                        community_id.push(char);
                    } else if char == '.' {
                        // the period closes the community id
                        accepting_community_id_chars = false;
                    } else {
                        emoji_name.push(char);
                    }

                    if char_count >= 4 && community_id.is_empty() {
                        accepting_community_id_chars = false;
                    }
                }

                out.push((
                    format!(
                        ":{}{emoji_name}:",
                        if !community_id.is_empty() {
                            format!("{community_id}.")
                        } else {
                            String::new()
                        }
                    ),
                    community_id.parse::<usize>().unwrap_or(0),
                    emoji_name,
                ));

                continue;
            } else if in_emoji {
                buffer.push(char);
            }

            escape = false;
        }

        out
    }
}