forked from element-hq/element-web
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseDownloadMedia.ts
More file actions
97 lines (80 loc) · 3.22 KB
/
Copy pathuseDownloadMedia.ts
File metadata and controls
97 lines (80 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { parseErrorResponse } from "matrix-js-sdk/src/matrix";
import { useRef, useState, useMemo, useEffect } from "react";
import { type MatrixEvent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import ErrorDialog from "../components/views/dialogs/ErrorDialog";
import { _t } from "../languageHandler";
import Modal from "../Modal";
import { FileDownloader } from "../utils/FileDownloader";
import { MediaEventHelper } from "../utils/MediaEventHelper";
import { ModuleApi } from "../modules/Api";
export interface UseDownloadMediaReturn {
download: () => Promise<void>;
loading: boolean;
canDownload: boolean;
}
export function useDownloadMedia(url: string, fileName?: string, mxEvent?: MatrixEvent): UseDownloadMediaReturn {
const downloader = useRef(new FileDownloader()).current;
const blobRef = useRef<Blob>(null);
const [loading, setLoading] = useState(false);
const [canDownload, setCanDownload] = useState<boolean>(true);
const mediaEventHelper = useMemo(() => (mxEvent ? new MediaEventHelper(mxEvent) : undefined), [mxEvent]);
useEffect(() => {
if (!mxEvent) return;
const hints = ModuleApi.instance.customComponents.getHintsForMessage(mxEvent);
if (hints?.allowDownloadingMedia) {
setCanDownload(false);
hints
.allowDownloadingMedia()
.then(setCanDownload)
.catch((err: any) => {
logger.error(`Failed to check media download permission for ${mxEvent.event.event_id}`, err);
setCanDownload(false);
});
} else {
setCanDownload(true);
}
}, [mxEvent]);
const download = async (): Promise<void> => {
if (loading) return;
try {
setLoading(true);
if (blobRef.current) {
return downloadBlob(blobRef.current);
}
// We must download via the mediaEventHelper if given as the file may need decryption.
if (mediaEventHelper) {
blobRef.current = await mediaEventHelper.sourceBlob.value;
} else {
const res = await fetch(url);
if (!res.ok) {
throw parseErrorResponse(res, await res.text());
}
blobRef.current = await res.blob();
}
await downloadBlob(blobRef.current);
} catch (e) {
showError(e);
}
};
const downloadBlob = async (blob: Blob): Promise<void> => {
await downloader.download({
blob,
name: mediaEventHelper?.fileName ?? fileName ?? _t("common|image"),
});
setLoading(false);
};
const showError = (e: unknown): void => {
Modal.createDialog(ErrorDialog, {
title: _t("timeline|download_failed"),
description: `${_t("timeline|download_failed_description")}\n\n${String(e)}`,
});
setLoading(false);
};
return { download, loading, canDownload };
}