🔧 Adding methods for comicinfo.xml detection/extraction

This commit is contained in:
2022-02-25 22:27:19 -08:00
parent fdc1acd1ad
commit 36d18d4846
5 changed files with 94 additions and 150 deletions

1
.gitignore vendored
View File

@@ -70,3 +70,4 @@ userdata/
.DS_Store
erl_crash.dump
temp
test

View File

@@ -1,85 +0,0 @@
"use strict";
import { ServiceBroker } from "moleculer";
import DbService from "moleculer-db";
import {DbMixin} from "../../../mixins/db.mixin";
describe("Test DB mixin", () => {
describe("Test schema generator", () => {
const broker = new ServiceBroker({ logger: false, cacher: "Memory" });
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("check schema properties", async () => {
const schema = new DbMixin("my-collection").start();
expect(schema.mixins).toEqual([DbService]);
// @ts-ignore
expect(schema.adapter).toBeInstanceOf(DbService.MemoryAdapter);
expect(schema.started).toBeDefined();
expect(schema.events["cache.clean.my-collection"]).toBeInstanceOf(Function);
});
it("check cache event handler", async () => {
jest.spyOn(broker.cacher, "clean");
const schema = new DbMixin("my-collection").start();
// @ts-ignore
await schema.events["cache.clean.my-collection"].call({ broker, fullName: "my-service" });
expect(broker.cacher.clean).toBeCalledTimes(1);
expect(broker.cacher.clean).toBeCalledWith("my-service.*");
});
describe("Check service started handler", () => {
it("should not call seedDB method", async () => {
const schema = new DbMixin("my-collection").start();
schema.adapter.count = jest.fn(async () => 10);
const seedDBFn = jest.fn();
// @ts-ignore
await schema.started.call({ broker, logger: broker.logger, adapter: schema.adapter, seedDB: seedDBFn });
expect(schema.adapter.count).toBeCalledTimes(1);
expect(schema.adapter.count).toBeCalledWith();
expect(seedDBFn).toBeCalledTimes(0);
});
it("should call seedDB method", async () => {
const schema = new DbMixin("my-collection").start();
schema.adapter.count = jest.fn(async () => 0);
const seedDBFn = jest.fn();
// @ts-ignore
await schema.started.call({ broker, logger: broker.logger, adapter: schema.adapter, seedDB: seedDBFn });
expect(schema.adapter.count).toBeCalledTimes(2);
expect(schema.adapter.count).toBeCalledWith();
expect(seedDBFn).toBeCalledTimes(1);
expect(seedDBFn).toBeCalledWith();
});
});
it("should broadcast a cache clear event", async () => {
const schema = new DbMixin("my-collection").start();
const ctx = {
broadcast: jest.fn(),
};
await schema.methods.entityChanged(null, null, ctx);
expect(ctx.broadcast).toBeCalledTimes(1);
expect(ctx.broadcast).toBeCalledWith("cache.clean.my-collection");
});
});
});

View File

@@ -1,40 +0,0 @@
"use strict";
import { Errors, ServiceBroker} from "moleculer";
import TestService from "../../../services/greeter.service";
describe("Test 'greeter' service", () => {
const broker = new ServiceBroker({ logger: false });
broker.createService(TestService);
beforeAll(() => broker.start());
afterAll(() => broker.stop());
describe("Test 'greeter.hello' action", () => {
it("should return with 'Hello Moleculer'", async () => {
const res = await broker.call("greeter.hello");
expect(res).toBe("Hello Moleculer");
});
});
describe("Test 'greeter.welcome' action", () => {
it("should return with 'Welcome'", async () => {
const res = await broker.call("greeter.welcome", { name: "Adam" });
expect(res).toBe("Welcome, Adam");
});
it("should reject an ValidationError", async () => {
expect.assertions(1);
try {
await broker.call("greeter.welcome");
} catch (err) {
expect(err).toBeInstanceOf(Errors.ValidationError);
}
});
});
});

View File

@@ -44,63 +44,65 @@ import {
import { constructPaths, explodePath, walkFolder } from "../utils/file.utils";
import { resizeImage } from "./imagetransformation.utils";
import { isNil } from "lodash";
import { isNil, isUndefined } from "lodash";
import { convertXMLToJSON } from "./xml.utils";
const sevenZip = require("7zip-min");
const unrar = require("node-unrar-js");
const { Calibre } = require("node-calibre");
import { USERDATA_DIRECTORY, COMICS_DIRECTORY } from "../constants/directories";
export const extractCoverFromFile2 = async (
fileObject: any
): Promise<IExtractedComicBookCoverFile> => {
try {
const { filePath, fileSize } = fileObject;
const calibre = new Calibre();
console.info(`Initiating extraction process for path ${filePath}`);
// 1. Check for process.env.COMICS_DIRECTORY and process.env.USERDATA_DIRECTORY
if (!isNil(USERDATA_DIRECTORY)) {
// 2. Create the directory to which the cover image will be extracted
console.info("Attempting to create target directory for cover extraction...");
console.info(
"Attempting to create target directory for cover extraction..."
);
const directoryOptions = {
mode: 0o2775,
};
const extension = path.extname(filePath);
const fileNameWithExtension = path.basename(filePath);
const fileNameWithoutExtension = path.basename(filePath, path.extname(filePath));
const fileNameWithoutExtension = path.basename(
filePath,
path.extname(filePath)
);
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${fileNameWithoutExtension}`;
await fse.ensureDir(targetDirectory, directoryOptions);
console.info(`%s was created.`, targetDirectory);
// 2.1 look for comicinfo.xml
extractFileFromArchive(filePath, targetDirectory, extension);
// 3. extract the cover
console.info(`Starting cover extraction...`);
let result: string;
const targetCoverImageFilePath = path.resolve(
targetDirectory +
"/" +
fileNameWithoutExtension +
"_cover.jpg"
targetDirectory + "/" + fileNameWithoutExtension + "_cover.jpg"
);
const ebookMetaPath = process.env.CALIBRE_EBOOK_META_PATH
? `${process.env.CALIBRE_EBOOK_META_PATH}`
: `ebook-meta`;
result = await calibre.run(
ebookMetaPath,
[filePath],
{
getCover: targetCoverImageFilePath,
}
result = await calibre.run(ebookMetaPath, [filePath], {
getCover: targetCoverImageFilePath,
});
console.info(
`ebook-meta ran with the following result: %o`,
result
);
console.info(`ebook-meta ran with the following result: %o`, result)
// 4. create rendition path
const renditionPath =
targetDirectory+
"/" +
fileNameWithoutExtension +
"_275px.jpg";
targetDirectory + "/" + fileNameWithoutExtension + "_275px.jpg";
// 5. resize image
await resizeImage(
@@ -112,9 +114,9 @@ export const extractCoverFromFile2 = async (
name: fileNameWithoutExtension,
filePath,
fileSize,
extension: path.extname(filePath),
extension,
cover: {
filePath: path.relative(process.cwd(),renditionPath),
filePath: path.relative(process.cwd(), renditionPath),
},
containedIn: path.resolve(fileNameWithExtension),
calibreMetadata: {
@@ -170,3 +172,69 @@ export const unrarArchive = async (
console.info(`${error}`);
}
};
export const extractFileFromRar = async (
filePath: string,
fileToExtract: string
) => {
try {
// Read the archive file into a typedArray
const fileBuffer = await fse
.readFile(filePath)
.catch((err) => console.error("Failed to read file", err));
const extractor = await unrar.createExtractorFromData({
data: fileBuffer,
});
const list = extractor.getFileList();
const listArcHeader = list.arcHeader; // archive header
const fileHeaders = [...list.fileHeaders]; // load the file headers
const extracted = extractor.extract({ files: ["ComicInfo.xml"] });
const files = [...extracted.files]; //load the files
console.log("asdas", files[0]);
if(!isUndefined(files[0])) {
const trin = String.fromCharCode.apply(null, files[0].extraction)
const foo = await convertXMLToJSON(trin);
console.log(foo);
}
} catch (error) {
throw new Error(error);
}
};
export const extractFileFromZip = async (
filePath: string,
outputDirectory: string
) => {
const foo = sevenZip.cmd(
["e", path.resolve(filePath), outputDirectory, "*.xml"],
(err) => {
console.log(err);
}
);
return foo;
};
export const extractFileFromArchive = async (
filePath: string,
outputDirectory: string,
extension: string
) => {
console.log(extension);
switch (extension) {
case ".cbz":
console.log("cbz");
extractFileFromZip(filePath, outputDirectory);
break;
case ".cbr":
console.log("cbr");
extractFileFromRar(filePath, outputDirectory);
break;
default:
console.log("error na rao");
break;
}
};

View File

@@ -35,9 +35,9 @@ export const convertXMLToJSON = (xmlPayload) => {
trim: true,
normalizeTags: true,
});
const xml = fs.readFileSync(__dirname + "/comicinfo.xml", "utf8");
return parser
.parseStringPromise(xml)
.parseStringPromise(xmlPayload)
.then((result) => {
return result;
})