diff --git a/ts/components/conversation/media-gallery/propTypes/Message.tsx b/ts/components/conversation/media-gallery/propTypes/Message.tsx index b37b1cba3..326fc0e59 100644 --- a/ts/components/conversation/media-gallery/propTypes/Message.tsx +++ b/ts/components/conversation/media-gallery/propTypes/Message.tsx @@ -2,7 +2,9 @@ * @prettier */ import is from '@sindresorhus/is'; +import { partition, sortBy } from 'lodash'; +import * as MIME from '../../../../types/MIME'; import { arrayBufferToObjectURL } from '../../../../util/arrayBufferToObjectURL'; import { Attachment } from '../../../../types/Attachment'; import { MapAsync } from '../../../../types/MapAsync'; @@ -16,24 +18,55 @@ export type Message = { const DEFAULT_CONTENT_TYPE: MIMEType = 'application/octet-stream' as MIMEType; export const loadWithObjectURL = (loadMessage: MapAsync) => async ( - media: Array + messages: Array ): Promise> => { if (!is.function_(loadMessage)) { throw new TypeError("'loadMessage' must be a function"); } - if (!is.array(media)) { - throw new TypeError("'media' must be a function"); + if (!is.array(messages)) { + throw new TypeError("'messages' must be an array"); } - const mediaWithAttachmentData = await Promise.all(media.map(loadMessage)); - return mediaWithAttachmentData.map(withObjectURL); + // Messages with video are too expensive to load into memory, so we don’t: + const [messagesWithVideo, messagesWithoutVideo] = partition( + messages, + hasVideoAttachment + ); + const loadedMessagesWithoutVideo = await Promise.all( + messagesWithoutVideo.map(loadMessage) + ); + const loadedMessages = sortBy( + [...messagesWithVideo, ...loadedMessagesWithoutVideo], + message => -message.received_at + ); + + return loadedMessages.map(withObjectURL); }; +const hasVideoAttachment = (message: Message): boolean => + message.attachments.some( + attachment => + !is.undefined(attachment.contentType) && + MIME.isVideo(attachment.contentType) + ); + const withObjectURL = (message: Message): Message => { if (message.attachments.length === 0) { throw new TypeError('`message.attachments` cannot be empty'); } + const attachment = message.attachments[0]; + if (typeof attachment.contentType === 'undefined') { + throw new TypeError('`attachment.contentType` is required'); + } + + if (MIME.isVideo(attachment.contentType)) { + return { + ...message, + objectURL: 'images/video.svg', + }; + } + const objectURL = arrayBufferToObjectURL({ data: attachment.data, type: attachment.contentType || DEFAULT_CONTENT_TYPE,