2022-11-13 17:05:58 +04:00

255 lines
7.1 KiB
TypeScript

import type {
ApiChat, ApiMessage, ApiMessageEntityTextUrl, ApiReactions, ApiUser,
} from '../../api/types';
import { ApiMessageEntityTypes } from '../../api/types';
import type { LangFn } from '../../hooks/useLang';
import {
CONTENT_NOT_SUPPORTED,
LOCAL_MESSAGE_MIN_ID,
RE_LINK_TEMPLATE,
SERVICE_NOTIFICATIONS_USER_ID,
} from '../../config';
import { getUserFullName } from './users';
import { IS_OPUS_SUPPORTED, isWebpSupported } from '../../util/environment';
import { getChatTitle, isUserId } from './chats';
import { getGlobal } from '../index';
const RE_LINK = new RegExp(RE_LINK_TEMPLATE, 'i');
export type MessageKey = `msg${string}-${number}`;
export function getMessageHtmlId(messageId: number) {
return `message${messageId.toString().replace('.', '-')}`;
}
export function getMessageKey(message: ApiMessage): MessageKey {
const { chatId, id, previousLocalId } = message;
return buildMessageKey(chatId, isServiceNotificationMessage(message) ? previousLocalId || id : id);
}
export function buildMessageKey(chatId: string, msgId: number): MessageKey {
return `msg${chatId}-${msgId}`;
}
export function parseMessageKey(key: MessageKey) {
const match = key.match(/^msg(-?\d+)-(\d+)/)!;
return { chatId: match[1], messageId: Number(match[2]) };
}
export function getMessageOriginalId(message: ApiMessage) {
return message.previousLocalId || message.id;
}
export function getMessageTranscription(message: ApiMessage) {
const { transcriptionId } = message;
const global = getGlobal();
return transcriptionId && global.transcriptions[transcriptionId]?.text;
}
export function hasMessageText(message: ApiMessage) {
const {
text, sticker, photo, video, audio, voice, document, poll, webPage, contact, invoice, location,
game, action,
} = message.content;
return Boolean(text) || !(
sticker || photo || video || audio || voice || document || contact || poll || webPage || invoice || location
|| game || action?.phoneCall
);
}
export function getMessageText(message: ApiMessage) {
return hasMessageText(message) ? message.content.text?.text || CONTENT_NOT_SUPPORTED : undefined;
}
export function getMessageCustomShape(message: ApiMessage): boolean {
const {
text, sticker, photo, video, audio, voice, document, poll, webPage, contact, action, game, invoice, location,
} = message.content;
if (sticker || (video?.isRound)) {
return true;
}
if (!text || photo || video || audio || voice || document || poll || webPage || contact || action || game || invoice
|| location) {
return false;
}
const hasOtherFormatting = text?.entities?.some((entity) => entity.type !== ApiMessageEntityTypes.CustomEmoji);
return Boolean(message.emojiOnlyCount && !hasOtherFormatting);
}
export function getMessageSingleRegularEmoji(message: ApiMessage) {
const { text } = message.content;
if (text?.entities?.length || message.emojiOnlyCount !== 1) {
return undefined;
}
return text!.text;
}
export function getMessageSingleCustomEmoji(message: ApiMessage): string | undefined {
const { text } = message.content;
if (text?.entities?.length !== 1
|| text.entities[0].type !== ApiMessageEntityTypes.CustomEmoji
|| message.emojiOnlyCount !== 1) {
return undefined;
}
return text.entities[0].documentId;
}
export function getFirstLinkInMessage(message: ApiMessage) {
const { text } = message.content;
let match: RegExpMatchArray | null | undefined;
if (text?.entities) {
const firstTextUrl = text.entities.find((entity): entity is ApiMessageEntityTextUrl => (
entity.type === ApiMessageEntityTypes.TextUrl
));
if (firstTextUrl) {
match = firstTextUrl.url.match(RE_LINK);
}
if (!match) {
const firstUrl = text.entities.find((entity) => entity.type === ApiMessageEntityTypes.Url);
if (firstUrl) {
const { offset, length } = firstUrl;
match = text.text.substring(offset, offset + length).match(RE_LINK);
}
}
}
if (!match && text) {
match = text.text.match(RE_LINK);
}
if (!match) {
return undefined;
}
return {
url: match[0],
domain: match[3],
};
}
export function matchLinkInMessageText(message: ApiMessage) {
const { text } = message.content;
const match = text && text.text.match(RE_LINK);
if (!match) {
return undefined;
}
return {
url: match[0],
domain: match[3],
};
}
export function isOwnMessage(message: ApiMessage) {
return message.isOutgoing;
}
export function isReplyMessage(message: ApiMessage) {
return Boolean(message.replyToMessageId);
}
export function isForwardedMessage(message: ApiMessage) {
return Boolean(message.forwardInfo);
}
export function isActionMessage(message: ApiMessage) {
return Boolean(message.content.action);
}
export function isServiceNotificationMessage(message: ApiMessage) {
return message.chatId === SERVICE_NOTIFICATIONS_USER_ID && Math.round(message.id) !== message.id;
}
export function isAnonymousOwnMessage(message: ApiMessage) {
return Boolean(message.senderId) && !isUserId(message.senderId!) && isOwnMessage(message);
}
export function getSenderTitle(lang: LangFn, sender: ApiUser | ApiChat) {
return isUserId(sender.id) ? getUserFullName(sender as ApiUser) : getChatTitle(lang, sender as ApiChat);
}
export function getSendingState(message: ApiMessage) {
if (!message.sendingState) {
return 'succeeded';
}
return message.sendingState === 'messageSendingStateFailed' ? 'failed' : 'pending';
}
export function isMessageLocal(message: ApiMessage) {
return message.id > LOCAL_MESSAGE_MIN_ID;
}
export function isHistoryClearMessage(message: ApiMessage) {
return message.content.action && message.content.action.type === 'historyClear';
}
export function getMessageContentFilename(message: ApiMessage) {
const { content } = message;
const video = content.webPage ? content.webPage.video : content.video;
const photo = content.webPage ? content.webPage.photo : content.photo;
const document = content.webPage ? content.webPage.document : content.document;
if (document) {
return document.fileName;
}
if (video) {
return video.fileName;
}
if (content.sticker) {
const extension = content.sticker.isLottie ? 'tgs' : content.sticker.isVideo
? 'webm' : isWebpSupported() ? 'webp' : 'png';
return `${content.sticker.id}.${extension}`;
}
if (content.audio) {
return content.audio.fileName;
}
const baseFilename = getMessageKey(message);
if (photo) {
return `${baseFilename}.jpg`;
}
if (content.voice) {
return IS_OPUS_SUPPORTED ? `${baseFilename}.ogg` : `${baseFilename}.wav`;
}
return baseFilename;
}
export function areReactionsEmpty(reactions: ApiReactions) {
return !reactions.results.some((l) => l.count > 0);
}
export function isGeoLiveExpired(message: ApiMessage, timestamp = Date.now() / 1000) {
const { location } = message.content;
if (location?.type !== 'geoLive') return false;
return (timestamp - (message.date || 0) >= location.period);
}
export function getMessageSingleInlineButton(message: ApiMessage) {
return message.inlineButtons?.length === 1
&& message.inlineButtons[0].length === 1
&& message.inlineButtons[0][0];
}