From 5684598709e46f5c13d4c3262e5199b4a7bbeb7b Mon Sep 17 00:00:00 2001 From: sifat Date: Sat, 16 Dec 2023 14:30:41 +0600 Subject: [PATCH] Add support for resumable downloads in app.js --- app.js | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/app.js b/app.js index e6910db..9b22036 100644 --- a/app.js +++ b/app.js @@ -122,14 +122,52 @@ module.exports = ({ sharedPath: sharedPathIn, port, maxUploadSize, zipCompressio if (isDir) { await serveDirZip(filePath, res); } else { - if (forceDownload) { - // NOTE: Must support non latin characters + try { + const stat = await fs.stat(filePath); + const fileSize = stat.size; + + // if (forceDownload) { + // // Set the filename in the Content-disposition header + // res.set('Content-disposition', contentDisposition(basename(filePath))); + // } + res.set('Content-disposition', contentDisposition(basename(filePath))); - } - await pipeline(fs.createReadStream(filePath), res); + // Check if the client supports resumable downloads + const range = req.headers.range; + if (range) { + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1; + const chunkSize = (end - start) + 1; + + // Set headers for resumable download + res.status(206).set({ + 'Content-Range': `bytes ${start}-${end}/${fileSize}`, + 'Accept-Ranges': 'bytes', + 'Content-Length': chunkSize, + 'Content-Type': 'application/octet-stream', // Adjust the content type as needed + }); + + // Create a readable stream to send the requested chunk + const fileStream = fs.createReadStream(filePath, { start, end }); + fileStream.pipe(res); + } else { + // Standard download without resuming + res.writeHead(200, { + 'Content-Type': 'application/octet-stream', // Adjust the content type as needed + 'Content-Length': fileSize, + }); + + await pipeline(fs.createReadStream(filePath), res); + } + } catch (err) { + console.error('Error while processing download request:', err); + res.status(500).send({ error: { message: 'Internal Server Error' } }); + } } })); + app.get('/api/browse', asyncHandler(async (req, res) => { const curRelPath = req.query.p || '/';