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

134 lines
3.2 KiB
TypeScript
Raw Normal View History

2023-01-13 05:40:33 +01:00
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";
2023-02-17 09:01:22 +01:00
const legacies = new Map([
['like', '👍'],
['love', '❤️'],
['laugh', '😆'],
['hmm', '🤔'],
['surprise', '😮'],
['congrats', '🎉'],
['angry', '💢'],
['confused', '😥'],
['rip', '😇'],
['pudding', '🍮'],
['star', '⭐'],
]);
export async function getFallbackReaction() {
const meta = await fetchMeta();
return meta.defaultReaction;
}
2020-02-18 22:36:50 +01:00
export function convertLegacyReactions(reactions: Record<string, number>) {
2023-02-17 09:01:22 +01:00
const _reactions = new Map();
const decodedReactions = new Map();
2020-02-18 22:36:50 +01:00
2023-02-17 09:01:22 +01:00
for (const reaction in reactions) {
if (reactions[reaction] <= 0) continue;
2023-02-17 09:01:22 +01:00
let decodedReaction;
if (decodedReactions.has(reaction)) {
decodedReaction = decodedReactions.get(reaction);
2020-02-18 22:36:50 +01:00
} else {
2023-02-17 09:01:22 +01:00
decodedReaction = decodeReaction(reaction);
decodedReactions.set(reaction, decodedReaction);
2020-02-18 22:36:50 +01:00
}
2023-02-17 09:01:22 +01:00
let emoji = legacies.get(decodedReaction.reaction);
if (emoji) {
_reactions.set(emoji, (_reactions.get(emoji) || 0) + reactions[reaction]);
} else {
_reactions.set(reaction, (_reactions.get(reaction) || 0) + reactions[reaction]);
}
}
2023-02-17 09:01:22 +01:00
const _reactions2 = new Map();
for (const [reaction, count] of _reactions) {
const decodedReaction = decodedReactions.get(reaction);
_reactions2.set(decodedReaction.reaction, count);
}
2023-02-17 09:01:22 +01:00
return Object.fromEntries(_reactions2);
2020-02-18 22:36:50 +01:00
}
2023-01-13 05:40:33 +01:00
export async function toDbReaction(
reaction?: string | null,
reacterHost?: string | null,
): Promise<string> {
2023-02-17 09:01:22 +01:00
if (!reaction) return await getFallbackReaction();
reacterHost = toPunyNullable(reacterHost);
2023-02-04 02:30:43 +01:00
// Convert string-type reactions to unicode
2023-02-17 09:01:22 +01:00
const emoji = legacies.get(reaction) || (reaction === "♥️" ? "❤️" : null);
if (emoji) return emoji;
// Allow unicode reactions
const match = emojiRegex.exec(reaction);
if (match) {
const unicode = match[0];
return unicode;
}
2020-04-15 17:47:17 +02:00
const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
if (custom) {
const name = custom[1];
const emoji = await Emojis.findOneBy({
2023-02-17 09:01:22 +01:00
host: reacterHost || IsNull(),
name,
});
2020-05-10 10:25:16 +02: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 {
2023-01-13 05:40:33 +01:00
reaction: `:${name}@${host || "."}:`, // ローカル分は@以降を省略するのではなく.にする
name,
2021-12-09 15:58:30 +01:00
host,
};
}
return {
reaction: str,
name: undefined,
2021-12-09 15:58:30 +01:00
host: undefined,
};
}
export function convertLegacyReaction(reaction: string): string {
2023-02-17 09:01:22 +01:00
const decoded = decodeReaction(reaction).reaction;
if (legacies.has(decoded)) return legacies.get(decoded)!;
return decoded;
}