216 lines
4.7 KiB
TypeScript
216 lines
4.7 KiB
TypeScript
import type { TeactNode } from '../../lib/teact/teact';
|
|
import type { ApiMessage } from '../../api/types';
|
|
import { ApiMessageEntityTypes } from '../../api/types';
|
|
import { CONTENT_NOT_SUPPORTED } from '../../config';
|
|
|
|
import type { LangFn } from '../../hooks/useLang';
|
|
|
|
import trimText from '../../util/trimText';
|
|
import { getMessageText, getMessageTranscription } from './messages';
|
|
import { getMessageRecentReaction } from './reactions';
|
|
|
|
const SPOILER_CHARS = ['⠺', '⠵', '⠞', '⠟'];
|
|
export const TRUNCATED_SUMMARY_LENGTH = 80;
|
|
|
|
export function getMessageSummaryText(
|
|
lang: LangFn,
|
|
message: ApiMessage,
|
|
noEmoji = false,
|
|
truncateLength = TRUNCATED_SUMMARY_LENGTH,
|
|
noReactions = true,
|
|
isExtended = false,
|
|
) {
|
|
const emoji = !noEmoji && getMessageSummaryEmoji(message, noReactions);
|
|
const emojiWithSpace = emoji ? `${emoji} ` : '';
|
|
const text = trimText(getMessageTextWithSpoilers(message), truncateLength);
|
|
const description = getMessageSummaryDescription(lang, message, text, noReactions, isExtended);
|
|
|
|
return `${emojiWithSpace}${description}`;
|
|
}
|
|
|
|
export function getMessageTextWithSpoilers(message: ApiMessage) {
|
|
const transcription = getMessageTranscription(message);
|
|
|
|
const textWithoutTranscription = getMessageText(message);
|
|
if (!textWithoutTranscription) {
|
|
return transcription;
|
|
}
|
|
|
|
const { entities } = message.content.text || {};
|
|
if (!entities?.length) {
|
|
return transcription ? `${transcription}\n${textWithoutTranscription}` : textWithoutTranscription;
|
|
}
|
|
|
|
const text = entities.reduce((accText, {
|
|
type,
|
|
offset,
|
|
length,
|
|
}) => {
|
|
if (type !== ApiMessageEntityTypes.Spoiler) {
|
|
return accText;
|
|
}
|
|
|
|
const spoiler = generateBrailleSpoiler(length);
|
|
|
|
return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`;
|
|
}, textWithoutTranscription);
|
|
|
|
return transcription ? `${transcription}\n${text}` : text;
|
|
}
|
|
|
|
export function getMessageSummaryEmoji(message: ApiMessage, noReactions = true) {
|
|
const {
|
|
photo,
|
|
video,
|
|
audio,
|
|
voice,
|
|
document,
|
|
sticker,
|
|
poll,
|
|
} = message.content;
|
|
|
|
if (message.groupedId || photo) {
|
|
return '🖼';
|
|
}
|
|
|
|
if (video) {
|
|
return '📹';
|
|
}
|
|
|
|
if (sticker) {
|
|
return sticker.emoji;
|
|
}
|
|
|
|
if (audio) {
|
|
return '🎧';
|
|
}
|
|
|
|
if (voice) {
|
|
return '🎤';
|
|
}
|
|
|
|
if (document) {
|
|
return '📎';
|
|
}
|
|
|
|
if (poll) {
|
|
return '📊';
|
|
}
|
|
|
|
const reaction = !noReactions && getMessageRecentReaction(message);
|
|
if (reaction) {
|
|
return reaction.reaction;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export function getMessageSummaryDescription(
|
|
lang: LangFn,
|
|
message: ApiMessage,
|
|
truncatedText?: string | TeactNode,
|
|
noReactions = true,
|
|
isExtended = false,
|
|
) {
|
|
const {
|
|
text,
|
|
photo,
|
|
video,
|
|
audio,
|
|
voice,
|
|
document,
|
|
sticker,
|
|
contact,
|
|
poll,
|
|
invoice,
|
|
location,
|
|
game,
|
|
} = message.content;
|
|
|
|
let summary: string | TeactNode | undefined;
|
|
|
|
if (message.groupedId) {
|
|
summary = truncatedText || lang('lng_in_dlg_album');
|
|
}
|
|
|
|
if (photo) {
|
|
summary = truncatedText || lang('AttachPhoto');
|
|
}
|
|
|
|
if (video) {
|
|
summary = truncatedText || lang(video.isGif ? 'AttachGif' : 'AttachVideo');
|
|
}
|
|
|
|
if (sticker) {
|
|
summary = lang('AttachSticker').trim();
|
|
}
|
|
|
|
if (audio) {
|
|
summary = getMessageAudioCaption(message) || lang('AttachMusic');
|
|
}
|
|
|
|
if (voice) {
|
|
summary = truncatedText || lang('AttachAudio');
|
|
}
|
|
|
|
if (document) {
|
|
summary = isExtended ? document.fileName : (truncatedText || document.fileName);
|
|
}
|
|
|
|
if (contact) {
|
|
summary = lang('AttachContact');
|
|
}
|
|
|
|
if (poll) {
|
|
summary = poll.summary.question;
|
|
}
|
|
|
|
if (invoice) {
|
|
summary = invoice.extendedMedia ? invoice.title : `${lang('PaymentInvoice')}: ${invoice.text}`;
|
|
}
|
|
|
|
if (text) {
|
|
if (isExtended && summary) {
|
|
summary += `\n${truncatedText}`;
|
|
} else {
|
|
summary = truncatedText;
|
|
}
|
|
}
|
|
|
|
if (location?.type === 'geo' || location?.type === 'venue') {
|
|
summary = lang('Message.Location');
|
|
}
|
|
|
|
if (location?.type === 'geoLive') {
|
|
summary = lang('Message.LiveLocation');
|
|
}
|
|
|
|
if (game) {
|
|
summary = `🎮 ${game.title}`;
|
|
}
|
|
|
|
const reaction = !noReactions && getMessageRecentReaction(message);
|
|
if (summary && reaction) {
|
|
summary = `to your "${summary}"`;
|
|
}
|
|
|
|
return summary || CONTENT_NOT_SUPPORTED;
|
|
}
|
|
|
|
export function generateBrailleSpoiler(length: number) {
|
|
return new Array(length)
|
|
.fill(undefined)
|
|
.map(() => SPOILER_CHARS[Math.floor(Math.random() * SPOILER_CHARS.length)])
|
|
.join('');
|
|
}
|
|
|
|
function getMessageAudioCaption(message: ApiMessage) {
|
|
const {
|
|
audio,
|
|
text,
|
|
} = message.content;
|
|
|
|
return (audio && [audio.title, audio.performer].filter(Boolean)
|
|
.join(' — ')) || (text?.text);
|
|
}
|