416 lines
11 KiB
TypeScript
416 lines
11 KiB
TypeScript
import {
|
|
ApiAudio, ApiMediaFormat, ApiMessage, ApiMessageSearchType, ApiPhoto, ApiVideo, ApiDimensions,
|
|
} from '../../api/types';
|
|
|
|
import { IS_OPUS_SUPPORTED, IS_PROGRESSIVE_SUPPORTED, IS_SAFARI } from '../../util/environment';
|
|
import { getMessageKey, isMessageLocal, matchLinkInMessageText } from './messages';
|
|
import { getDocumentHasPreview } from '../../components/common/helpers/documentInfo';
|
|
|
|
type Target =
|
|
'micro'
|
|
| 'pictogram'
|
|
| 'inline'
|
|
| 'viewerPreview'
|
|
| 'viewerFull'
|
|
| 'download';
|
|
|
|
export function getMessageContent(message: ApiMessage) {
|
|
return message.content;
|
|
}
|
|
|
|
export function hasMessageMedia(message: ApiMessage) {
|
|
return Boolean((
|
|
getMessagePhoto(message)
|
|
|| getMessageVideo(message)
|
|
|| getMessageDocument(message)
|
|
|| getMessageSticker(message)
|
|
|| getMessageContact(message)
|
|
|| getMessagePoll(message)
|
|
|| getMessageAction(message)
|
|
|| getMessageAudio(message)
|
|
|| getMessageVoice(message)
|
|
));
|
|
}
|
|
|
|
export function getMessagePhoto(message: ApiMessage) {
|
|
return message.content.photo;
|
|
}
|
|
|
|
export function getMessageVideo(message: ApiMessage) {
|
|
return message.content.video;
|
|
}
|
|
|
|
export function getMessageRoundVideo(message: ApiMessage) {
|
|
const { video } = message.content;
|
|
|
|
return video?.isRound ? video : undefined;
|
|
}
|
|
|
|
export function getMessageAction(message: ApiMessage) {
|
|
return message.content.action;
|
|
}
|
|
|
|
export function getMessageAudio(message: ApiMessage) {
|
|
return message.content.audio;
|
|
}
|
|
|
|
export function getMessageVoice(message: ApiMessage) {
|
|
return message.content.voice;
|
|
}
|
|
|
|
export function getMessageSticker(message: ApiMessage) {
|
|
return message.content.sticker;
|
|
}
|
|
|
|
export function getMessageDocument(message: ApiMessage) {
|
|
return message.content.document;
|
|
}
|
|
|
|
export function isMessageDocumentPhoto(message: ApiMessage) {
|
|
const document = getMessageDocument(message);
|
|
return document ? document.mediaType === 'photo' : undefined;
|
|
}
|
|
|
|
export function isMessageDocumentVideo(message: ApiMessage) {
|
|
const document = getMessageDocument(message);
|
|
return document ? document.mediaType === 'video' : undefined;
|
|
}
|
|
|
|
export function getMessageContact(message: ApiMessage) {
|
|
return message.content.contact;
|
|
}
|
|
|
|
export function getMessagePoll(message: ApiMessage) {
|
|
return message.content.poll;
|
|
}
|
|
|
|
export function getMessageInvoice(message: ApiMessage) {
|
|
return message.content.invoice;
|
|
}
|
|
|
|
export function getMessageWebPage(message: ApiMessage) {
|
|
return message.content.webPage;
|
|
}
|
|
|
|
export function getMessageWebPagePhoto(message: ApiMessage) {
|
|
return getMessageWebPage(message)?.photo;
|
|
}
|
|
|
|
export function getMessageWebPageDocument(message: ApiMessage) {
|
|
return getMessageWebPage(message)?.document;
|
|
}
|
|
|
|
export function getMessageWebPageVideo(message: ApiMessage): ApiVideo | undefined {
|
|
return getMessageWebPage(message)?.video;
|
|
}
|
|
|
|
export function getMessageMediaThumbnail(message: ApiMessage) {
|
|
const media = getMessagePhoto(message)
|
|
|| getMessageVideo(message)
|
|
|| getMessageDocument(message)
|
|
|| getMessageSticker(message)
|
|
|| getMessageWebPagePhoto(message)
|
|
|| getMessageWebPageVideo(message);
|
|
|
|
if (!media) {
|
|
return undefined;
|
|
}
|
|
|
|
return media.thumbnail;
|
|
}
|
|
|
|
export function getMessageMediaThumbDataUri(message: ApiMessage) {
|
|
return getMessageMediaThumbnail(message)?.dataUri;
|
|
}
|
|
|
|
export function getMessageMediaHash(
|
|
message: ApiMessage,
|
|
target: Target,
|
|
) {
|
|
const {
|
|
photo, video, sticker, audio, voice, document,
|
|
} = message.content;
|
|
const webPagePhoto = getMessageWebPagePhoto(message);
|
|
const webPageVideo = getMessageWebPageVideo(message);
|
|
|
|
const messageVideo = video || webPageVideo;
|
|
const messagePhoto = photo || webPagePhoto;
|
|
|
|
if (!(messagePhoto || messageVideo || sticker || audio || voice || document)) {
|
|
return undefined;
|
|
}
|
|
|
|
const mediaId = (messagePhoto || messageVideo || sticker || audio || voice || document)!.id;
|
|
const base = `${getMessageKey(message)}${mediaId ? `:${mediaId}` : ''}`;
|
|
|
|
if (messageVideo) {
|
|
switch (target) {
|
|
case 'micro':
|
|
case 'pictogram':
|
|
return `${base}?size=m`;
|
|
case 'inline':
|
|
return !hasMessageLocalBlobUrl(message) ? getVideoOrAudioBaseHash(messageVideo, base) : undefined;
|
|
case 'viewerPreview':
|
|
return `${base}?size=m`;
|
|
case 'viewerFull':
|
|
return getVideoOrAudioBaseHash(messageVideo, base);
|
|
case 'download':
|
|
return `${base}?download`;
|
|
}
|
|
}
|
|
|
|
if (messagePhoto) {
|
|
switch (target) {
|
|
case 'micro':
|
|
case 'pictogram':
|
|
return `${base}?size=m`;
|
|
case 'inline':
|
|
return !hasMessageLocalBlobUrl(message) ? `${base}?size=x` : undefined;
|
|
case 'viewerPreview':
|
|
return `${base}?size=x`;
|
|
case 'viewerFull':
|
|
case 'download':
|
|
return `${base}?size=z`;
|
|
}
|
|
}
|
|
|
|
if (document) {
|
|
switch (target) {
|
|
case 'micro':
|
|
case 'pictogram':
|
|
case 'inline':
|
|
case 'viewerPreview':
|
|
if (!getDocumentHasPreview(document) || hasMessageLocalBlobUrl(message)) {
|
|
return undefined;
|
|
}
|
|
|
|
return `${base}?size=m`;
|
|
case 'viewerFull':
|
|
case 'download':
|
|
return base;
|
|
}
|
|
}
|
|
|
|
if (sticker) {
|
|
switch (target) {
|
|
case 'micro':
|
|
return undefined;
|
|
case 'pictogram':
|
|
return `${base}?size=m`;
|
|
case 'inline':
|
|
return base;
|
|
case 'download':
|
|
return `${base}?download`;
|
|
}
|
|
}
|
|
|
|
if (audio) {
|
|
switch (target) {
|
|
case 'micro':
|
|
case 'pictogram':
|
|
return getAudioHasCover(audio) ? `${base}?size=m` : undefined;
|
|
case 'inline':
|
|
return getVideoOrAudioBaseHash(audio, base);
|
|
case 'download':
|
|
return `${base}?download`;
|
|
}
|
|
}
|
|
|
|
if (voice) {
|
|
switch (target) {
|
|
case 'micro':
|
|
case 'pictogram':
|
|
return undefined;
|
|
case 'inline':
|
|
return base;
|
|
case 'download':
|
|
return `${base}?download`;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
function getVideoOrAudioBaseHash(media: ApiAudio | ApiVideo, base: string) {
|
|
if (IS_PROGRESSIVE_SUPPORTED && IS_SAFARI) {
|
|
return `${base}?fileSize=${media.size}&mimeType=${media.mimeType}`;
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
export function getAudioHasCover(media: ApiAudio) {
|
|
return media.thumbnailSizes && media.thumbnailSizes.length > 0;
|
|
}
|
|
|
|
export function getMessageMediaFormat(
|
|
message: ApiMessage, target: Target,
|
|
): Exclude<ApiMediaFormat, ApiMediaFormat.Lottie>;
|
|
export function getMessageMediaFormat(message: ApiMessage, target: Target, canBeLottie: true): ApiMediaFormat;
|
|
export function getMessageMediaFormat(
|
|
message: ApiMessage, target: Target,
|
|
): ApiMediaFormat {
|
|
const {
|
|
sticker, video, audio, voice,
|
|
} = message.content;
|
|
|
|
const fullVideo = video || getMessageWebPageVideo(message);
|
|
|
|
if (sticker && target === 'inline' && sticker.isAnimated) {
|
|
return ApiMediaFormat.Lottie;
|
|
} else if (fullVideo && IS_PROGRESSIVE_SUPPORTED && (
|
|
target === 'viewerFull' || target === 'inline'
|
|
)) {
|
|
return ApiMediaFormat.Progressive;
|
|
} else if (audio || voice) {
|
|
// Safari
|
|
if (voice && !IS_OPUS_SUPPORTED) {
|
|
return ApiMediaFormat.BlobUrl;
|
|
}
|
|
|
|
return ApiMediaFormat.Progressive;
|
|
}
|
|
|
|
return ApiMediaFormat.BlobUrl;
|
|
}
|
|
|
|
export function getMessageFileName(message: ApiMessage) {
|
|
const {
|
|
photo, video, document,
|
|
} = message.content;
|
|
const webPagePhoto = getMessageWebPagePhoto(message);
|
|
const webPageVideo = getMessageWebPageVideo(message);
|
|
|
|
if (photo || webPagePhoto) {
|
|
return `photo${message.date}.jpeg`;
|
|
}
|
|
|
|
const { fileName } = video || webPageVideo || document || {};
|
|
|
|
return fileName;
|
|
}
|
|
|
|
export function getMessageFileSize(message: ApiMessage) {
|
|
const { video, document } = message.content;
|
|
const webPageVideo = getMessageWebPageVideo(message);
|
|
const { size } = video || webPageVideo || document || {};
|
|
|
|
return size;
|
|
}
|
|
|
|
export function hasMessageLocalBlobUrl(message: ApiMessage) {
|
|
const { photo, video, document } = message.content;
|
|
|
|
return (photo?.blobUrl) || (video?.blobUrl) || (document?.previewBlobUrl);
|
|
}
|
|
|
|
export function getChatMediaMessageIds(
|
|
messages: Record<number, ApiMessage>, listedIds: number[], isFromSharedMedia = false,
|
|
) {
|
|
const ids = getMessageContentIds(messages, listedIds, isFromSharedMedia ? 'media' : 'inlineMedia');
|
|
|
|
return isFromSharedMedia ? ids.reverse() : ids;
|
|
}
|
|
|
|
export function getPhotoFullDimensions(photo: ApiPhoto): ApiDimensions | undefined {
|
|
return (
|
|
photo.sizes.find((size) => size.type === 'z')
|
|
|| photo.sizes.find((size) => size.type === 'y')
|
|
|| getPhotoInlineDimensions(photo)
|
|
);
|
|
}
|
|
|
|
export function getPhotoInlineDimensions(photo: ApiPhoto): ApiDimensions | undefined {
|
|
return (
|
|
photo.sizes.find((size) => size.type === 'x')
|
|
|| photo.sizes.find((size) => size.type === 'm')
|
|
|| photo.sizes.find((size) => size.type === 's')
|
|
|| photo.thumbnail
|
|
);
|
|
}
|
|
|
|
export function getVideoDimensions(video: ApiVideo): ApiDimensions | undefined {
|
|
if (video.width && video.height) {
|
|
return video as ApiDimensions;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export function getMediaTransferState(message: ApiMessage, progress?: number, isLoadNeeded = false) {
|
|
const isUploading = isMessageLocal(message);
|
|
const isTransferring = isUploading || isLoadNeeded;
|
|
const transferProgress = Number(progress);
|
|
|
|
return {
|
|
isUploading, isTransferring, transferProgress,
|
|
};
|
|
}
|
|
|
|
export function getMessageContentIds(
|
|
messages: Record<number, ApiMessage>, messageIds: number[], contentType: ApiMessageSearchType | 'inlineMedia',
|
|
) {
|
|
let validator: Function;
|
|
|
|
switch (contentType) {
|
|
case 'media':
|
|
validator = (message: ApiMessage) => {
|
|
const video = getMessageVideo(message);
|
|
return getMessagePhoto(message) || (video && !video.isRound && !video.isGif);
|
|
};
|
|
break;
|
|
|
|
case 'documents':
|
|
validator = getMessageDocument;
|
|
break;
|
|
|
|
case 'links':
|
|
validator = (message: ApiMessage) => getMessageWebPage(message) || matchLinkInMessageText(message);
|
|
break;
|
|
|
|
case 'audio':
|
|
validator = getMessageAudio;
|
|
break;
|
|
|
|
case 'voice':
|
|
validator = (message: ApiMessage) => {
|
|
const video = getMessageVideo(message);
|
|
return getMessageVoice(message) || (video && video.isRound);
|
|
};
|
|
break;
|
|
|
|
case 'inlineMedia':
|
|
validator = (message: ApiMessage) => {
|
|
const video = getMessageVideo(message);
|
|
return (
|
|
getMessagePhoto(message)
|
|
|| (video && !video.isRound && !video.isGif)
|
|
|| isMessageDocumentPhoto(message)
|
|
|| isMessageDocumentVideo(message)
|
|
);
|
|
};
|
|
break;
|
|
|
|
default:
|
|
return [] as Array<number>;
|
|
}
|
|
|
|
return messageIds.reduce((result, messageId) => {
|
|
if (messages[messageId] && validator(messages[messageId])) {
|
|
result.push(messageId);
|
|
}
|
|
|
|
return result;
|
|
}, [] as Array<number>);
|
|
}
|
|
|
|
export function getMediaDuration(message: ApiMessage) {
|
|
const { audio, voice, video } = getMessageContent(message);
|
|
const media = audio || voice || video || getMessageWebPageVideo(message);
|
|
if (!media) {
|
|
return undefined;
|
|
}
|
|
|
|
return media.duration;
|
|
}
|