From 275244b941085a22dfbba022c7eb7dafcd99d837 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 10 Apr 2024 15:40:43 -1000 Subject: [PATCH] Resolve custom emojis from federated posts --- database/entities/Emoji.ts | 24 +++++++++++++++++++-- database/entities/Status.ts | 42 ++++++++++++++++++++++++++----------- database/entities/User.ts | 4 ++-- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/database/entities/Emoji.ts b/database/entities/Emoji.ts index f2b5d3b7..1b1c93a0 100644 --- a/database/entities/Emoji.ts +++ b/database/entities/Emoji.ts @@ -2,6 +2,7 @@ import type { Emoji } from "@prisma/client"; import { client } from "~database/datasource"; import type { APIEmoji } from "~types/entities/emoji"; import type * as Lysand from "lysand-types"; +import { addInstanceIfNotExists } from "./Instance"; /** * Represents an emoji entity in the database. @@ -29,16 +30,28 @@ export const parseEmojis = async (text: string): Promise => { }); }; -export const addEmojiIfNotExists = async (emoji: Lysand.Emoji) => { +/** + * Gets an emoji from the database, and fetches it from the remote instance if it doesn't exist. + * @param emoji Emoji to fetch + * @param host Host to fetch the emoji from if remote + * @returns The emoji + */ +export const fetchEmoji = async (emoji: Lysand.Emoji, host?: string) => { const existingEmoji = await client.emoji.findFirst({ where: { shortcode: emoji.name, - instance: null, + instance: host + ? { + base_url: host, + } + : null, }, }); if (existingEmoji) return existingEmoji; + const instance = host ? await addInstanceIfNotExists(host) : null; + return await client.emoji.create({ data: { shortcode: emoji.name, @@ -46,6 +59,13 @@ export const addEmojiIfNotExists = async (emoji: Lysand.Emoji) => { alt: emoji.alt || emoji.url[0].description || undefined, content_type: Object.keys(emoji.url)[0], visible_in_picker: true, + instance: host + ? { + connect: { + id: instance?.id, + }, + } + : undefined, }, }); }; diff --git a/database/entities/Status.ts b/database/entities/Status.ts index 73155639..6ba0ce44 100644 --- a/database/entities/Status.ts +++ b/database/entities/Status.ts @@ -26,7 +26,7 @@ import { attachmentToAPI, attachmentToLysand, } from "./Attachment"; -import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji"; +import { emojiToAPI, emojiToLysand, fetchEmoji, parseEmojis } from "./Emoji"; import type { UserWithRelations } from "./User"; import { getUserUri, resolveUser, resolveWebFinger, userToAPI } from "./User"; import { statusAndUserRelations, userRelations } from "./relations"; @@ -116,16 +116,34 @@ export const resolveStatus = async ( throw new Error("Invalid object author"); } - const attachments = ( - await Promise.all( - (note.attachments ?? []).map((attachment) => - attachmentFromLysand(attachment).catch((e) => { - console.error(e); - return null; - }), - ), - ) - ).filter((attachment) => attachment !== null) as Attachment[]; + const attachments = []; + + for (const attachment of note.attachments ?? []) { + const resolvedAttachment = await attachmentFromLysand(attachment).catch( + (e) => { + console.error(e); + return null; + }, + ); + + if (resolvedAttachment) { + attachments.push(resolvedAttachment); + } + } + + const emojis = []; + + for (const emoji of note.extensions?.["org.lysand:custom_emojis"]?.emojis ?? + []) { + const resolvedEmoji = await fetchEmoji(emoji).catch((e) => { + console.error(e); + return null; + }); + + if (resolvedEmoji) { + emojis.push(resolvedEmoji); + } + } return await createNewStatus( author, @@ -137,7 +155,7 @@ export const resolveStatus = async ( note.visibility as APIStatus["visibility"], note.is_sensitive ?? false, note.subject ?? "", - [], + emojis, note.uri, await Promise.all( (note.mentions ?? []) diff --git a/database/entities/User.ts b/database/entities/User.ts index 3ca5de57..7cd40f94 100644 --- a/database/entities/User.ts +++ b/database/entities/User.ts @@ -7,7 +7,7 @@ import { client } from "~database/datasource"; import type { APIAccount } from "~types/entities/account"; import type { APISource } from "~types/entities/source"; import type * as Lysand from "lysand-types"; -import { addEmojiIfNotExists, emojiToAPI, emojiToLysand } from "./Emoji"; +import { fetchEmoji, emojiToAPI, emojiToLysand } from "./Emoji"; import { addInstanceIfNotExists } from "./Instance"; import { userRelations } from "./relations"; import { createNewRelationship } from "./Relationship"; @@ -241,7 +241,7 @@ export const resolveUser = async (uri: string) => { const emojis = []; for (const emoji of userEmojis) { - emojis.push(await addEmojiIfNotExists(emoji)); + emojis.push(await fetchEmoji(emoji)); } const user = await client.user.create({