import type { FC } from '../../lib/teact/teact'; import { memo, useCallback, useEffect } from '../../lib/teact/teact'; import { getActions, withGlobal } from '../../global'; import type { Thread } from '../../global/types'; import type { ApiMessage } from '../../api/types'; import { ApiMediaFormat } from '../../api/types'; import * as mediaLoader from '../../util/mediaLoader'; import download from '../../util/download'; import { getMessageContentFilename, getMessageMediaHash, } from '../../global/helpers'; import useRunDebounced from '../../hooks/useRunDebounced'; type StateProps = { activeDownloads: Record; messages: Record; threadsById: Record; }>; }; const GLOBAL_UPDATE_DEBOUNCE = 1000; const processedMessages = new Set(); const downloadedMessages = new Set(); const DownloadManager: FC = ({ activeDownloads, messages, }) => { const { cancelMessagesMediaDownload } = getActions(); const runDebounced = useRunDebounced(GLOBAL_UPDATE_DEBOUNCE, true); const handleMessageDownloaded = useCallback((message: ApiMessage) => { downloadedMessages.add(message); runDebounced(() => { if (downloadedMessages.size) { cancelMessagesMediaDownload({ messages: Array.from(downloadedMessages) }); downloadedMessages.clear(); } }); }, [cancelMessagesMediaDownload, runDebounced]); useEffect(() => { const activeMessages = Object.entries(activeDownloads).map(([chatId, messageIds]) => ( messageIds.map((id) => messages[chatId].byId[id]) )).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; } mediaLoader.fetch(downloadHash, ApiMediaFormat.BlobUrl, true).then((result) => { if (result) { download(result, getMessageContentFilename(message)); } handleMessageDownloaded(message); }); }); }, [messages, activeDownloads, cancelMessagesMediaDownload, handleMessageDownloaded]); return undefined; }; export default memo(withGlobal( (global): StateProps => { const activeDownloads = global.activeDownloads.byChatId; const messages = global.messages.byChatId; return { activeDownloads, messages, }; }, )(DownloadManager));