129 lines
4.4 KiB
TypeScript
129 lines
4.4 KiB
TypeScript
import type { FC } from '../../lib/teact/teact';
|
|
import { memo, useEffect } from '../../lib/teact/teact';
|
|
import { getActions, getGlobal, withGlobal } from '../../global';
|
|
|
|
import type { GlobalState, TabState } from '../../global/types';
|
|
import type { ApiMessage } from '../../api/types';
|
|
import { ApiMediaFormat } from '../../api/types';
|
|
|
|
import { selectTabState } from '../../global/selectors';
|
|
import { IS_OPFS_SUPPORTED, IS_SERVICE_WORKER_SUPPORTED, MAX_BUFFER_SIZE } from '../../util/windowEnvironment';
|
|
import * as mediaLoader from '../../util/mediaLoader';
|
|
import download from '../../util/download';
|
|
import {
|
|
getMessageContentFilename, getMessageMediaFormat, getMessageMediaHash,
|
|
} from '../../global/helpers';
|
|
import { compact } from '../../util/iteratees';
|
|
|
|
import useLastCallback from '../../hooks/useLastCallback';
|
|
import useRunDebounced from '../../hooks/useRunDebounced';
|
|
|
|
type StateProps = {
|
|
activeDownloads: TabState['activeDownloads']['byChatId'];
|
|
messages?: GlobalState['messages']['byChatId'];
|
|
};
|
|
|
|
const GLOBAL_UPDATE_DEBOUNCE = 1000;
|
|
|
|
const processedMessages = new Set<ApiMessage>();
|
|
const downloadedMessages = new Set<ApiMessage>();
|
|
|
|
const DownloadManager: FC<StateProps> = ({
|
|
activeDownloads,
|
|
}) => {
|
|
const { cancelMessagesMediaDownload, showNotification } = getActions();
|
|
|
|
const runDebounced = useRunDebounced(GLOBAL_UPDATE_DEBOUNCE, true);
|
|
|
|
const handleMessageDownloaded = useLastCallback((message: ApiMessage) => {
|
|
downloadedMessages.add(message);
|
|
runDebounced(() => {
|
|
if (downloadedMessages.size) {
|
|
cancelMessagesMediaDownload({ messages: Array.from(downloadedMessages) });
|
|
downloadedMessages.clear();
|
|
}
|
|
});
|
|
});
|
|
|
|
useEffect(() => {
|
|
// No need for expensive global updates on messages, so we avoid them
|
|
const messages = getGlobal().messages.byChatId;
|
|
const scheduledMessages = getGlobal().scheduledMessages.byChatId;
|
|
|
|
const activeMessages = Object.entries(activeDownloads).map(([chatId, chatActiveDownloads]) => {
|
|
const chatMessages = chatActiveDownloads.ids?.map((id) => messages[chatId]?.byId[id]);
|
|
const chatScheduledMessages = chatActiveDownloads.scheduledIds?.map((id) => scheduledMessages[chatId]?.byId[id]);
|
|
|
|
return compact([...chatMessages || [], ...chatScheduledMessages || []]);
|
|
}).flat();
|
|
|
|
if (!activeMessages.length) {
|
|
processedMessages.clear();
|
|
return;
|
|
}
|
|
|
|
activeMessages.forEach((message) => {
|
|
if (processedMessages.has(message)) {
|
|
return;
|
|
}
|
|
processedMessages.add(message);
|
|
const downloadHash = getMessageMediaHash(message, 'download');
|
|
if (!downloadHash) {
|
|
handleMessageDownloaded(message);
|
|
return;
|
|
}
|
|
|
|
const mediaData = mediaLoader.getFromMemory(downloadHash);
|
|
|
|
if (mediaData) {
|
|
download(mediaData, getMessageContentFilename(message));
|
|
handleMessageDownloaded(message);
|
|
return;
|
|
}
|
|
|
|
const {
|
|
document, video, audio,
|
|
} = message.content;
|
|
const mediaSize = (document || video || audio)?.size || 0;
|
|
if (mediaSize > MAX_BUFFER_SIZE && !IS_OPFS_SUPPORTED && !IS_SERVICE_WORKER_SUPPORTED) {
|
|
showNotification({
|
|
message: 'Downloading files bigger than 2GB is not supported in your browser.',
|
|
});
|
|
handleMessageDownloaded(message);
|
|
return;
|
|
}
|
|
|
|
const mediaFormat = getMessageMediaFormat(message, 'download');
|
|
mediaLoader.fetch(downloadHash, mediaFormat, true).then((result) => {
|
|
if (mediaFormat === ApiMediaFormat.DownloadUrl) {
|
|
const url = new URL(result, window.document.baseURI);
|
|
const filename = getMessageContentFilename(message);
|
|
url.searchParams.set('filename', encodeURIComponent(filename));
|
|
const downloadWindow = window.open(url.toString());
|
|
downloadWindow?.addEventListener('beforeunload', () => {
|
|
showNotification({
|
|
message: 'Download started. Please, do not close the app before it is finished.',
|
|
});
|
|
});
|
|
} else if (result) {
|
|
download(result, getMessageContentFilename(message));
|
|
}
|
|
|
|
handleMessageDownloaded(message);
|
|
});
|
|
});
|
|
}, [activeDownloads, cancelMessagesMediaDownload, handleMessageDownloaded, showNotification]);
|
|
|
|
return undefined;
|
|
};
|
|
|
|
export default memo(withGlobal(
|
|
(global): StateProps => {
|
|
const activeDownloads = selectTabState(global).activeDownloads.byChatId;
|
|
|
|
return {
|
|
activeDownloads,
|
|
};
|
|
},
|
|
)(DownloadManager));
|