From e790c9fadfaae7c5044ec43424ff43d642b26ba6 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 26 Apr 2020 18:33:23 -0400 Subject: [PATCH] File descriptors are now stored in the config_api until they find a better home File deletion now works in multi-user mode. Sharing and subscriptions are the last holdouts for porting over to multi-user-mode Fixed bug with archive mode that defaulted to storing the ID in the video archive all the time (rather than audio if it's an mp3) --- backend/app.js | 57 ++++++++++++++++----------- backend/authentication/auth.js | 72 ++++++++++++++++++++++++++++++++++ backend/config.js | 3 +- 3 files changed, 109 insertions(+), 23 deletions(-) diff --git a/backend/app.js b/backend/app.js index 392cfa0..60ff1a7 100644 --- a/backend/app.js +++ b/backend/app.js @@ -149,7 +149,6 @@ if (writeConfigMode) { } var downloads = {}; -var descriptors = {}; app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); @@ -882,10 +881,10 @@ async function deleteAudioFile(name, blacklistMode = false) { let audioFileExists = fs.existsSync(audioFilePath); - if (descriptors[name]) { + if (config_api.descriptors[name]) { try { - for (let i = 0; i < descriptors[name].length; i++) { - descriptors[name][i].destroy(); + for (let i = 0; i < config_api.descriptors[name].length; i++) { + config_api.descriptors[name][i].destroy(); } } catch(e) { @@ -940,10 +939,10 @@ async function deleteVideoFile(name, customPath = null, blacklistMode = false) { jsonExists = fs.existsSync(jsonPath); videoFileExists = fs.existsSync(videoFilePath); - if (descriptors[name]) { + if (config_api.descriptors[name]) { try { - for (let i = 0; i < descriptors[name].length; i++) { - descriptors[name][i].destroy(); + for (let i = 0; i < config_api.descriptors[name].length; i++) { + config_api.descriptors[name][i].destroy(); } } catch(e) { @@ -1352,7 +1351,7 @@ async function downloadFileByURL_normal(url, type, options, sessionID = null) { if (options.merged_string) { let current_merged_archive = fs.readFileSync(fileFolderPath + 'merged.txt', 'utf8'); let diff = current_merged_archive.replace(options.merged_string, ''); - const archive_path = path.join(archivePath, 'archive_video.txt'); + const archive_path = req.isAuthenticated() ? path.join(fileFolderPath, 'archives', `archive_${type}.txt`) : path.join(archivePath, `archive_${type}.txt`); fs.appendFileSync(archive_path, diff); } @@ -1440,13 +1439,13 @@ async function generateArgs(url, type, options) { let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); if (useYoutubeDLArchive) { - const archive_path = path.join(archivePath, `archive_${type}.txt`); + const archive_path = options.user ? path.join(fileFolderPath, 'archives', `archive_${type}.txt`) : path.join(archivePath, `archive_${type}.txt`); // create archive file if it doesn't exist if (!fs.existsSync(archive_path)) { fs.closeSync(fs.openSync(archive_path, 'w')); } - let blacklist_path = path.join(archivePath, `blacklist_${type}.txt`); + let blacklist_path = options.user ? path.join(fileFolderPath, 'archives', `blacklist_${type}.txt`) : path.join(archivePath, `blacklist_${type}.txt`); // create blacklist file if it doesn't exist if (!fs.existsSync(blacklist_path)) { fs.closeSync(fs.openSync(blacklist_path, 'w')); @@ -2244,12 +2243,19 @@ app.post('/api/deletePlaylist', optionalJwt, async (req, res) => { }); // deletes mp3 file -app.post('/api/deleteMp3', async (req, res) => { +app.post('/api/deleteMp3', optionalJwt, async (req, res) => { // var name = req.body.name; var uid = req.body.uid; + var blacklistMode = req.body.blacklistMode; + + if (req.isAuthenticated()) { + let success = auth_api.deleteUserFile(req.user.uid, uid, 'audio', blacklistMode); + res.send(success); + return; + } + var audio_obj = db.get('files.audio').find({uid: uid}).value(); var name = audio_obj.id; - var blacklistMode = req.body.blacklistMode; var fullpath = audioFolderPath + name + ".mp3"; var wasDeleted = false; if (fs.existsSync(fullpath)) @@ -2270,11 +2276,18 @@ app.post('/api/deleteMp3', async (req, res) => { }); // deletes mp4 file -app.post('/api/deleteMp4', async (req, res) => { +app.post('/api/deleteMp4', optionalJwt, async (req, res) => { var uid = req.body.uid; + var blacklistMode = req.body.blacklistMode; + + if (req.isAuthenticated()) { + let success = auth_api.deleteUserFile(req.user.uid, uid, 'video', blacklistMode); + res.send(success); + return; + } + var video_obj = db.get('files.video').find({uid: uid}).value(); var name = video_obj.id; - var blacklistMode = req.body.blacklistMode; var fullpath = videoFolderPath + name + ".mp4"; var wasDeleted = false; if (fs.existsSync(fullpath)) @@ -2472,11 +2485,11 @@ app.get('/api/video/:id', optionalJwt, function(req , res){ : fileSize-1 const chunksize = (end-start)+1 const file = fs.createReadStream(file_path, {start, end}) - if (descriptors[id]) descriptors[id].push(file); - else descriptors[id] = [file]; + if (config_api.descriptors[id]) config_api.descriptors[id].push(file); + else config_api.descriptors[id] = [file]; file.on('close', function() { - let index = descriptors[id].indexOf(file); - descriptors[id].splice(index, 1); + let index = config_api.descriptors[id].indexOf(file); + config_api.descriptors[id].splice(index, 1); logger.debug('Successfully closed stream and removed file reference.'); }); head = { @@ -2517,11 +2530,11 @@ app.get('/api/audio/:id', optionalJwt, function(req , res){ : fileSize-1 const chunksize = (end-start)+1 const file = fs.createReadStream(file_path, {start, end}); - if (descriptors[id]) descriptors[id].push(file); - else descriptors[id] = [file]; + if (config_api.descriptors[id]) config_api.descriptors[id].push(file); + else config_api.descriptors[id] = [file]; file.on('close', function() { - let index = descriptors[id].indexOf(file); - descriptors[id].splice(index, 1); + let index = config_api.descriptors[id].indexOf(file); + config_api.descriptors[id].splice(index, 1); logger.debug('Successfully closed stream and removed file reference.'); }); head = { diff --git a/backend/authentication/auth.js b/backend/authentication/auth.js index 2dc0fc6..2a9eceb 100644 --- a/backend/authentication/auth.js +++ b/backend/authentication/auth.js @@ -2,6 +2,10 @@ const low = require('lowdb') const FileSync = require('lowdb/adapters/FileSync'); const adapter = new FileSync('./appdata/users.json'); const db = low(adapter); +const path = require('path'); +const config_api = require('../config'); +var subscriptions_api = require('../subscriptions') +const fs = require('fs-extra'); db.defaults( { users: [] @@ -294,6 +298,74 @@ exports.registerUserFile = function(user_uid, file_object, type) { .write(); } +exports.deleteUserFile = function(user_uid, file_uid, type, blacklistMode = false) { + let success = false; + const file_obj = db.get('users').find({uid: user_uid}).get(`files.${type}`).find({uid: file_uid}).value(); + if (file_obj) { + const usersFileFolder = config_api.getConfigItem('ytdl_users_base_path'); + const ext = type === 'audio' ? '.mp3' : '.mp4'; + + // close descriptors + if (config_api.descriptors[file_obj.id]) { + try { + for (let i = 0; i < config_api.descriptors[file_obj.id].length; i++) { + config_api.descriptors[file_obj.id][i].destroy(); + } + } catch(e) { + + } + } + + const full_path = path.join(usersFileFolder, user_uid, type, file_obj.id + ext); + db.get('users').find({uid: user_uid}).get(`files.${type}`) + .remove({ + uid: file_uid + }).write(); + if (fs.existsSync(full_path)) { + // remove json and file + const json_path = path.join(usersFileFolder, user_uid, type, file_obj.id + '.info.json'); + const alternate_json_path = path.join(usersFileFolder, user_uid, type, file_obj.id + ext + '.info.json'); + let youtube_id = null; + if (fs.existsSync(json_path)) { + youtube_id = fs.readJSONSync(json_path).id; + fs.unlinkSync(json_path); + } else if (fs.existsSync(alternate_json_path)) { + youtube_id = fs.readJSONSync(alternate_json_path).id; + fs.unlinkSync(alternate_json_path); + } + + fs.unlinkSync(full_path); + + // do archive stuff + + let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); + if (useYoutubeDLArchive) { + const archive_path = path.join(usersFileFolder, user_uid, 'archives', `archive_${type}.txt`); + + // use subscriptions API to remove video from the archive file, and write it to the blacklist + if (fs.existsSync(archive_path)) { + const line = youtube_id ? subscriptions_api.removeIDFromArchive(archive_path, youtube_id) : null; + if (blacklistMode && line) { + let blacklistPath = path.join(usersFileFolder, user_uid, 'archives', `blacklist_${type}.txt`); + // adds newline to the beginning of the line + line = '\n' + line; + fs.appendFileSync(blacklistPath, line); + } + } else { + logger.info('Could not find archive file for audio files. Creating...'); + fs.closeSync(fs.openSync(archive_path, 'w')); + } + } + } + success = true; + } else { + success = false; + console.log('file does not exist!'); + } + + return success; +} + function getToken(queryParams) { if (queryParams && queryParams.jwt) { var parted = queryParams.jwt.split(' '); diff --git a/backend/config.js b/backend/config.js index b3415ee..19ec0ae 100644 --- a/backend/config.js +++ b/backend/config.js @@ -134,7 +134,8 @@ module.exports = { setConfigFile: setConfigFile, configExistsCheck: configExistsCheck, CONFIG_ITEMS: CONFIG_ITEMS, - setLogger: setLogger + setLogger: setLogger, + descriptors: {} } DEFAULT_CONFIG = {