diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts index 2a4e09519f..cee85a5688 100644 --- a/packages/backend/src/core/entities/EmojiEntityService.ts +++ b/packages/backend/src/core/entities/EmojiEntityService.ts @@ -22,7 +22,7 @@ export class EmojiEntityService { @bindThis public async pack( src: Emoji['id'] | Emoji, - opts: { omitHost?: boolean; omitId?: boolean; } = {}, + opts: { omitHost?: boolean; omitId?: boolean; withUrl?: boolean; } = {}, ): Promise> { const emoji = typeof src === 'object' ? src : await this.emojisRepository.findOneByOrFail({ id: src }); @@ -32,13 +32,15 @@ export class EmojiEntityService { name: emoji.name, category: emoji.category, host: opts.omitHost ? undefined : emoji.host, + // ?? emoji.originalUrl してるのは後方互換性のため + url: opts.withUrl ? (emoji.publicUrl ?? emoji.originalUrl) : undefined, }; } @bindThis public packMany( emojis: any[], - opts: { omitHost?: boolean; omitId?: boolean; } = {}, + opts: { omitHost?: boolean; omitId?: boolean; withUrl?: boolean; } = {}, ) { return Promise.all(emojis.map(x => this.pack(x, opts))); } diff --git a/packages/backend/src/models/schema/emoji.ts b/packages/backend/src/models/schema/emoji.ts index d897a0fc05..143f25373c 100644 --- a/packages/backend/src/models/schema/emoji.ts +++ b/packages/backend/src/models/schema/emoji.ts @@ -29,5 +29,9 @@ export const packedEmojiSchema = { optional: true, nullable: true, description: 'The local host is represented with `null`.', }, + url: { + type: 'string', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/emojis.ts b/packages/backend/src/server/api/endpoints/emojis.ts index 97dcfde596..db1eddc80a 100644 --- a/packages/backend/src/server/api/endpoints/emojis.ts +++ b/packages/backend/src/server/api/endpoints/emojis.ts @@ -83,6 +83,7 @@ export default class extends Endpoint { emojis: await this.emojiEntityService.packMany(emojis, { omitId: true, omitHost: true, + withUrl: true, }), }; }); diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue index b7dd0296cd..aaad81c656 100644 --- a/packages/frontend/src/components/global/MkEmoji.vue +++ b/packages/frontend/src/components/global/MkEmoji.vue @@ -12,6 +12,7 @@ import { getStaticImageUrl } from '@/scripts/media-proxy'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; import { defaultStore } from '@/store'; import { getEmojiName } from '@/scripts/emojilist'; +import { customEmojis } from '@/custom-emojis'; const props = defineProps<{ emoji: string; @@ -30,6 +31,9 @@ const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'nati const url = computed(() => { if (char.value) { return char2path(char.value); + } else if (props.host == null) { + const found = customEmojis.find(x => x.name === customEmojiName); + return found ? found.url : null; } else { const rawUrl = props.host ? `/emoji/${customEmojiName}@${props.host}.webp` : `/emoji/${customEmojiName}.webp`; return defaultStore.state.disableShowingAnimatedImages @@ -38,7 +42,7 @@ const url = computed(() => { } }); const alt = computed(() => isCustom.value ? `:${customEmojiName}:` : char.value); -let errored = $ref(false); +let errored = $ref(isCustom.value && url.value == null); // Searching from an array with 2000 items for every emoji felt like too energy-consuming, so I decided to do it lazily on pointerenter function computeTitle(event: PointerEvent): void { diff --git a/packages/frontend/src/custom-emojis.ts b/packages/frontend/src/custom-emojis.ts index 19469999b6..637ee9c06e 100644 --- a/packages/frontend/src/custom-emojis.ts +++ b/packages/frontend/src/custom-emojis.ts @@ -2,14 +2,19 @@ import { api } from './os'; import { miLocalStorage } from './local-storage'; const storageCache = miLocalStorage.getItem('emojis'); -export let customEmojis = storageCache ? JSON.parse(storageCache) : []; +export let customEmojis: { + name: string; + aliases: string[]; + category: string; + url: string; +}[] = storageCache ? JSON.parse(storageCache) : []; fetchCustomEmojis(); export async function fetchCustomEmojis() { const now = Date.now(); const lastFetchedAt = miLocalStorage.getItem('lastEmojisFetchedAt'); - if (lastFetchedAt && (now - parseInt(lastFetchedAt)) < 1000 * 60 * 60) return; + if (lastFetchedAt && (now - parseInt(lastFetchedAt)) < 1000 * 60 * 60 * 24) return; const res = await api('emojis', {});