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 (