Support sending custom emoji in messages and reactions

This commit is contained in:
2026-10-11 18:11:23 +07:00
parent 6dad27469d
commit c87c789439
13 changed files with 288 additions and 183 deletions
+50
View File
@@ -51,3 +51,53 @@ impl EventExt for UnsignedEvent {
public_keys.into_iter().unique().sorted().collect()
}
}
/// Custom emoji (NIP-30) declared by `emoji` tags, first per shortcode wins
pub fn emojis_from_tags(tags: &Tags) -> Vec<(String, Url)> {
let mut emojis: Vec<(String, Url)> = Vec::new();
for tag in tags.iter() {
let Ok(Nip30Tag::Emoji {
shortcode,
image_url,
..
}) = Nip30Tag::try_from(tag)
else {
continue;
};
if !emojis.iter().any(|(existing, _)| *existing == shortcode) {
emojis.push((shortcode, image_url));
}
}
emojis
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn emojis_from_tags_parses_and_deduplicates() {
let tags = Tags::from_list(vec![
Tag::parse(vec!["emoji", "soapbox", "https://example.com/soapbox.png"]).unwrap(),
Tag::parse(vec!["emoji", "soapbox", "https://example.com/other.png"]).unwrap(),
Tag::parse(vec![
"emoji",
"bad shortcode",
"https://example.com/bad.png",
])
.unwrap(),
]);
let emojis = emojis_from_tags(&tags);
assert_eq!(emojis.len(), 1);
assert_eq!(emojis[0].0, "soapbox");
assert_eq!(
emojis[0].1,
Url::parse("https://example.com/soapbox.png").unwrap()
);
}
}