import { emojiRegex } from './emoji-regex.js'; import { fetchMeta } from './fetch-meta.js'; import { Emojis } from '@/models/index.js'; import { toPunyNullable } from './convert-host.js'; const legacies: Record = { 'like': '👍', 'love': '❤', // ここに記述する場合は異体字セレクタを入れない 'laugh': '😆', 'hmm': '🤔', 'surprise': '😮', 'congrats': '🎉', 'angry': '💢', 'confused': '😥', 'rip': '😇', 'pudding': '🍮', 'star': '⭐', }; export async function getFallbackReaction(): Promise { const meta = await fetchMeta(); return meta.useStarForReactionFallback ? '⭐' : '👍'; } export function convertLegacyReactions(reactions: Record) { const _reactions = {} as Record; for (const reaction of Object.keys(reactions)) { if (reactions[reaction] <= 0) continue; if (Object.keys(legacies).includes(reaction)) { if (_reactions[legacies[reaction]]) { _reactions[legacies[reaction]] += reactions[reaction]; } else { _reactions[legacies[reaction]] = reactions[reaction]; } } else { if (_reactions[reaction]) { _reactions[reaction] += reactions[reaction]; } else { _reactions[reaction] = reactions[reaction]; } } } const _reactions2 = {} as Record; for (const reaction of Object.keys(_reactions)) { _reactions2[decodeReaction(reaction).reaction] = _reactions[reaction]; } return _reactions2; } export async function toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise { if (reaction == null) return await getFallbackReaction(); reacterHost = toPunyNullable(reacterHost); // 文字列タイプのリアクションを絵文字に変換 if (Object.keys(legacies).includes(reaction)) return legacies[reaction]; // Unicode絵文字 const match = emojiRegex.exec(reaction); if (match) { // 合字を含む1つの絵文字 const unicode = match[0]; // 異体字セレクタ除去 return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, ''); } const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); if (custom) { const name = custom[1]; const emoji = await Emojis.findOne({ host: reacterHost || null, name, }); if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; } return await getFallbackReaction(); } type DecodedReaction = { /** * リアクション名 (Unicode Emoji or ':name@hostname' or ':name@.') */ reaction: string; /** * name (カスタム絵文字の場合name, Emojiクエリに使う) */ name?: string; /** * host (カスタム絵文字の場合host, Emojiクエリに使う) */ host?: string | null; }; export function decodeReaction(str: string): DecodedReaction { const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/); if (custom) { const name = custom[1]; const host = custom[2] || null; return { reaction: `:${name}@${host || '.'}:`, // ローカル分は@以降を省略するのではなく.にする name, host }; } return { reaction: str, name: undefined, host: undefined }; } export function convertLegacyReaction(reaction: string): string { reaction = decodeReaction(reaction).reaction; if (Object.keys(legacies).includes(reaction)) return legacies[reaction]; return reaction; }