From cabb360a2e7164c5e6e79022d58e096c52084fbe Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Wed, 20 Oct 2021 21:08:41 +0300 Subject: [PATCH] proper scheduled file deletion --- package-lock.json | 11 +++++ package.json | 1 + src/index.js | 121 ++++++++++++++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 808caea..391a09c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "dotenv": "^10.0.0", "express": "^4.17.1", "express-ws": "^5.0.2", + "timeago.js": "^4.0.2", "ws": "^8.2.3" }, "optionalDependencies": { @@ -1261,6 +1262,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/timeago.js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz", + "integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==" + }, "node_modules/toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -2342,6 +2348,11 @@ } } }, + "timeago.js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz", + "integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==" + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", diff --git a/package.json b/package.json index a9fe9e9..a07a9c3 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dotenv": "^10.0.0", "express": "^4.17.1", "express-ws": "^5.0.2", + "timeago.js": "^4.0.2", "ws": "^8.2.3" }, "optionalDependencies": { diff --git a/src/index.js b/src/index.js index 5a7451a..e5fc66f 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,14 @@ const deezer = require('deezer-js'); const deemix = require('deemix'); const path = require('path'); const { inspect, promisify } = require('util'); -const ws = require('ws'); const fs = require('fs'); const { exec } = require('child_process'); +const timeago = require('timeago.js'); const port = process.env.PORT || 4500; +// const deleteTimer = 1000 * 60 * 60; // 1 hour +const deleteTimer = 1000 * 60 * 25; // 25 minutes +// const deleteTimer = 16000; require('dotenv').config(); @@ -21,6 +24,66 @@ deemixSettings.downloadLocation = path.join(process.cwd(), 'data/'); deemixSettings.maxBitrate = String(deezer.TrackFormats.FLAC); deemixSettings.overwriteFile = deemix.settings.OverwriteOption.OVERWRITE; +const toDeleteLocation = './data/toDelete.json'; + +if (!fs.existsSync(toDeleteLocation)) fs.writeFileSync(toDeleteLocation, '[]', {encoding: 'utf8'}); +let toDelete = JSON.parse(fs.readFileSync(toDeleteLocation, {encoding: 'utf8'})); + +function updateQueueFile() { + fs.writeFileSync(toDeleteLocation, JSON.stringify(toDelete), {encoding: 'utf8'}); +} + +function queueDeletion(file) { + console.log(`queued deletion of ${file} ${timeago.format(Date.now() + deleteTimer)}`); + + toDelete.push({ + date: Date.now() + deleteTimer, + file + }); + setTimeout(() => { + toDelete = toDelete.filter(c => c.file !== file); + updateQueueFile(); + console.log(`deleting queued file ${file}`); + try { + fs.unlinkSync(file); + } catch(err) { + console.log(`failed to delete ${file}! is the file already gone?`); + } + }, deleteTimer); + updateQueueFile(); +} + +console.log(`loaded ${toDelete.length} items in deletion queue`); +let updateQueue = false; +for (let del of toDelete) { + if (Date.now() - del.date >= 0) { + console.log(`deleting ${del.file} - was meant to be deleted ${timeago.format(del.date)}`); + updateQueue = true; + try { + fs.unlinkSync(del.file); + } catch(err) { + console.log(`failed to delete ${del.file}! is the file already gone?`); + } + delete del; + } else { + console.log(`queueing deletion of ${del.file} ${timeago.format(del.date)}`); + setTimeout(() => { + toDelete = toDelete.filter(c => c.file !== del.file); + updateQueueFile(); + try { + fs.unlinkSync(del.file); + } catch(err) { + console.log(`failed to delete ${del.file}! is the file already gone?`); + } + }, del.date - Date.now()); + } +}; + +if (updateQueue) { + updateQueueFile(); + console.log('updated deletion queue json'); +} + app.use(express.static('public')); app.use('/data', express.static('data', {extensions: ['flac', 'mp3']})); app.get('/api/search', async (req, res) => { @@ -45,18 +108,6 @@ app.get('/api/search', async (req, res) => { res.send(format); }); -/* -app.get('/api/album', async (req, res) => { - if (!req.query.id) return res.sendStatus(400); - let dlObj = await deemix.generateDownloadObject(deezerInstance, 'https://www.deezer.com/album/' + req.query.id, deezer.TrackFormats.FLAC); - deemixDownloader = new deemix.downloader.Downloader(deezerInstance, dlObj, deemixSettings, listener); - - console.log(await deemixDownloader.start()); - - res.send('a'); -}); -*/ - app.get('/api/album', async (req, res) => { if (!req.query.id) return req.sendStatus(400); let album; @@ -91,14 +142,7 @@ app.ws('/api/album', async (ws, req) => { if (data.downloaded) { // ws.send(JSON.stringify({key: 'download', data: data.downloadPath.replace(process.cwd(), '')})); trackpaths.push(data.downloadPath); - console.log('downloaded ' + data.downloadPath + ', deleting in 1hr'); - setTimeout(() => { - try { - fs.unlinkSync(data.downloadPath); - } catch(err) { - console.log('tried to delete ' + data.downloadPath + ', but failed? its likely already gone'); - } - }, 1000 * 60 * 60 /* 1 hour */); + queueDeletion(data.downloadPath); } if (data.state !== 'tagging' && data.state !== 'getAlbumArt' && data.state !== 'getTags') ws.send(JSON.stringify({key, data})); @@ -121,25 +165,22 @@ app.ws('/api/album', async (ws, req) => { await deemixDownloader.start(); - await ws.send(JSON.stringify({key: 'zipping'})); + if (trackpaths.length > 1) { + await ws.send(JSON.stringify({key: 'zipping'})); - const folderName = trackpaths[0].split('/').slice(-2)[0]; - try { - await promisify(exec)(`zip -0rD "data/${folderName}.zip" "data/${folderName}"`); - } catch(err) { - return ws.close(1011, 'Zipping album failed'); - } - - await ws.send(JSON.stringify({key: 'download', data: `data/${folderName}.zip`})); - - console.log('zipped up data/' + folderName + '.zip, deleting in 1hr'); - setTimeout(() => { + const folderName = trackpaths[0].split('/').slice(-2)[0]; try { - fs.unlinkSync('./data/' + folderName + '.zip'); + await promisify(exec)(`zip -0rD "data/${folderName}.zip" "data/${folderName}"`); } catch(err) { - console.log('tried to delete ' + folderName + '.zip, but failed? its likely already gone'); + return ws.close(1011, 'Zipping album failed'); } - }, 1000 * 60 * 60 /* 1 hour */); + + await ws.send(JSON.stringify({key: 'download', data: `data/${folderName}.zip`})); + + queueDeletion('./data/' + folderName + '.zip'); + } else { + await ws.send(JSON.stringify({key: 'download', data: trackpaths[0].replace(process.cwd(), '')})); + } ws.close(1000); }); @@ -151,13 +192,7 @@ app.ws('/api/track', async (ws, req) => { send(key, data) { if (data.downloaded) { ws.send(JSON.stringify({key: 'download', data: data.downloadPath.replace(process.cwd(), '')})); - setTimeout(() => { - try { - fs.unlinkSync(data.downloadPath); - } catch(err) { - console.log('tried to delete ' + data.downloadPath + ', but failed? its likely already gone'); - } - }, 1000 * 60 * 60 /* 1 hour */); + queueDeletion(data.downloadPath); } if (data.state !== 'tagging' && data.state !== 'getAlbumArt' && data.state !== 'getTags') ws.send(JSON.stringify({key, data}));