diff --git a/config.sample.js b/config.sample.js index a46c411..593b073 100644 --- a/config.sample.js +++ b/config.sample.js @@ -121,11 +121,18 @@ module.exports = { }, /* - Allows users to download a .zip file of all files in an album. + Allows users to download a ZIP file of all files in an album. The file is generated when the user clicks the download button in the view - and is re-used if the album has not changed between download requests + and is re-used if the album has not changed between download requests. + If "maxTotalSize" is set (needs to be in MB), generating ZIP file will be disabled + if the total size of all the files in the album exceeds the set limit. + If you have CloudFlare properly caching the zipping API route, it's recommended to + set this to '512MB' as CloudFlare will not cache files bigger than that. */ - generateZips: true + generateZips: { + enabled: true, + maxTotalSize: null + } }, // Folder where to store logs diff --git a/controllers/albumsController.js b/controllers/albumsController.js index a74a323..42d535e 100644 --- a/controllers/albumsController.js +++ b/controllers/albumsController.js @@ -209,7 +209,7 @@ albumsController.generateZip = async (req, res, next) => { }) } - if (!config.uploads.generateZips) { + if (!config.uploads.generateZips || !config.uploads.generateZips.enabled) { return res.status(401).json({ success: false, description: 'Zip generation disabled.' @@ -238,7 +238,7 @@ albumsController.generateZip = async (req, res, next) => { } else { console.log(`Generating zip for album identifier: ${identifier}`) const files = await db.table('files') - .select('name') + .select('name', 'size') .where('albumid', album.id) if (files.length === 0) { return res.json({ @@ -247,6 +247,17 @@ albumsController.generateZip = async (req, res, next) => { }) } + if (config.uploads.generateZips.maxTotalSize) { + const maxTotalSizeBytes = parseInt(config.uploads.generateZips.maxTotalSize) * 1000000 + const totalSizeBytes = files.reduce((accumulator, file) => accumulator + parseInt(file.size), 0) + if (totalSizeBytes > maxTotalSizeBytes) { + return res.json({ + success: false, + description: `Total size of all the files in the album exceeds the limit set by the administrator (${config.uploads.generateZips.maxTotalSize}).` + }) + } + } + const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`) const archive = new Zip() @@ -262,7 +273,11 @@ albumsController.generateZip = async (req, res, next) => { archive .generateNodeStream({ type: 'nodebuffer', - streamFiles: true + streamFiles: true, + compression: 'DEFLATE', + compressionOptions: { + level: 1 + } }) .pipe(fs.createWriteStream(zipPath)) .on('finish', async () => { diff --git a/routes/album.js b/routes/album.js index 3197c82..76de1df 100644 --- a/routes/album.js +++ b/routes/album.js @@ -61,7 +61,7 @@ routes.get('/a/:identifier', async (req, res, next) => { thumb, files, identifier, - enableDownload: Boolean(config.uploads.generateZips), + enableDownload: Boolean(config.uploads.generateZips && config.uploads.generateZips.enabled), editedAt: album.editedAt, url: `${homeDomain}/a/${album.identifier}` })