172 lines
5.6 KiB
Rust
172 lines
5.6 KiB
Rust
use crate::model::processing::{PackError, PackResult};
|
|
use crate::model::{PackType, PackingContext};
|
|
use either::Either;
|
|
use futures_util::TryFutureExt;
|
|
use itertools::Itertools;
|
|
use magnetar_calckey_model::ck;
|
|
use magnetar_calckey_model::emoji::EmojiTag;
|
|
use magnetar_common::util::{parse_reaction, RawReaction};
|
|
use magnetar_sdk::types::emoji::{EmojiBase, PackEmojiBase};
|
|
use magnetar_sdk::types::note::{Reaction, ReactionShortcode, ReactionUnicode, ReactionUnknown};
|
|
use magnetar_sdk::types::Id;
|
|
use magnetar_sdk::{Packed, Required};
|
|
use std::sync::Arc;
|
|
|
|
pub fn parse_emoji_or_raw(tag: &str) -> Either<String, RawReaction> {
|
|
parse_reaction(tag).map_or_else(|| Either::Left(tag.to_string()), Either::Right)
|
|
}
|
|
|
|
pub fn shortcode_tag_or_none(value: &RawReaction) -> Option<EmojiTag<'_>> {
|
|
match value {
|
|
RawReaction::Shortcode { shortcode, host } => Some(EmojiTag {
|
|
name: shortcode.as_str(),
|
|
host: host.as_deref(),
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn resolve_reaction<'a>(
|
|
value: RawReaction,
|
|
code_lookup: &impl Fn(&str, Option<&str>) -> Option<&'a ck::emoji::Model>,
|
|
) -> Reaction {
|
|
match value {
|
|
RawReaction::Unicode(text) => Reaction::Unicode(ReactionUnicode(text)),
|
|
RawReaction::Shortcode { shortcode, host } => code_lookup(&shortcode, host.as_deref())
|
|
.map_or_else(
|
|
|| {
|
|
Reaction::Unknown(ReactionUnknown {
|
|
raw: format!(
|
|
":{shortcode}{}:",
|
|
host.as_deref().map(|h| format!("@{h}")).unwrap_or_default()
|
|
),
|
|
})
|
|
},
|
|
|e| {
|
|
Reaction::Shortcode(ReactionShortcode {
|
|
name: shortcode.clone(),
|
|
host: host.clone(),
|
|
url: e.public_url.clone(),
|
|
})
|
|
},
|
|
),
|
|
}
|
|
}
|
|
|
|
pub struct EmojiModel;
|
|
|
|
impl EmojiModel {
|
|
pub fn pack_existing(&self, ctx: &PackingContext, emoji: &ck::emoji::Model) -> PackEmojiBase {
|
|
PackEmojiBase::pack_from((
|
|
Required(Id::from(&emoji.id)),
|
|
Required(EmojiBase::extract(ctx, &emoji)),
|
|
))
|
|
}
|
|
|
|
pub async fn fetch_many_emojis(
|
|
&self,
|
|
ctx: &PackingContext,
|
|
shortcodes: &[String],
|
|
host: Option<&str>,
|
|
) -> PackResult<Vec<PackEmojiBase>> {
|
|
let emojis = ctx.service.emoji_cache.get_many(shortcodes, host).await?;
|
|
let packed_emojis = emojis.iter().map(|e| self.pack_existing(ctx, &e)).collect();
|
|
|
|
Ok(packed_emojis)
|
|
}
|
|
|
|
pub async fn fetch_many_tag_emojis(
|
|
&self,
|
|
ctx: &PackingContext,
|
|
tags: &[EmojiTag<'_>],
|
|
) -> PackResult<Vec<PackEmojiBase>> {
|
|
let emojis = ctx.service.emoji_cache.get_many_tagged(tags).await?;
|
|
let packed_emojis = emojis.iter().map(|e| self.pack_existing(ctx, &e)).collect();
|
|
|
|
Ok(packed_emojis)
|
|
}
|
|
|
|
pub fn deduplicate_emoji(&self, ctx: &PackingContext, emoji_list: Vec<String>) -> Vec<String> {
|
|
emoji_list
|
|
.into_iter()
|
|
.sorted()
|
|
.dedup()
|
|
.take(ctx.limits.max_emojis)
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
pub async fn resolve_reaction(
|
|
&self,
|
|
ctx: &PackingContext,
|
|
reaction: &str,
|
|
) -> PackResult<Reaction> {
|
|
let parsed = parse_emoji_or_raw(reaction);
|
|
|
|
Ok(match parsed {
|
|
Either::Left(raw) => Reaction::Unknown(ReactionUnknown { raw }),
|
|
Either::Right(raw) => {
|
|
let reaction_fetched = match shortcode_tag_or_none(&raw) {
|
|
Some(tag) => {
|
|
ctx.service
|
|
.emoji_cache
|
|
.get(tag.name, tag.host)
|
|
.map_err(PackError::from)
|
|
.await?
|
|
}
|
|
None => None,
|
|
};
|
|
|
|
let reaction_ref = reaction_fetched.as_ref().map(Arc::as_ref);
|
|
resolve_reaction(raw, &move |_, _| reaction_ref)
|
|
}
|
|
})
|
|
}
|
|
|
|
pub async fn resolve_reactions_many(
|
|
&self,
|
|
ctx: &PackingContext,
|
|
reactions_raw: &[String],
|
|
) -> PackResult<Vec<Reaction>> {
|
|
let reactions_parsed = reactions_raw
|
|
.iter()
|
|
.map(String::as_ref)
|
|
.map(parse_emoji_or_raw)
|
|
.collect::<Vec<_>>();
|
|
|
|
// Pick out all successfully-parsed shortcode emojis
|
|
let reactions_to_resolve = reactions_parsed
|
|
.iter()
|
|
.map(Either::as_ref)
|
|
.filter_map(Either::right)
|
|
.filter_map(shortcode_tag_or_none)
|
|
.collect::<Vec<_>>();
|
|
|
|
let reactions_fetched = ctx
|
|
.service
|
|
.emoji_cache
|
|
.get_many_tagged(&reactions_to_resolve)
|
|
.map_err(PackError::from)
|
|
.await?;
|
|
|
|
// Left reactions and the Right ones that didn't resolve to any emoji are turned back into Unknown
|
|
let reactions_resolved = reactions_parsed
|
|
.into_iter()
|
|
.map(|val| {
|
|
val.either(
|
|
|raw| Reaction::Unknown(ReactionUnknown { raw }),
|
|
|raw| {
|
|
resolve_reaction(raw, &|shortcode, host| {
|
|
reactions_fetched
|
|
.iter()
|
|
.find(|e| e.host.as_deref() == host && e.name == shortcode)
|
|
.map(Arc::as_ref)
|
|
})
|
|
},
|
|
)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
Ok(reactions_resolved)
|
|
}
|
|
}
|