This commit is contained in:
2022-06-27 09:57:50 -07:00
parent 92fdcb9923
commit 4452b64895
4 changed files with 453 additions and 551 deletions

956
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -36,25 +36,24 @@
"typescript": "^4.6.4" "typescript": "^4.6.4"
}, },
"dependencies": { "dependencies": {
"@bluelovers/fast-glob": "https://github.com/rishighan/fast-glob-v2-api.git",
"@elastic/elasticsearch": "^7.16.0", "@elastic/elasticsearch": "^7.16.0",
"@jorgeferrero/stream-to-buffer": "^2.0.6", "@jorgeferrero/stream-to-buffer": "^2.0.6",
"@root/walk": "^1.1.0", "@root/walk": "^1.1.0",
"@types/jest": "^27.4.1", "@types/jest": "^27.4.1",
"@bluelovers/fast-glob": "https://github.com/rishighan/fast-glob-v2-api.git",
"calibre-opds": "^1.0.7",
"opds-extra": "^3.0.9",
"http-response-stream": "^1.0.9",
"@types/mkdirp": "^1.0.0", "@types/mkdirp": "^1.0.0",
"@types/node": "^13.9.8", "@types/node": "^13.9.8",
"@types/string-similarity": "^4.0.0", "@types/string-similarity": "^4.0.0",
"axios": "^0.25.0", "axios": "^0.25.0",
"axios-retry": "^3.2.4", "axios-retry": "^3.2.4",
"bree": "^7.1.5", "bree": "^7.1.5",
"calibre-opds": "^1.0.7",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"delay": "^5.0.0", "delay": "^5.0.0",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"filename-parser": "^1.0.4", "filename-parser": "^1.0.4",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"http-response-stream": "^1.0.9",
"image-js": "^0.34.0", "image-js": "^0.34.0",
"imghash": "^0.0.9", "imghash": "^0.0.9",
"jsdom": "^15.2.1", "jsdom": "^15.2.1",
@@ -75,7 +74,9 @@
"nats": "^1.3.2", "nats": "^1.3.2",
"node-calibre": "^2.1.1", "node-calibre": "^2.1.1",
"node-unrar-js": "^1.0.5", "node-unrar-js": "^1.0.5",
"opds-extra": "^3.0.9",
"p7zip-threetwo": "^1.0.4", "p7zip-threetwo": "^1.0.4",
"sanitize-filename-ts": "^1.0.2",
"sharp": "^0.30.4", "sharp": "^0.30.4",
"socket.io-redis": "^6.1.1", "socket.io-redis": "^6.1.1",
"threetwo-ui-typings": "^1.0.14", "threetwo-ui-typings": "^1.0.14",

View File

@@ -13,6 +13,7 @@ import {
} from "threetwo-ui-typings"; } from "threetwo-ui-typings";
import { includes, remove, indexOf } from "lodash"; import { includes, remove, indexOf } from "lodash";
import { Errors } from "moleculer"; import { Errors } from "moleculer";
import { sanitize } from "sanitize-filename-ts";
const ALLOWED_IMAGE_FILE_FORMATS = [".jpg", ".jpeg", ".png"]; const ALLOWED_IMAGE_FILE_FORMATS = [".jpg", ".jpeg", ".png"];

View File

@@ -36,6 +36,7 @@ import { isEmpty, isNil, isUndefined, remove, each, map, reject } from "lodash";
import * as p7zip from "p7zip-threetwo"; import * as p7zip from "p7zip-threetwo";
import path from "path"; import path from "path";
import sharp from "sharp"; import sharp from "sharp";
import { sanitize } from "sanitize-filename-ts";
import { IMPORT_IMAGE_FILE_FORMATS } from "../constants/allowedFileFormats"; import { IMPORT_IMAGE_FILE_FORMATS } from "../constants/allowedFileFormats";
import { USERDATA_DIRECTORY } from "../constants/directories"; import { USERDATA_DIRECTORY } from "../constants/directories";
import { import {
@@ -76,7 +77,7 @@ export const extractComicInfoXMLFromRar = async (
}; };
const { fileNameWithoutExtension, extension } = const { fileNameWithoutExtension, extension } =
getFileConstituents(filePath); getFileConstituents(filePath);
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${fileNameWithoutExtension}`; const targetDirectory = `${USERDATA_DIRECTORY}/covers/${sanitize(fileNameWithoutExtension)}`;
await createDirectory(directoryOptions, targetDirectory); await createDirectory(directoryOptions, targetDirectory);
const archive = new Unrar({ const archive = new Unrar({
@@ -103,7 +104,10 @@ export const extractComicInfoXMLFromRar = async (
remove( remove(
filesInArchive, filesInArchive,
({ name }) => !IMPORT_IMAGE_FILE_FORMATS.includes(path.extname(name).toLowerCase()) ({ name }) =>
!IMPORT_IMAGE_FILE_FORMATS.includes(
path.extname(name).toLowerCase()
)
); );
const files = filesInArchive.sort((a, b) => { const files = filesInArchive.sort((a, b) => {
if (!isUndefined(a) && !isUndefined(b)) { if (!isUndefined(a) && !isUndefined(b)) {
@@ -153,7 +157,7 @@ export const extractComicInfoXMLFromRar = async (
}); });
const coverFilePromise = new Promise((resolve, reject) => { const coverFilePromise = new Promise((resolve, reject) => {
const coverFile = path.basename(files[0].name); const coverFile = sanitize(path.basename(files[0].name));
const sharpStream = sharp().resize(275).toFormat("png"); const sharpStream = sharp().resize(275).toFormat("png");
const coverExtractionStream = archive.stream(files[0].name); const coverExtractionStream = archive.stream(files[0].name);
const resizeStream = coverExtractionStream.pipe(sharpStream); const resizeStream = coverExtractionStream.pipe(sharpStream);
@@ -203,7 +207,7 @@ export const extractComicInfoXMLFromZip = async (
}; };
const { fileNameWithoutExtension, extension } = const { fileNameWithoutExtension, extension } =
getFileConstituents(filePath); getFileConstituents(filePath);
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${fileNameWithoutExtension}`; const targetDirectory = `${USERDATA_DIRECTORY}/covers/${sanitize(fileNameWithoutExtension)}`;
await createDirectory(directoryOptions, targetDirectory); await createDirectory(directoryOptions, targetDirectory);
let filesToWriteToDisk = { coverFile: null, comicInfoXML: null }; let filesToWriteToDisk = { coverFile: null, comicInfoXML: null };
@@ -211,19 +215,19 @@ export const extractComicInfoXMLFromZip = async (
// read the archive // read the archive
let filesFromArchive = await p7zip.read(path.resolve(filePath)); let filesFromArchive = await p7zip.read(path.resolve(filePath));
// only allow allowed image formats
remove(
filesFromArchive.files,
({ name }) =>
!IMPORT_IMAGE_FILE_FORMATS.includes(path.extname(name).toLowerCase())
);
// detect ComicInfo.xml // detect ComicInfo.xml
const comicInfoXMLFileObject = remove( const comicInfoXMLFileObject = remove(
filesFromArchive.files, filesFromArchive.files,
(file) => path.basename(file.name.toLowerCase()) === "comicinfo.xml" (file) => path.basename(file.name.toLowerCase()) === "comicinfo.xml"
); );
// only allow allowed image formats
remove(
filesFromArchive.files,
({ name }) =>
!IMPORT_IMAGE_FILE_FORMATS.includes(
path.extname(name).toLowerCase()
)
);
// Natural sort // Natural sort
const files = filesFromArchive.files.sort((a, b) => { const files = filesFromArchive.files.sort((a, b) => {
@@ -236,7 +240,7 @@ export const extractComicInfoXMLFromZip = async (
}); });
// Push the first file (cover) to our extraction target // Push the first file (cover) to our extraction target
extractionTargets.push(files[0].name); extractionTargets.push(files[0].name);
filesToWriteToDisk.coverFile = files[0].name; filesToWriteToDisk.coverFile = sanitize(path.basename(files[0].name));
if (!isEmpty(comicInfoXMLFileObject)) { if (!isEmpty(comicInfoXMLFileObject)) {
filesToWriteToDisk.comicInfoXML = comicInfoXMLFileObject[0].name; filesToWriteToDisk.comicInfoXML = comicInfoXMLFileObject[0].name;
extractionTargets.push(filesToWriteToDisk.comicInfoXML); extractionTargets.push(filesToWriteToDisk.comicInfoXML);
@@ -290,9 +294,7 @@ export const extractComicInfoXMLFromZip = async (
const coverFilePromise = new Promise((resolve, reject) => { const coverFilePromise = new Promise((resolve, reject) => {
const sharpStream = sharp().resize(275).toFormat("png"); const sharpStream = sharp().resize(275).toFormat("png");
const coverStream = createReadStream( const coverStream = createReadStream(
`${targetDirectory}/${path.basename( `${targetDirectory}/${filesToWriteToDisk.coverFile}`
filesToWriteToDisk.coverFile
)}`
); );
coverStream coverStream
.pipe(sharpStream) .pipe(sharpStream)