mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-04 04:59:37 +01:00
Fix:File permissions on cache dirs and cache images, Fix:Db delete read stream closing before write stream resulting in deletes sometimes not happening
This commit is contained in:
parent
c962090c3a
commit
853858825b
@ -1,6 +1,7 @@
|
|||||||
const Path = require('path')
|
const Path = require('path')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const stream = require('stream')
|
const stream = require('stream')
|
||||||
|
const filePerms = require('../utils/filePerms')
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const { resizeImage } = require('../utils/ffmpegHelpers')
|
const { resizeImage } = require('../utils/ffmpegHelpers')
|
||||||
|
|
||||||
@ -9,6 +10,34 @@ class CacheManager {
|
|||||||
this.CachePath = Path.join(global.MetadataPath, 'cache')
|
this.CachePath = Path.join(global.MetadataPath, 'cache')
|
||||||
this.CoverCachePath = Path.join(this.CachePath, 'covers')
|
this.CoverCachePath = Path.join(this.CachePath, 'covers')
|
||||||
this.ImageCachePath = Path.join(this.CachePath, 'images')
|
this.ImageCachePath = Path.join(this.CachePath, 'images')
|
||||||
|
|
||||||
|
this.cachePathsExist = false
|
||||||
|
}
|
||||||
|
|
||||||
|
async ensureCachePaths() { // Creates cache paths if necessary and sets owner and permissions
|
||||||
|
if (this.cachePathsExist) return
|
||||||
|
|
||||||
|
var pathsCreated = false
|
||||||
|
if (!(await fs.pathExists(this.CachePath))) {
|
||||||
|
await fs.mkdir(this.CachePath)
|
||||||
|
pathsCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await fs.pathExists(this.CoverCachePath))) {
|
||||||
|
await fs.mkdir(this.CoverCachePath)
|
||||||
|
pathsCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await fs.pathExists(this.ImageCachePath))) {
|
||||||
|
await fs.mkdir(this.ImageCachePath)
|
||||||
|
pathsCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathsCreated) {
|
||||||
|
await filePerms.setDefault(this.CachePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cachePathsExist = true
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleCoverCache(res, libraryItem, options = {}) {
|
async handleCoverCache(res, libraryItem, options = {}) {
|
||||||
@ -34,7 +63,7 @@ class CacheManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write cache
|
// Write cache
|
||||||
await fs.ensureDir(this.CoverCachePath)
|
await this.ensureCachePaths()
|
||||||
|
|
||||||
if (!libraryItem.media.coverPath || !await fs.pathExists(libraryItem.media.coverPath)) {
|
if (!libraryItem.media.coverPath || !await fs.pathExists(libraryItem.media.coverPath)) {
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
@ -43,6 +72,9 @@ class CacheManager {
|
|||||||
let writtenFile = await resizeImage(libraryItem.media.coverPath, path, width, height)
|
let writtenFile = await resizeImage(libraryItem.media.coverPath, path, width, height)
|
||||||
if (!writtenFile) return res.sendStatus(400)
|
if (!writtenFile) return res.sendStatus(400)
|
||||||
|
|
||||||
|
// Set owner and permissions of cache image
|
||||||
|
await filePerms.setDefault(path)
|
||||||
|
|
||||||
var readStream = fs.createReadStream(writtenFile)
|
var readStream = fs.createReadStream(writtenFile)
|
||||||
readStream.pipe(res)
|
readStream.pipe(res)
|
||||||
}
|
}
|
||||||
@ -57,7 +89,8 @@ class CacheManager {
|
|||||||
|
|
||||||
async purgeEntityCache(entityId, cachePath) {
|
async purgeEntityCache(entityId, cachePath) {
|
||||||
// If purgeAll has been called... The cover cache directory no longer exists
|
// If purgeAll has been called... The cover cache directory no longer exists
|
||||||
await fs.ensureDir(cachePath)
|
await this.ensureCachePaths()
|
||||||
|
|
||||||
return Promise.all((await fs.readdir(cachePath)).reduce((promises, file) => {
|
return Promise.all((await fs.readdir(cachePath)).reduce((promises, file) => {
|
||||||
if (file.startsWith(entityId)) {
|
if (file.startsWith(entityId)) {
|
||||||
Logger.debug(`[CacheManager] Going to purge ${file}`);
|
Logger.debug(`[CacheManager] Going to purge ${file}`);
|
||||||
@ -109,11 +142,14 @@ class CacheManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write cache
|
// Write cache
|
||||||
await fs.ensureDir(this.ImageCachePath)
|
await this.ensureCachePaths()
|
||||||
|
|
||||||
let writtenFile = await resizeImage(author.imagePath, path, width, height)
|
let writtenFile = await resizeImage(author.imagePath, path, width, height)
|
||||||
if (!writtenFile) return res.sendStatus(400)
|
if (!writtenFile) return res.sendStatus(400)
|
||||||
|
|
||||||
|
// Set owner and permissions of cache image
|
||||||
|
await filePerms.setDefault(path)
|
||||||
|
|
||||||
var readStream = fs.createReadStream(writtenFile)
|
var readStream = fs.createReadStream(writtenFile)
|
||||||
readStream.pipe(res)
|
readStream.pipe(res)
|
||||||
}
|
}
|
||||||
|
@ -480,7 +480,6 @@ const updateStoreData = async (store, match, update, tempstore, lockoptions) =>
|
|||||||
|
|
||||||
release = await lock(store, lockoptions);
|
release = await lock(store, lockoptions);
|
||||||
|
|
||||||
// console.log('Start updateStoreData for tempstore', tempstore, 'real store', store)
|
|
||||||
const handlerResults = await new Promise((resolve, reject) => {
|
const handlerResults = await new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const writer = createWriteStream(tempstore);
|
const writer = createWriteStream(tempstore);
|
||||||
@ -490,14 +489,11 @@ const updateStoreData = async (store, match, update, tempstore, lockoptions) =>
|
|||||||
// Reader was opening and closing before writer ever opened
|
// Reader was opening and closing before writer ever opened
|
||||||
const reader = createInterface({ input: createReadStream(store), crlfDelay: Infinity });
|
const reader = createInterface({ input: createReadStream(store), crlfDelay: Infinity });
|
||||||
|
|
||||||
// console.log('Writer opened for tempstore', tempstore)
|
|
||||||
reader.on("line", record => {
|
reader.on("line", record => {
|
||||||
handler.next(record, writer)
|
handler.next(record, writer)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
reader.on("close", () => {
|
reader.on("close", () => {
|
||||||
// console.log('Closing reader for store', store)
|
|
||||||
writer.end();
|
writer.end();
|
||||||
resolve(handler.return());
|
resolve(handler.return());
|
||||||
});
|
});
|
||||||
@ -505,12 +501,7 @@ const updateStoreData = async (store, match, update, tempstore, lockoptions) =>
|
|||||||
reader.on("error", error => reject(error));
|
reader.on("error", error => reject(error));
|
||||||
});
|
});
|
||||||
|
|
||||||
// writer.on('close', () => {
|
|
||||||
// console.log('Writer closed for tempstore', tempstore)
|
|
||||||
// })
|
|
||||||
|
|
||||||
writer.on("error", error => reject(error));
|
writer.on("error", error => reject(error));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
results = Object.assign({ store: store, tempstore: tempstore }, handlerResults);
|
results = Object.assign({ store: store, tempstore: tempstore }, handlerResults);
|
||||||
@ -579,26 +570,27 @@ const updateStoreDataSync = (store, match, update, tempstore) => {
|
|||||||
|
|
||||||
const deleteStoreData = async (store, match, tempstore, lockoptions) => {
|
const deleteStoreData = async (store, match, tempstore, lockoptions) => {
|
||||||
let release, results;
|
let release, results;
|
||||||
|
|
||||||
release = await lock(store, lockoptions);
|
release = await lock(store, lockoptions);
|
||||||
|
|
||||||
const handlerResults = await new Promise((resolve, reject) => {
|
const handlerResults = await new Promise((resolve, reject) => {
|
||||||
const reader = createInterface({ input: createReadStream(store), crlfDelay: Infinity });
|
|
||||||
const writer = createWriteStream(tempstore);
|
const writer = createWriteStream(tempstore);
|
||||||
const handler = Handler("delete", match);
|
const handler = Handler("delete", match);
|
||||||
|
|
||||||
writer.on("open", () => {
|
writer.on("open", () => {
|
||||||
|
// Create reader after writer opens otherwise the reader can sometimes close before the writer opens
|
||||||
|
const reader = createInterface({ input: createReadStream(store), crlfDelay: Infinity });
|
||||||
|
|
||||||
reader.on("line", record => handler.next(record, writer));
|
reader.on("line", record => handler.next(record, writer));
|
||||||
|
|
||||||
|
reader.on("close", () => {
|
||||||
|
writer.end();
|
||||||
|
resolve(handler.return());
|
||||||
|
});
|
||||||
|
|
||||||
|
reader.on("error", error => reject(error));
|
||||||
});
|
});
|
||||||
|
|
||||||
writer.on("error", error => reject(error));
|
writer.on("error", error => reject(error));
|
||||||
|
|
||||||
reader.on("close", () => {
|
|
||||||
writer.end();
|
|
||||||
resolve(handler.return());
|
|
||||||
});
|
|
||||||
|
|
||||||
reader.on("error", error => reject(error));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
results = Object.assign({ store: store, tempstore: tempstore }, handlerResults);
|
results = Object.assign({ store: store, tempstore: tempstore }, handlerResults);
|
||||||
|
@ -120,9 +120,6 @@ module.exports.extractCoverArt = extractCoverArt
|
|||||||
|
|
||||||
//This should convert based on the output file extension as well
|
//This should convert based on the output file extension as well
|
||||||
async function resizeImage(filePath, outputPath, width, height) {
|
async function resizeImage(filePath, outputPath, width, height) {
|
||||||
var dirname = Path.dirname(outputPath);
|
|
||||||
await fs.ensureDir(dirname);
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
var ffmpeg = Ffmpeg(filePath)
|
var ffmpeg = Ffmpeg(filePath)
|
||||||
ffmpeg.addOption(['-vf', `scale=${width || -1}:${height || -1}`])
|
ffmpeg.addOption(['-vf', `scale=${width || -1}:${height || -1}`])
|
||||||
|
Loading…
Reference in New Issue
Block a user