jormungandr-bite/packages/backend/src/misc/reaction-lib.ts

132 lines
3.5 KiB
TypeScript
Raw Normal View History

2021-11-13 03:10:14 -07: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': '👍',
2023-01-12 15:14:45 -07:00
'love': '❤️', // ここに記述する場合は異体字セレクタを入れない <- not that good because modern browsers just display it as the red heart so just convert it to it to not end up with two seperate reactions of "the same emoji" for the user
'laugh': '😆',
'hmm': '🤔',
'surprise': '😮',
'congrats': '🎉',
'angry': '💢',
'confused': '😥',
'rip': '😇',
'pudding': '🍮',
'star': '⭐',
};
export async function getFallbackReaction(): Promise<string> {
const meta = await fetchMeta();
return meta.defaultReaction;
}
2020-02-18 14:36:50 -07: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-18 14:36:50 -07:00
} else {
_reactions[legacies[reaction]] = reactions[reaction];
2020-02-18 14:36:50 -07: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-18 14:36:50 -07:00
}
export async function toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise<string> {
if (reaction == null) return await getFallbackReaction();
reacterHost = toPunyNullable(reacterHost);
2023-01-12 15:14:45 -07:00
// Convert string-type reactions to pictograms
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
2023-01-12 15:14:45 -07:00
// Unicode Pictograms
/*const match = emojiRegex.exec(reaction);
if (match) {
2023-01-12 15:14:45 -07:00
// One pictogram with ligatures
const unicode = match[0];
2023-01-12 15:14:45 -07:00
// variant character selector removal
return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, '');
2023-01-12 15:14:45 -07:00
}*/
2020-04-15 09:47:17 -06:00
const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
if (custom) {
const name = custom[1];
const emoji = await Emojis.findOneBy({
host: reacterHost ?? IsNull(),
name,
});
2020-05-10 02:25:16 -06: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 07:58:30 -07:00
host,
};
}
return {
reaction: str,
name: undefined,
2021-12-09 07:58:30 -07:00
host: undefined,
};
}
export function convertLegacyReaction(reaction: string): string {
reaction = decodeReaction(reaction).reaction;
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
return reaction;
}