Merge pull request #7 from rishighan/qbittorrent-settings

🌊 Modified settings model schema
This commit was merged in pull request #7.
This commit is contained in:
2023-12-30 00:52:17 -05:00
committed by GitHub
9 changed files with 704 additions and 695 deletions

View File

@@ -2,7 +2,7 @@ const paginate = require("mongoose-paginate-v2");
const { Client } = require("@elastic/elasticsearch"); const { Client } = require("@elastic/elasticsearch");
import ComicVineMetadataSchema from "./comicvine.metadata.model"; import ComicVineMetadataSchema from "./comicvine.metadata.model";
import { mongoosastic } from "mongoosastic-ts"; import { mongoosastic } from "mongoosastic-ts";
const mongoose = require("mongoose") const mongoose = require("mongoose");
import { import {
MongoosasticDocument, MongoosasticDocument,
MongoosasticModel, MongoosasticModel,
@@ -112,6 +112,7 @@ const ComicSchema = mongoose.Schema(
}, },
}, },
torrent: { torrent: {
downloads: [],
sourceApplication: String, sourceApplication: String,
magnet: String, magnet: String,
tracker: String, tracker: String,

View File

@@ -1,21 +1,28 @@
const mongoose = require("mongoose"); const mongoose = require("mongoose");
const paginate = require("mongoose-paginate-v2"); const paginate = require("mongoose-paginate-v2");
const HostSchema = mongoose.Schema({
_id: false,
username: String,
password: String,
hostname: String,
port: String,
protocol: String,
});
const SettingsScehma = mongoose.Schema({ const SettingsScehma = mongoose.Schema({
directConnect: { directConnect: {
client: { client: {
host: { host: HostSchema,
username: String,
password: String,
hostname: String,
port: String,
protocol: String,
},
airDCPPUserSettings: Object, airDCPPUserSettings: Object,
hubs: Array, hubs: Array,
}, },
}, },
bittorrent: {
client: {
name: String,
host: HostSchema,
},
},
}); });
const Settings = mongoose.model("Settings", SettingsScehma); const Settings = mongoose.model("Settings", SettingsScehma);

861
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ import { Context, Service, ServiceBroker } from "moleculer";
import JobResult from "../models/jobresult.model"; import JobResult from "../models/jobresult.model";
import { refineQuery } from "filename-parser"; import { refineQuery } from "filename-parser";
import BullMqMixin from "moleculer-bullmq"; import BullMqMixin from "moleculer-bullmq";
import { extractFromArchive } from "../utils/uncompression.utils"; import { extractFromArchive, uncompressEntireArchive } from "../utils/uncompression.utils";
import { isNil, isUndefined } from "lodash"; import { isNil, isUndefined } from "lodash";
import { pubClient } from "../config/redis.config"; import { pubClient } from "../config/redis.config";
@@ -47,12 +47,15 @@ export default class JobQueueService extends Service {
enqueue: { enqueue: {
queue: true, queue: true,
rest: "/GET enqueue", rest: "/GET enqueue",
handler: async (ctx: Context<{}>) => { handler: async (ctx: Context<{ queueName: string; description: string }>) => {
console.log(ctx.params);
const { queueName, description } = ctx.params;
// Enqueue the job // Enqueue the job
const job = await this.localQueue(ctx, "enqueue.async", ctx.params, { const job = await this.localQueue(ctx, queueName, ctx.params, {
priority: 10, priority: 10,
}); });
console.log(`Job ${job.id} enqueued`); console.log(`Job ${job.id} enqueued`);
console.log(`${description}`);
return job.id; return job.id;
}, },
@@ -249,9 +252,24 @@ export default class JobQueueService extends Service {
]); ]);
}, },
}, },
"uncompressFullArchive.async": {
rest: "POST /uncompressFullArchive",
handler: async (ctx: Context<{ filePath: string; options: any }>) => {
const { filePath, options } = ctx.params;
console.log("asd", filePath);
// 2. Extract metadata from the archive
return await uncompressEntireArchive(filePath, options);
},
},
}, },
events: { events: {
async "uncompressFullArchive.async.active"(ctx: Context<{ id: number }>) {
console.log(`Uncompression Job ID ${ctx.params.id} is set to active.`);
},
async "uncompressFullArchive.async.completed"(ctx: Context<{ id: number }>) {
console.log(`Uncompression Job ID ${ctx.params.id} completed.`);
},
// use the `${QUEUE_NAME}.QUEUE_EVENT` scheme // use the `${QUEUE_NAME}.QUEUE_EVENT` scheme
async "enqueue.async.active"(ctx: Context<{ id: Number }>) { async "enqueue.async.active"(ctx: Context<{ id: Number }>) {
console.log(`Job ID ${ctx.params.id} is set to active.`); console.log(`Job ID ${ctx.params.id} is set to active.`);
@@ -260,10 +278,10 @@ export default class JobQueueService extends Service {
console.log("Queue drained."); console.log("Queue drained.");
await this.broker.call("socket.broadcast", { await this.broker.call("socket.broadcast", {
namespace: "/", namespace: "/",
event: "action", event: "LS_IMPORT_QUEUE_DRAINED",
args: [ args: [
{ {
type: "LS_IMPORT_QUEUE_DRAINED", message: "drained",
}, },
], ],
}); });
@@ -278,10 +296,9 @@ export default class JobQueueService extends Service {
// 4. Emit the LS_COVER_EXTRACTED event with the necessary details // 4. Emit the LS_COVER_EXTRACTED event with the necessary details
await this.broker.call("socket.broadcast", { await this.broker.call("socket.broadcast", {
namespace: "/", namespace: "/",
event: "action", event: "LS_COVER_EXTRACTED",
args: [ args: [
{ {
type: "LS_COVER_EXTRACTED",
completedJobCount, completedJobCount,
importResult: job.returnvalue.data.importResult, importResult: job.returnvalue.data.importResult,
}, },
@@ -315,10 +332,9 @@ export default class JobQueueService extends Service {
// 4. Emit the LS_COVER_EXTRACTION_FAILED event with the necessary details // 4. Emit the LS_COVER_EXTRACTION_FAILED event with the necessary details
await this.broker.call("socket.broadcast", { await this.broker.call("socket.broadcast", {
namespace: "/", namespace: "/",
event: "action", event: "LS_COVER_EXTRACTION_FAILED",
args: [ args: [
{ {
type: "LS_COVER_EXTRACTION_FAILED",
failedJobCount, failedJobCount,
importResult: job, importResult: job,
}, },

View File

@@ -186,6 +186,7 @@ export default class ImportService extends Service {
}, },
sessionId, sessionId,
importType: "new", importType: "new",
queueName: "enqueue.async",
}); });
} else { } else {
console.log("Comic already exists in the library."); console.log("Comic already exists in the library.");
@@ -385,6 +386,7 @@ export default class ImportService extends Service {
rest: "POST /getComicBookById", rest: "POST /getComicBookById",
params: { id: "string" }, params: { id: "string" },
async handler(ctx: Context<{ id: string }>) { async handler(ctx: Context<{ id: string }>) {
console.log(ctx.params.id);
return await Comic.findById(ctx.params.id); return await Comic.findById(ctx.params.id);
}, },
}, },

View File

@@ -75,9 +75,9 @@ export default class SettingsService extends Service {
) => { ) => {
try { try {
console.log(ctx.params); console.log(ctx.params);
const { query, pagination } = ctx.params; const { query, pagination, type } = ctx.params;
let eSQuery = {}; let eSQuery = {};
switch (ctx.params.type) { switch (type) {
case "all": case "all":
Object.assign(eSQuery, { Object.assign(eSQuery, {
match_all: {}, match_all: {},

View File

@@ -8,7 +8,7 @@ import {
} from "moleculer"; } from "moleculer";
import { DbMixin } from "../mixins/db.mixin"; import { DbMixin } from "../mixins/db.mixin";
import Settings from "../models/settings.model"; import Settings from "../models/settings.model";
import { isEmpty, pickBy, identity, map } from "lodash"; import { isEmpty, pickBy, identity, map, isNil } from "lodash";
const ObjectId = require("mongoose").Types.ObjectId; const ObjectId = require("mongoose").Types.ObjectId;
export default class SettingsService extends Service { export default class SettingsService extends Service {
@@ -42,44 +42,106 @@ export default class SettingsService extends Service {
params: {}, params: {},
async handler( async handler(
ctx: Context<{ ctx: Context<{
settingsPayload: { settingsPayload?: {
host: object; protocol: string;
airDCPPUserSettings: object; hostname: string;
hubs: []; port: string;
username: string;
password: string;
_id?: string;
airDCPPUserSettings?: object;
hubs?: [];
}; };
settingsObjectId: string; settingsObjectId?: string;
settingsKey: string;
}> }>
) { ) {
console.log("varan bhat", ctx.params); try {
const { host, airDCPPUserSettings, hubs } = let query = {};
ctx.params.settingsPayload; const { settingsKey, settingsObjectId } =
let query = { ctx.params;
host, const {
airDCPPUserSettings, hostname,
hubs, protocol,
}; port,
const keysToUpdate = pickBy(query, identity); username,
let updateQuery = {}; password,
} = ctx.params.settingsPayload;
const host = {
hostname,
protocol,
port,
username,
password,
};
const undefinedPropsInHostname = Object.values(
host
).filter((value) => value === undefined);
map(Object.keys(keysToUpdate), (key) => { // Update, depending what key was passed in params
updateQuery[`directConnect.client.${key}`] = // 1. Construct the update query
query[key]; switch (settingsKey) {
}); case "bittorrent":
const options = { console.log(
upsert: true, `Recieved settings for ${settingsKey}, building query...`
new: true, );
setDefaultsOnInsert: true, query = {
}; ...(undefinedPropsInHostname.length ===
const filter = { 0 && {
_id: new ObjectId(ctx.params.settingsObjectId), $set: {
}; "bittorrent.client.host": host,
const result = Settings.findOneAndUpdate( },
filter, }),
{ $set: updateQuery }, };
options break;
); case "directConnect":
console.log(
`Recieved settings for ${settingsKey}, building query...`
);
const { hubs, airDCPPUserSettings } =
ctx.params.settingsPayload;
query = {
...(undefinedPropsInHostname.length ===
0 && {
$set: {
"directConnect.client.host":
host,
},
}),
...(!isNil(hubs) && {
$set: {
"directConnect.client.hubs":
hubs,
},
}),
};
console.log(JSON.stringify(query, null, 4));
break;
return result; default:
return false;
}
// 2. Set up options, filters
const options = {
upsert: true,
setDefaultsOnInsert: true,
returnDocument: "after",
};
const filter = settingsObjectId
? { _id: settingsObjectId }
: {};
// 3. Execute the mongo query
const result = await Settings.findOneAndUpdate(
filter,
query,
options
);
return result;
} catch (err) {
return err;
}
}, },
}, },
deleteSettings: { deleteSettings: {

View File

@@ -26,89 +26,7 @@ export default class SocketService extends Service {
"/": { "/": {
events: { events: {
call: { call: {
// whitelist: ["math.*", "say.*", "accounts.*", "rooms.*", "io.*"], whitelist: ["socket.*"],
},
action: async (data) => {
switch (data.type) {
case "RESUME_SESSION":
console.log("Attempting to resume session...");
try {
const sessionRecord = await Session.find({
sessionId: data.session.sessionId,
});
// 1. Check for sessionId's existence, and a match
if (
sessionRecord.length !== 0 &&
sessionRecord[0].sessionId ===
data.session.sessionId
) {
// 2. Find if the queue has active jobs
const jobs: JobType = await this.broker.call(
"jobqueue.getJobCountsByType",
{}
);
const { active } = jobs;
if (active > 0) {
// 3. Get job counts
const completedJobCount =
await pubClient.get(
"completedJobCount"
);
const failedJobCount = await pubClient.get(
"failedJobCount"
);
// 4. Send the counts to the active socket.io session
await this.broker.call("socket.broadcast", {
namespace: "/",
event: "action",
args: [
{
type: "RESTORE_JOB_COUNTS_AFTER_SESSION_RESTORATION",
completedJobCount,
failedJobCount,
queueStatus: "running",
},
],
});
}
}
} catch (err) {
throw new MoleculerError(
err,
500,
"SESSION_ID_NOT_FOUND",
{
data: data.session.sessionId,
}
);
}
break;
case "LS_SET_QUEUE_STATUS":
console.log(data);
await this.broker.call(
"jobqueue.toggle",
{ action: data.data.queueAction },
{}
);
break;
case "LS_SINGLE_IMPORT":
console.info("AirDC++ finished a download -> ");
console.log(data);
await this.broker.call(
"library.importDownloadedComic",
{ bundle: data },
{}
);
break;
// uncompress archive events
case "COMICBOOK_EXTRACTION_SUCCESS":
console.log(data);
return data;
}
}, },
}, },
}, },
@@ -119,7 +37,84 @@ export default class SocketService extends Service {
}, },
}, },
hooks: {}, hooks: {},
actions: {}, actions: {
resumeSession: async (ctx: Context<{ sessionId: string }>) => {
const { sessionId } = ctx.params;
console.log("Attempting to resume session...");
try {
const sessionRecord = await Session.find({
sessionId,
});
// 1. Check for sessionId's existence, and a match
if (
sessionRecord.length !== 0 &&
sessionRecord[0].sessionId === sessionId
) {
// 2. Find if the queue has active, paused or waiting jobs
const jobs: JobType = await this.broker.call(
"jobqueue.getJobCountsByType",
{}
);
const { active, paused, waiting } = jobs;
if (active > 0 || paused > 0 || waiting > 0) {
// 3. Get job counts
const completedJobCount = await pubClient.get(
"completedJobCount"
);
const failedJobCount = await pubClient.get(
"failedJobCount"
);
// 4. Send the counts to the active socket.io session
await this.broker.call("socket.broadcast", {
namespace: "/",
event: "RESTORE_JOB_COUNTS_AFTER_SESSION_RESTORATION",
args: [
{
completedJobCount,
failedJobCount,
queueStatus: "running",
},
],
});
}
}
} catch (err) {
throw new MoleculerError(
err,
500,
"SESSION_ID_NOT_FOUND",
{
data: sessionId,
}
);
}
},
setQueueStatus: async (
ctx: Context<{
queueAction: string;
queueStatus: string;
}>
) => {
const { queueAction } = ctx.params;
await this.broker.call(
"jobqueue.toggle",
{ action: queueAction },
{}
);
},
importSingleIssue: async (ctx: Context<{}>) => {
console.info("AirDC++ finished a download -> ");
console.log(ctx.params);
// await this.broker.call(
// "library.importDownloadedComic",
// { bundle: data },
// {}
// );
},
},
methods: {}, methods: {},
async started() { async started() {
this.io.on("connection", async (socket) => { this.io.on("connection", async (socket) => {
@@ -146,10 +141,7 @@ export default class SocketService extends Service {
} }
// 2. else, retrieve it from Mongo and "resume" the socket.io connection // 2. else, retrieve it from Mongo and "resume" the socket.io connection
else { else {
console.log( console.log(`Found socketId ${socket.id}, no-op.`);
`Found socketId ${socket.id}, attempting to resume socket.io connection...`
);
console.log(socket.handshake.query.sessionId);
} }
}); });
}, },

View File

@@ -74,15 +74,14 @@ const errors = [];
*/ */
export const extractComicInfoXMLFromRar = async ( export const extractComicInfoXMLFromRar = async (
filePath: string, filePath: string,
mimeType: string, mimeType: string
): Promise<any> => { ): Promise<any> => {
try { try {
// Create the target directory // Create the target directory
const directoryOptions = { const directoryOptions = {
mode: 0o2775, mode: 0o2775,
}; };
const { fileNameWithoutExtension, extension } = const { fileNameWithoutExtension, extension } = getFileConstituents(filePath);
getFileConstituents(filePath);
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${sanitize( const targetDirectory = `${USERDATA_DIRECTORY}/covers/${sanitize(
fileNameWithoutExtension fileNameWithoutExtension
)}`; )}`;
@@ -93,17 +92,15 @@ export const extractComicInfoXMLFromRar = async (
bin: `${UNRAR_BIN_PATH}`, // this will change depending on Docker base OS bin: `${UNRAR_BIN_PATH}`, // this will change depending on Docker base OS
arguments: ["-v"], arguments: ["-v"],
}); });
const filesInArchive: [RarFile] = await new Promise( const filesInArchive: [RarFile] = await new Promise((resolve, reject) => {
(resolve, reject) => { return archive.list((err, entries) => {
return archive.list((err, entries) => { if (err) {
if (err) { console.log(`DEBUG: ${JSON.stringify(err, null, 2)}`);
console.log(`DEBUG: ${JSON.stringify(err, null, 2)}`); reject(err);
reject(err); }
} resolve(entries);
resolve(entries); });
}); });
}
);
remove(filesInArchive, ({ type }) => type === "Directory"); remove(filesInArchive, ({ type }) => type === "Directory");
const comicInfoXML = remove( const comicInfoXML = remove(
@@ -113,10 +110,7 @@ export const extractComicInfoXMLFromRar = async (
remove( remove(
filesInArchive, filesInArchive,
({ name }) => ({ name }) => !IMPORT_IMAGE_FILE_FORMATS.includes(path.extname(name).toLowerCase())
!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)) {
@@ -129,12 +123,8 @@ export const extractComicInfoXMLFromRar = async (
const comicInfoXMLFilePromise = new Promise((resolve, reject) => { const comicInfoXMLFilePromise = new Promise((resolve, reject) => {
let comicinfostring = ""; let comicinfostring = "";
if (!isUndefined(comicInfoXML[0])) { if (!isUndefined(comicInfoXML[0])) {
const comicInfoXMLFileName = path.basename( const comicInfoXMLFileName = path.basename(comicInfoXML[0].name);
comicInfoXML[0].name const writeStream = createWriteStream(`${targetDirectory}/${comicInfoXMLFileName}`);
);
const writeStream = createWriteStream(
`${targetDirectory}/${comicInfoXMLFileName}`
);
archive.stream(comicInfoXML[0]["name"]).pipe(writeStream); archive.stream(comicInfoXML[0]["name"]).pipe(writeStream);
writeStream.on("finish", async () => { writeStream.on("finish", async () => {
@@ -147,11 +137,7 @@ export const extractComicInfoXMLFromRar = async (
}); });
readStream.on("error", (error) => reject(error)); readStream.on("error", (error) => reject(error));
readStream.on("end", async () => { readStream.on("end", async () => {
if ( if (existsSync(`${targetDirectory}/${comicInfoXMLFileName}`)) {
existsSync(
`${targetDirectory}/${comicInfoXMLFileName}`
)
) {
const comicInfoJSON = await convertXMLToJSON( const comicInfoJSON = await convertXMLToJSON(
comicinfostring.toString() comicinfostring.toString()
); );
@@ -172,34 +158,29 @@ export const extractComicInfoXMLFromRar = async (
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);
resizeStream.toFile( resizeStream.toFile(`${targetDirectory}/${coverFile}`, (err, info) => {
`${targetDirectory}/${coverFile}`, if (err) {
(err, info) => { reject(err);
if (err) {
reject(err);
}
checkFileExists(`${targetDirectory}/${coverFile}`).then(
(bool) => {
console.log(`${coverFile} exists: ${bool}`);
// orchestrate result
resolve({
filePath,
name: fileNameWithoutExtension,
extension,
containedIn: targetDirectory,
fileSize: fse.statSync(filePath).size,
mimeType,
cover: {
filePath: path.relative(
process.cwd(),
`${targetDirectory}/${coverFile}`
),
},
});
}
);
} }
); checkFileExists(`${targetDirectory}/${coverFile}`).then((bool) => {
console.log(`${coverFile} exists: ${bool}`);
// orchestrate result
resolve({
filePath,
name: fileNameWithoutExtension,
extension,
containedIn: targetDirectory,
fileSize: fse.statSync(filePath).size,
mimeType,
cover: {
filePath: path.relative(
process.cwd(),
`${targetDirectory}/${coverFile}`
),
},
});
});
});
}); });
return Promise.all([comicInfoXMLFilePromise, coverFilePromise]); return Promise.all([comicInfoXMLFilePromise, coverFilePromise]);
@@ -210,15 +191,14 @@ export const extractComicInfoXMLFromRar = async (
export const extractComicInfoXMLFromZip = async ( export const extractComicInfoXMLFromZip = async (
filePath: string, filePath: string,
mimeType: string, mimeType: string
): Promise<any> => { ): Promise<any> => {
try { try {
// Create the target directory // Create the target directory
const directoryOptions = { const directoryOptions = {
mode: 0o2775, mode: 0o2775,
}; };
const { fileNameWithoutExtension, extension } = const { fileNameWithoutExtension, extension } = getFileConstituents(filePath);
getFileConstituents(filePath);
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${sanitize( const targetDirectory = `${USERDATA_DIRECTORY}/covers/${sanitize(
fileNameWithoutExtension fileNameWithoutExtension
)}`; )}`;
@@ -237,10 +217,7 @@ export const extractComicInfoXMLFromZip = async (
// only allow allowed image formats // only allow allowed image formats
remove( remove(
filesFromArchive.files, filesFromArchive.files,
({ name }) => ({ name }) => !IMPORT_IMAGE_FILE_FORMATS.includes(path.extname(name).toLowerCase())
!IMPORT_IMAGE_FILE_FORMATS.includes(
path.extname(name).toLowerCase()
)
); );
// Natural sort // Natural sort
@@ -261,13 +238,7 @@ export const extractComicInfoXMLFromZip = async (
extractionTargets.push(filesToWriteToDisk.comicInfoXML); extractionTargets.push(filesToWriteToDisk.comicInfoXML);
} }
// Extract the files. // Extract the files.
await p7zip.extract( await p7zip.extract(filePath, targetDirectory, extractionTargets, "", false);
filePath,
targetDirectory,
extractionTargets,
"",
false
);
// ComicInfoXML detection, parsing and conversion to JSON // ComicInfoXML detection, parsing and conversion to JSON
// Write ComicInfo.xml to disk // Write ComicInfo.xml to disk
@@ -275,26 +246,15 @@ export const extractComicInfoXMLFromZip = async (
const comicInfoXMLPromise = new Promise((resolve, reject) => { const comicInfoXMLPromise = new Promise((resolve, reject) => {
if ( if (
!isNil(filesToWriteToDisk.comicInfoXML) && !isNil(filesToWriteToDisk.comicInfoXML) &&
existsSync( existsSync(`${targetDirectory}/${path.basename(filesToWriteToDisk.comicInfoXML)}`)
`${targetDirectory}/${path.basename(
filesToWriteToDisk.comicInfoXML
)}`
)
) { ) {
let comicinfoString = ""; let comicinfoString = "";
const comicInfoXMLStream = createReadStream( const comicInfoXMLStream = createReadStream(
`${targetDirectory}/${path.basename( `${targetDirectory}/${path.basename(filesToWriteToDisk.comicInfoXML)}`
filesToWriteToDisk.comicInfoXML
)}`
);
comicInfoXMLStream.on(
"data",
(data) => (comicinfoString += data)
); );
comicInfoXMLStream.on("data", (data) => (comicinfoString += data));
comicInfoXMLStream.on("end", async () => { comicInfoXMLStream.on("end", async () => {
const comicInfoJSON = await convertXMLToJSON( const comicInfoJSON = await convertXMLToJSON(comicinfoString.toString());
comicinfoString.toString()
);
resolve({ resolve({
comicInfoJSON: comicInfoJSON.comicinfo, comicInfoJSON: comicInfoJSON.comicinfo,
}); });
@@ -314,9 +274,7 @@ export const extractComicInfoXMLFromZip = async (
coverStream coverStream
.pipe(sharpStream) .pipe(sharpStream)
.toFile( .toFile(
`${targetDirectory}/${path.basename( `${targetDirectory}/${path.basename(filesToWriteToDisk.coverFile)}`,
filesToWriteToDisk.coverFile
)}`,
(err, info) => { (err, info) => {
if (err) { if (err) {
reject(err); reject(err);
@@ -365,13 +323,10 @@ export const extractFromArchive = async (filePath: string) => {
return Object.assign({}, ...cbrResult); return Object.assign({}, ...cbrResult);
default: default:
console.error( console.error("Error inferring filetype for comicinfo.xml extraction.");
"Error inferring filetype for comicinfo.xml extraction."
);
throw new MoleculerError({}, 500, "FILETYPE_INFERENCE_ERROR", { throw new MoleculerError({}, 500, "FILETYPE_INFERENCE_ERROR", {
data: { message: "Cannot infer filetype."}, data: { message: "Cannot infer filetype." },
}); });
} }
}; };
@@ -381,10 +336,7 @@ export const extractFromArchive = async (filePath: string) => {
* @param {any} options * @param {any} options
* @returns {Promise} A promise containing the contents of the uncompressed archive. * @returns {Promise} A promise containing the contents of the uncompressed archive.
*/ */
export const uncompressEntireArchive = async ( export const uncompressEntireArchive = async (filePath: string, options: any) => {
filePath: string,
options: any
) => {
const mimeType = await getMimeType(filePath); const mimeType = await getMimeType(filePath);
console.log(`File has the following mime-type: ${mimeType}`); console.log(`File has the following mime-type: ${mimeType}`);
switch (mimeType) { switch (mimeType) {
@@ -426,8 +378,7 @@ export const uncompressRarArchive = async (filePath: string, options: any) => {
const directoryOptions = { const directoryOptions = {
mode: 0o2775, mode: 0o2775,
}; };
const { fileNameWithoutExtension, extension } = const { fileNameWithoutExtension, extension } = getFileConstituents(filePath);
getFileConstituents(filePath);
const targetDirectory = `${USERDATA_DIRECTORY}/expanded/${options.purpose}/${fileNameWithoutExtension}`; const targetDirectory = `${USERDATA_DIRECTORY}/expanded/${options.purpose}/${fileNameWithoutExtension}`;
await createDirectory(directoryOptions, targetDirectory); await createDirectory(directoryOptions, targetDirectory);
@@ -464,10 +415,7 @@ export const uncompressRarArchive = async (filePath: string, options: any) => {
return await resizeImageDirectory(targetDirectory, options); return await resizeImageDirectory(targetDirectory, options);
}; };
export const resizeImageDirectory = async ( export const resizeImageDirectory = async (directoryPath: string, options: any) => {
directoryPath: string,
options: any
) => {
const files = await walkFolder(directoryPath, [ const files = await walkFolder(directoryPath, [
".jpg", ".jpg",
".jpeg", ".jpeg",
@@ -495,25 +443,15 @@ export const resizeImage = (directoryPath: string, file: any, options: any) => {
const { baseWidth } = options.imageResizeOptions; const { baseWidth } = options.imageResizeOptions;
const sharpResizeInstance = sharp().resize(baseWidth).toFormat("jpg"); const sharpResizeInstance = sharp().resize(baseWidth).toFormat("jpg");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const resizedStream = createReadStream( const resizedStream = createReadStream(`${directoryPath}/${file.name}${file.extension}`);
`${directoryPath}/${file.name}${file.extension}`
);
if (fse.existsSync(`${directoryPath}/${file.name}${file.extension}`)) { if (fse.existsSync(`${directoryPath}/${file.name}${file.extension}`)) {
resizedStream resizedStream
.pipe(sharpResizeInstance) .pipe(sharpResizeInstance)
.toFile( .toFile(`${directoryPath}/${file.name}_${baseWidth}px${file.extension}`)
`${directoryPath}/${file.name}_${baseWidth}px${file.extension}`
)
.then((data) => { .then((data) => {
console.log( console.log(`Resized image ${JSON.stringify(data, null, 4)}`);
`Resized image ${JSON.stringify(data, null, 4)}` fse.unlink(`${directoryPath}/${file.name}${file.extension}`);
); resolve(`${directoryPath}/${file.name}_${baseWidth}px${file.extension}`);
fse.unlink(
`${directoryPath}/${file.name}${file.extension}`
);
resolve(
`${directoryPath}/${file.name}_${baseWidth}px${file.extension}`
);
}); });
} }
}); });