misskey/packages/backend/src/misc/reaction-lib.ts

132 lines
3.4 KiB
TypeScript
Raw Normal View History

2021-11-13 19:10:14 +09:00
/* eslint-disable key-spacing */
import { emojiRegex } from './emoji-regex.js';
import { fetchMeta } from './fetch-meta.js';
import { Emojis } from '@/models/index.js';
import { toPunyNullable } from './convert-host.js';
import { IsNull } from 'typeorm';
const legacies: Record<string, string> = {
'like': '👍',
'love': '❤', // ここに記述する場合は異体字セレクタを入れない
'laugh': '😆',
'hmm': '🤔',
'surprise': '😮',
'congrats': '🎉',
'angry': '💢',
'confused': '😥',
'rip': '😇',
'pudding': '🍮',
'star': '⭐',
};
export async function getFallbackReaction(): Promise<string> {
const meta = await fetchMeta();
return meta.useStarForReactionFallback ? '⭐' : '👍';
}
2020-02-19 06:36:50 +09:00
export function convertLegacyReactions(reactions: Record<string, number>) {
const _reactions = {} as Record<string, number>;
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];
2020-02-19 06:36:50 +09:00
} else {
_reactions[legacies[reaction]] = reactions[reaction];
2020-02-19 06:36:50 +09:00
}
} else {
if (_reactions[reaction]) {
_reactions[reaction] += reactions[reaction];
} else {
_reactions[reaction] = reactions[reaction];
}
}
}
const _reactions2 = {} as Record<string, number>;
for (const reaction of Object.keys(_reactions)) {
_reactions2[decodeReaction(reaction).reaction] = _reactions[reaction];
}
return _reactions2;
2020-02-19 06:36:50 +09:00
}
export async function toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise<string> {
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, '');
}
2020-04-16 00:47:17 +09:00
const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
if (custom) {
const name = custom[1];
const emoji = await Emojis.findOneBy({
host: reacterHost ?? IsNull(),
name,
});
2020-05-10 17:25:16 +09:00
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,
2021-12-09 23:58:30 +09:00
host,
};
}
return {
reaction: str,
name: undefined,
2021-12-09 23:58:30 +09:00
host: undefined,
};
}
export function convertLegacyReaction(reaction: string): string {
reaction = decodeReaction(reaction).reaction;
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
return reaction;
}