diff --git a/client/package-lock.json b/client/package-lock.json index e161071..ed97935 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -13,7 +13,6 @@ "classnames": "^2.3.2", "copy-to-clipboard": "^3.3.3", "date-fns": "^2.29.3", - "downloadjs": "^1.4.7", "nanoid": "^3.3.4", "preact": "^10.3.2", "preact-feather": "^4.2.1", @@ -6373,11 +6372,6 @@ "node": ">=12" } }, - "node_modules/downloadjs": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", - "integrity": "sha1-9p+W+UDg0FU9rCkROYZaPNAQHjw=" - }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", diff --git a/client/package.json b/client/package.json index e7c9b84..dffc8e2 100644 --- a/client/package.json +++ b/client/package.json @@ -23,7 +23,6 @@ "classnames": "^2.3.2", "copy-to-clipboard": "^3.3.3", "date-fns": "^2.29.3", - "downloadjs": "^1.4.7", "nanoid": "^3.3.4", "preact": "^10.3.2", "preact-feather": "^4.2.1", diff --git a/client/src/routes/App/FileTransfer/FileTransfer.js b/client/src/routes/App/FileTransfer/FileTransfer.js index 727aee9..b300629 100644 --- a/client/src/routes/App/FileTransfer/FileTransfer.js +++ b/client/src/routes/App/FileTransfer/FileTransfer.js @@ -1,5 +1,4 @@ import { h, createRef } from 'preact'; -import download from 'downloadjs'; import { route } from 'preact-router'; import { PureComponent, forwardRef, memo } from 'preact/compat'; import { ArrowLeft, CheckCircle, Home, Plus, Image, Film, Box, Music, File, Zap, Share2, Send } from 'preact-feather'; @@ -17,6 +16,7 @@ import Visualizer from '../../../utils/visualizer'; import formatSize from '../../../utils/formatSize'; import pluralize from '../../../utils/pluralize'; import urls from '../../../utils/urls'; +import { multiDownload } from '../../../utils/download'; import constants from '../../../../../common/constants'; import roomsDispatch from '../../../reducers/rooms'; @@ -292,17 +292,10 @@ class FileTransfer extends PureComponent { isSelectorEnabled: false, }); }, - onDone: (file, meta) => { - if (file !== undefined) { - if (Array.isArray(file)) { - file.forEach(file => { - file.getBlob((err, blob) => download(blob, file.name)); - }); - } - else { - download(file, meta.name, meta.type); - } - } + onDone: (files) => { + if (files === undefined) return; + + multiDownload(files); this.resetState(); }, }); diff --git a/client/src/utils/download.js b/client/src/utils/download.js new file mode 100644 index 0000000..b02c365 --- /dev/null +++ b/client/src/utils/download.js @@ -0,0 +1,41 @@ +// Adapted from https://github.com/sindresorhus/multi-download/blob/v4.0.0/index.js +// to take File as input https://developer.mozilla.org/en-US/docs/Web/API/File + +/** + * Creates a promise that resolves after the specified number of milliseconds + */ +const delay = milliseconds => new Promise(resolve => { + setTimeout(resolve, milliseconds); +}); + +/** + * Downloads a single file + * @param file - An instance of the File type representing the file to download + */ +const download = async (file) => { + const a = document.createElement('a'); + const url = URL.createObjectURL(file); + a.download = file.name; + a.href = url; + a.style.display = 'none'; + document.body.append(a); + a.click(); + await delay(100); // for Chrome + a.remove(); + URL.revokeObjectURL(url); +}; + +/** + * Initiates multiple file downloads with a constant delay between each one + * @param files - An array of instances of the File type representing the files to download + */ +export const multiDownload = async (files) => { + if (!files) { + throw new Error('`files` required'); + }; + + for (const file of files) { + download(file); + await delay(1000); + } +}; diff --git a/client/src/utils/fileShare.js b/client/src/utils/fileShare.js index 056a197..acc5a90 100644 --- a/client/src/utils/fileShare.js +++ b/client/src/utils/fileShare.js @@ -50,7 +50,9 @@ class FileShare { this.socket.listen(constants.FILE_INIT, (data) => { if (data.end) { if (fileParts.length) { - onDone(new Blob(fileParts), metaData.meta[0]); + onDone([ + new File(fileParts, metaData.meta[0].name, {type: metaData.meta[0].type}) + ]); fileParts = []; size = 0; statProg = 0.25; @@ -106,8 +108,20 @@ class FileShare { torrent.on('upload', update); torrent.on('download', update); - torrent.on('done', () => { - onDone(torrent.files); + torrent.on('done', async () => { + const files = await Promise.all( + torrent.files.map( + (file) => + new Promise((resolve, reject) => { + // make regular File from webtorrent File https://github.com/webtorrent/webtorrent/blob/v1.9.7/lib/file.js#L13 + file.getBlob((err, blob) => { + if (err) reject(err); + resolve(new File([blob], file.name, { type: file.type })); + }); + }) + ) + ); + onDone(files); }); } @@ -227,4 +241,4 @@ class FileShare { } -export default FileShare; \ No newline at end of file +export default FileShare;