diff --git a/lib/media/media-utils.js b/lib/media/media-utils.js --- a/lib/media/media-utils.js +++ b/lib/media/media-utils.js @@ -7,7 +7,11 @@ MultimediaMessageInfo, RawMultimediaMessageInfo, } from '../types/message-types.js'; -import { isBlobServiceURI } from '../utils/blob-service.js'; +import { + isBlobServiceURI, + getBlobFetchableURL, + holderFromBlobServiceURI, +} from '../utils/blob-service.js'; const maxDimensions = Object.freeze({ width: 1920, height: 1920 }); @@ -46,6 +50,15 @@ ); } +function fetchableMediaURI(uri: string): string { + if (isBlobServiceURI(uri)) { + const holder = holderFromBlobServiceURI(uri); + return getBlobFetchableURL(holder); + } + + return uri; +} + function multimediaMessagePreview( messageInfo: MultimediaMessageInfo | RawMultimediaMessageInfo, ): string { @@ -71,4 +84,5 @@ isLocalUploadID, isMediaBlobServiceHosted, getNextLocalUploadID, + fetchableMediaURI, }; diff --git a/native/media/encryption-utils.js b/native/media/encryption-utils.js --- a/native/media/encryption-utils.js +++ b/native/media/encryption-utils.js @@ -268,6 +268,9 @@ let data; try { const response = await fetch(getFetchableURI(holder)); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}: ${response.statusText}`); + } const buf = await response.arrayBuffer(); data = new Uint8Array(buf); } catch (e) { diff --git a/native/media/identifier-utils.js b/native/media/identifier-utils.js --- a/native/media/identifier-utils.js +++ b/native/media/identifier-utils.js @@ -1,5 +1,7 @@ // @flow +import { fetchableMediaURI } from 'lib/media/media-utils.js'; + function getCompatibleMediaURI(uri: string, ext: ?string): string { if (!ext) { return uri; @@ -42,11 +44,13 @@ } function getFetchableURI(inputURI: string): string { + // support for blob service URIs + let uri = fetchableMediaURI(inputURI); + // React Native always resolves Apple's assets-library:// and FBMediaKit's // ph:// scheme as an image so that the Image component can render thumbnails // of videos. In order to force fetch() to return a blob of the video, we need // to use the ph-upload:// scheme. https://git.io/Jerlh - let uri = inputURI; if (uri.startsWith('assets-library://')) { const mediaNativeID = getMediaLibraryIdentifier(uri); if (mediaNativeID) { diff --git a/web/media/encryption-utils.js b/web/media/encryption-utils.js --- a/web/media/encryption-utils.js +++ b/web/media/encryption-utils.js @@ -4,6 +4,7 @@ import { hexToUintArray, uintArrayToHexString } from 'lib/media/data-utils.js'; import { fileInfoFromData } from 'lib/media/file-utils.js'; +import { fetchableMediaURI } from 'lib/media/media-utils.js'; import type { MediaMissionFailure, MediaMissionStep, @@ -139,8 +140,12 @@ // Step 1 - Fetch the encrypted media and convert it to a Uint8Array let data; const fetchStartTime = Date.now(); + const url = fetchableMediaURI(holder); try { - const response = await fetch(holder); + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}: ${response.statusText}`); + } const buffer = await response.arrayBuffer(); data = new Uint8Array(buffer); } catch (e) { @@ -149,7 +154,7 @@ } steps.push({ step: 'fetch_buffer', - url: holder, + url, time: Date.now() - fetchStartTime, success, exceptionMessage, diff --git a/web/media/multimedia-modal.react.js b/web/media/multimedia-modal.react.js --- a/web/media/multimedia-modal.react.js +++ b/web/media/multimedia-modal.react.js @@ -5,6 +5,7 @@ import { XCircle as XCircleIcon } from 'react-feather'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { fetchableMediaURI } from 'lib/media/media-utils.js'; import type { EncryptedMediaType, MediaType } from 'lib/types/media-types.js'; import EncryptedMultimedia from './encrypted-multimedia.react.js'; @@ -42,11 +43,13 @@ let mediaModalItem; const { media } = this.props; if (media.type === 'photo') { - mediaModalItem = ; + const uri = fetchableMediaURI(media.uri); + mediaModalItem = ; } else if (media.type === 'video') { + const uri = fetchableMediaURI(media.uri); mediaModalItem = ( ); } else { diff --git a/web/media/multimedia.react.js b/web/media/multimedia.react.js --- a/web/media/multimedia.react.js +++ b/web/media/multimedia.react.js @@ -14,6 +14,7 @@ useModalContext, type PushModal, } from 'lib/components/modal-provider.react.js'; +import { fetchableMediaURI } from 'lib/media/media-utils.js'; import type { MediaType, EncryptedMediaType } from 'lib/types/media-types.js'; import EncryptedMultimedia from './encrypted-multimedia.react.js'; @@ -118,11 +119,13 @@ // Media element is the actual image or video element (or encrypted version) let mediaElement; if (mediaSource.type === 'photo') { - mediaElement = ; + const uri = fetchableMediaURI(mediaSource.uri); + mediaElement = ; } else if (mediaSource.type === 'video') { + const uri = fetchableMediaURI(mediaSource.uri); mediaElement = ( ); } else if (