node-hp-scan-to 1.4.3 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -29
- package/dist/Destination.js +2 -2
- package/dist/Destination.js.map +1 -1
- package/dist/DiscoveryTree.js.map +1 -1
- package/dist/Event.js.map +1 -1
- package/dist/EventTable.js +1 -1
- package/dist/EventTable.js.map +1 -1
- package/dist/HPApi.js +4 -4
- package/dist/HPApi.js.map +1 -1
- package/dist/InputSource.js +1 -1
- package/dist/InputSource.js.map +1 -1
- package/dist/Job.js +2 -2
- package/dist/Job.js.map +1 -1
- package/dist/JpegUtil.d.ts +1 -0
- package/dist/JpegUtil.js.map +1 -1
- package/dist/PaperlessCOnfig.d.ts +7 -0
- package/dist/PaperlessCOnfig.js +3 -0
- package/dist/PaperlessCOnfig.js.map +1 -0
- package/dist/PaperlessConfig.d.ts +7 -0
- package/dist/PaperlessConfig.js +3 -0
- package/dist/PaperlessConfig.js.map +1 -0
- package/dist/PathHelper.js.map +1 -1
- package/dist/ScanCaps.js +12 -2
- package/dist/ScanCaps.js.map +1 -1
- package/dist/ScanContent.d.ts +0 -1
- package/dist/ScanContent.js +0 -24
- package/dist/ScanContent.js.map +1 -1
- package/dist/ScanJobManifest.js.map +1 -1
- package/dist/ScanJobSettings.js +2 -2
- package/dist/ScanJobSettings.js.map +1 -1
- package/dist/ScanStatus.js.map +1 -1
- package/dist/WalkupScanDestination.js.map +1 -1
- package/dist/WalkupScanDestinations.js +1 -1
- package/dist/WalkupScanDestinations.js.map +1 -1
- package/dist/WalkupScanManifest.js.map +1 -1
- package/dist/WalkupScanToCompDestination.js.map +1 -1
- package/dist/WalkupScanToCompDestinations.js +1 -1
- package/dist/WalkupScanToCompDestinations.js.map +1 -1
- package/dist/WalkupScanToCompManifest.js.map +1 -1
- package/dist/commitInfo.json +3 -0
- package/dist/healthcheck.d.ts +1 -0
- package/dist/healthcheck.js +24 -0
- package/dist/healthcheck.js.map +1 -0
- package/dist/index.js +106 -19
- package/dist/index.js.map +1 -1
- package/dist/listening.js +2 -2
- package/dist/listening.js.map +1 -1
- package/dist/paperless/PaperlessConfig.d.ts +7 -0
- package/dist/paperless/PaperlessConfig.js +3 -0
- package/dist/paperless/PaperlessConfig.js.map +1 -0
- package/dist/paperless/paperless.d.ts +7 -0
- package/dist/paperless/paperless.js +83 -0
- package/dist/paperless/paperless.js.map +1 -0
- package/dist/paperless.d.ts +7 -0
- package/dist/paperless.js +83 -0
- package/dist/paperless.js.map +1 -0
- package/dist/pdfProcessing.d.ts +4 -0
- package/dist/pdfProcessing.js +52 -0
- package/dist/pdfProcessing.js.map +1 -0
- package/dist/postProcessing.d.ts +3 -0
- package/dist/postProcessing.js +44 -0
- package/dist/postProcessing.js.map +1 -0
- package/dist/readDeviceCapabilities.js.map +1 -1
- package/dist/scanProcessing.d.ts +7 -1
- package/dist/scanProcessing.js +20 -49
- package/dist/scanProcessing.js.map +1 -1
- package/dist/test/PathHelper.test.js +2 -2
- package/dist/test/PathHelper.test.js.map +1 -1
- package/dist/test/ScanCaps.test.js +20 -0
- package/dist/test/ScanCaps.test.js.map +1 -1
- package/dist/test/clean.js.map +1 -1
- package/dist/test/scanProcessing.test.js +1 -0
- package/dist/test/scanProcessing.test.js.map +1 -1
- package/dist/test-bonjour.d.ts +1 -0
- package/dist/test-bonjour.js +20 -0
- package/dist/test-bonjour.js.map +1 -0
- package/package.json +12 -9
- package/src/Destination.ts +2 -2
- package/src/EventTable.ts +1 -1
- package/src/HPApi.ts +4 -4
- package/src/Job.ts +2 -2
- package/src/ScanCaps.ts +18 -8
- package/src/ScanContent.ts +0 -22
- package/src/ScanJobSettings.ts +2 -2
- package/src/WalkupScanDestinations.ts +1 -1
- package/src/WalkupScanToCompDestinations.ts +1 -1
- package/src/commitInfo.json +3 -0
- package/src/healthcheck.ts +17 -0
- package/src/index.ts +132 -24
- package/src/listening.ts +2 -2
- package/src/paperless/PaperlessConfig.ts +7 -0
- package/src/paperless/paperless.ts +122 -0
- package/src/pdfProcessing.ts +67 -0
- package/src/postProcessing.ts +91 -0
- package/src/scanProcessing.ts +46 -93
package/src/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import os from "os";
|
|
7
7
|
import { Command, Option, OptionValues, program } from "commander";
|
|
8
|
-
import Bonjour from "bonjour";
|
|
8
|
+
import { Bonjour } from "bonjour-service";
|
|
9
9
|
import config from "config";
|
|
10
10
|
import HPApi from "./HPApi";
|
|
11
11
|
import PathHelper from "./PathHelper";
|
|
@@ -19,11 +19,15 @@ import {
|
|
|
19
19
|
import {
|
|
20
20
|
AdfAutoScanConfig,
|
|
21
21
|
DirectoryConfig,
|
|
22
|
-
|
|
22
|
+
saveScanFromEvent,
|
|
23
23
|
ScanConfig,
|
|
24
24
|
scanFromAdf,
|
|
25
25
|
waitAdfLoaded,
|
|
26
26
|
} from "./scanProcessing";
|
|
27
|
+
import * as commitInfo from "./commitInfo.json";
|
|
28
|
+
import { PaperlessConfig } from "./paperless/PaperlessConfig";
|
|
29
|
+
import { startHealthCheckServer } from "./healthcheck";
|
|
30
|
+
|
|
27
31
|
|
|
28
32
|
let iteration = 0;
|
|
29
33
|
|
|
@@ -52,6 +56,7 @@ async function listenCmd(
|
|
|
52
56
|
let keepActive = true;
|
|
53
57
|
let errorCount = 0;
|
|
54
58
|
while (keepActive) {
|
|
59
|
+
iteration++;
|
|
55
60
|
console.log(`Running iteration: ${iteration} - errorCount: ${errorCount}`);
|
|
56
61
|
try {
|
|
57
62
|
const event = await waitScanEvent(deviceCapabilities, registrationConfig);
|
|
@@ -61,7 +66,7 @@ async function listenCmd(
|
|
|
61
66
|
scanConfig.directoryConfig.filePattern,
|
|
62
67
|
);
|
|
63
68
|
console.log(`Scan event captured, saving scan #${scanCount}`);
|
|
64
|
-
await
|
|
69
|
+
await saveScanFromEvent(
|
|
65
70
|
event,
|
|
66
71
|
folder,
|
|
67
72
|
tempFolder,
|
|
@@ -117,6 +122,7 @@ async function adfAutoscanCmd(
|
|
|
117
122
|
let keepActive = true;
|
|
118
123
|
let errorCount = 0;
|
|
119
124
|
while (keepActive) {
|
|
125
|
+
iteration++;
|
|
120
126
|
console.log(`Running iteration: ${iteration} - errorCount: ${errorCount}`);
|
|
121
127
|
try {
|
|
122
128
|
await waitAdfLoaded(
|
|
@@ -170,9 +176,9 @@ async function clearRegistrationsCmd(cmd: Command) {
|
|
|
170
176
|
|
|
171
177
|
function findOfficejetIp(deviceNamePrefix: string): Promise<string> {
|
|
172
178
|
return new Promise((resolve) => {
|
|
173
|
-
const bonjour = Bonjour();
|
|
179
|
+
const bonjour = new Bonjour();
|
|
174
180
|
console.log("Searching device...");
|
|
175
|
-
|
|
181
|
+
const browser = bonjour.find(
|
|
176
182
|
{
|
|
177
183
|
type: "http",
|
|
178
184
|
},
|
|
@@ -202,15 +208,15 @@ function getConfig<T>(name: string): T | undefined {
|
|
|
202
208
|
function setupScanParameters(command: Command): Command {
|
|
203
209
|
command.option(
|
|
204
210
|
"-d, --directory <dir>",
|
|
205
|
-
"Directory where scans are saved (default: /tmp/scan-to-
|
|
211
|
+
"Directory where scans are saved (default: /tmp/scan-to-pcRANDOM)",
|
|
206
212
|
);
|
|
207
213
|
command.option(
|
|
208
214
|
"-t, --temp-directory <dir>",
|
|
209
|
-
"Temp directory used for processing (default: /tmp/scan-to-
|
|
215
|
+
"Temp directory used for processing (default: /tmp/scan-to-pcRANDOM)",
|
|
210
216
|
);
|
|
211
217
|
command.option(
|
|
212
218
|
"-p, --pattern <pattern>",
|
|
213
|
-
'Pattern for filename (i.e. "scan"_dd.mm.yyyy_hh:MM:ss, without this its
|
|
219
|
+
'Pattern for filename (i.e. "scan"_dd.mm.yyyy_hh:MM:ss, without this its scanPageNUMBER)',
|
|
214
220
|
);
|
|
215
221
|
command.option(
|
|
216
222
|
"-r, --resolution <dpi>",
|
|
@@ -224,12 +230,33 @@ function setupScanParameters(command: Command): Command {
|
|
|
224
230
|
"-h, --height <height>",
|
|
225
231
|
"Height in pixel of the scans (default: 3507)",
|
|
226
232
|
);
|
|
233
|
+
command.option(
|
|
234
|
+
"-s, --paperless-post-document-url <paperless_post_document_url>",
|
|
235
|
+
"The paperless post document url (example: https://domain.tld/api/documents/post_document/)",
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
command.option(
|
|
239
|
+
"-o, --paperless-token <paperless_token>",
|
|
240
|
+
"The paperless token",
|
|
241
|
+
);
|
|
242
|
+
command.option(
|
|
243
|
+
"--paperless-group-multi-page-scan-into-a-pdf",
|
|
244
|
+
"Combine multiple scanned images into a single PDF document",
|
|
245
|
+
);
|
|
246
|
+
command.option(
|
|
247
|
+
"--paperless-always-send-as-pdf-file",
|
|
248
|
+
"Always convert scan job to pdf before sending to paperless",
|
|
249
|
+
);
|
|
250
|
+
command.option(
|
|
251
|
+
"-k, --paperless-keep-files",
|
|
252
|
+
"Keep the scan files on the file system (default: false)",
|
|
253
|
+
);
|
|
227
254
|
return command;
|
|
228
255
|
}
|
|
229
256
|
|
|
230
257
|
function setupParameterOpts(command: Command): Command {
|
|
231
258
|
command.option(
|
|
232
|
-
"-
|
|
259
|
+
"-a, --address <ip>",
|
|
233
260
|
"IP address of the device (this overrides -p)",
|
|
234
261
|
);
|
|
235
262
|
command.option(
|
|
@@ -266,41 +293,93 @@ function getIsDebug(options: OptionValues) {
|
|
|
266
293
|
return debug;
|
|
267
294
|
}
|
|
268
295
|
|
|
269
|
-
function
|
|
296
|
+
function getPaperlessConfig(
|
|
297
|
+
parentOption: OptionValues,
|
|
298
|
+
): PaperlessConfig | undefined {
|
|
299
|
+
const paperlessPostDocumentUrl: string =
|
|
300
|
+
parentOption.paperlessPostDocumentUrl ||
|
|
301
|
+
getConfig("paperless_post_document_url");
|
|
302
|
+
const configPaperlessToken: string =
|
|
303
|
+
parentOption.paperlessToken || getConfig("paperless_token");
|
|
304
|
+
const configPaperlessKeepFiles =
|
|
305
|
+
parentOption.paperlessKeepFiles ||
|
|
306
|
+
getConfig("paperless_keep_files") ||
|
|
307
|
+
false;
|
|
308
|
+
|
|
309
|
+
if (paperlessPostDocumentUrl && configPaperlessToken) {
|
|
310
|
+
const configPaperlessKeepFiles: boolean =
|
|
311
|
+
parentOption.paperlessKeepFiles ||
|
|
312
|
+
getConfig("paperless_keep_files") ||
|
|
313
|
+
false;
|
|
314
|
+
const groupMultiPageScanIntoAPdf: boolean =
|
|
315
|
+
parentOption.paperlessGroupMultiPageScanIntoAPdf ||
|
|
316
|
+
getConfig("paperless_group_multi_page_scan_into_a_pdf") ||
|
|
317
|
+
false;
|
|
318
|
+
const alwaysSendAsPdfFile: boolean =
|
|
319
|
+
parentOption.paperlessAlwaysSendAsPdfFile ||
|
|
320
|
+
getConfig("paperless_always_send_as_pdf_file") ||
|
|
321
|
+
false;
|
|
322
|
+
|
|
323
|
+
console.log(
|
|
324
|
+
`Paperless configuration provided, post document url: ${paperlessPostDocumentUrl}, the token length: ${configPaperlessToken.length}, keepFiles: ${configPaperlessKeepFiles}`,
|
|
325
|
+
);
|
|
326
|
+
return {
|
|
327
|
+
postDocumentUrl: paperlessPostDocumentUrl,
|
|
328
|
+
authToken: configPaperlessToken,
|
|
329
|
+
keepFiles: configPaperlessKeepFiles,
|
|
330
|
+
groupMultiPageScanIntoAPdf: groupMultiPageScanIntoAPdf,
|
|
331
|
+
alwaysSendAsPdfFile: alwaysSendAsPdfFile,
|
|
332
|
+
};
|
|
333
|
+
} else {
|
|
334
|
+
return undefined;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function getHealthCheckSetting(option: OptionValues) {
|
|
339
|
+
const healthCheckEnabled: boolean =
|
|
340
|
+
option.healthCheck || getConfig("enableHealthCheck") === true;
|
|
341
|
+
let healthCheckPort: number;
|
|
342
|
+
if (option.healthCheckPort) {
|
|
343
|
+
healthCheckPort = parseInt(option.healthCheckPort, 10);
|
|
344
|
+
} else {
|
|
345
|
+
healthCheckPort = getConfig<number>("healthCheckPort") || 3000;
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
isHealthCheckEnabled: healthCheckEnabled,
|
|
349
|
+
healthCheckPort: healthCheckPort,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function getScanConfiguration(option: OptionValues) {
|
|
270
354
|
const directoryConfig: DirectoryConfig = {
|
|
271
|
-
directory:
|
|
272
|
-
tempDirectory:
|
|
273
|
-
filePattern:
|
|
355
|
+
directory: option.directory || getConfig("directory"),
|
|
356
|
+
tempDirectory: option.tempDirectory || getConfig("tempDirectory"),
|
|
357
|
+
filePattern: option.pattern || getConfig("pattern"),
|
|
274
358
|
};
|
|
275
359
|
|
|
276
|
-
const configWidth = (
|
|
277
|
-
parentOption.width ||
|
|
278
|
-
getConfig("width") ||
|
|
279
|
-
0
|
|
280
|
-
).toString();
|
|
360
|
+
const configWidth = (option.width || getConfig("width") || 0).toString();
|
|
281
361
|
const width =
|
|
282
362
|
configWidth.toLowerCase() === "max"
|
|
283
363
|
? Number.MAX_SAFE_INTEGER
|
|
284
364
|
: parseInt(configWidth, 10);
|
|
285
365
|
|
|
286
|
-
const configHeight = (
|
|
287
|
-
parentOption.width ||
|
|
288
|
-
getConfig("height") ||
|
|
289
|
-
"0"
|
|
290
|
-
).toString();
|
|
366
|
+
const configHeight = (option.width || getConfig("height") || "0").toString();
|
|
291
367
|
const height =
|
|
292
368
|
configWidth.toLowerCase() === "max"
|
|
293
369
|
? Number.MAX_SAFE_INTEGER
|
|
294
370
|
: parseInt(configHeight, 10);
|
|
295
371
|
|
|
372
|
+
const paperlessConfig = getPaperlessConfig(option);
|
|
373
|
+
|
|
296
374
|
const scanConfig: ScanConfig = {
|
|
297
375
|
resolution: parseInt(
|
|
298
|
-
|
|
376
|
+
option.resolution || getConfig("resolution") || "200",
|
|
299
377
|
10,
|
|
300
378
|
),
|
|
301
379
|
width: width,
|
|
302
380
|
height: height,
|
|
303
381
|
directoryConfig,
|
|
382
|
+
paperlessConfig,
|
|
304
383
|
};
|
|
305
384
|
return scanConfig;
|
|
306
385
|
}
|
|
@@ -322,6 +401,15 @@ async function main() {
|
|
|
322
401
|
"-l, --label <label>",
|
|
323
402
|
"The label to display on the device (the default is the hostname)",
|
|
324
403
|
)
|
|
404
|
+
.addOption(
|
|
405
|
+
new Option("--health-check", "Start an http health check endpoint"),
|
|
406
|
+
)
|
|
407
|
+
.addOption(
|
|
408
|
+
new Option(
|
|
409
|
+
"--health-check-port <health-check-port>",
|
|
410
|
+
"Start an http health check endpoint",
|
|
411
|
+
),
|
|
412
|
+
)
|
|
325
413
|
.action(async (options, cmd) => {
|
|
326
414
|
const parentOption = cmd.parent.opts();
|
|
327
415
|
|
|
@@ -337,6 +425,11 @@ async function main() {
|
|
|
337
425
|
|
|
338
426
|
const deviceUpPollingInterval = getDeviceUpPollingInterval(parentOption);
|
|
339
427
|
|
|
428
|
+
const healthCheckSetting = getHealthCheckSetting(options);
|
|
429
|
+
if (healthCheckSetting.isHealthCheckEnabled) {
|
|
430
|
+
startHealthCheckServer(healthCheckSetting.healthCheckPort);
|
|
431
|
+
}
|
|
432
|
+
|
|
340
433
|
const scanConfig = getScanConfiguration(options);
|
|
341
434
|
|
|
342
435
|
await listenCmd(registrationConfig, scanConfig, deviceUpPollingInterval);
|
|
@@ -369,6 +462,15 @@ async function main() {
|
|
|
369
462
|
"Once document are detected to be in the adf, this specify the wait delay in millisecond before triggering the scan",
|
|
370
463
|
),
|
|
371
464
|
)
|
|
465
|
+
.addOption(
|
|
466
|
+
new Option("--health-check", "Start an http health check endpoint"),
|
|
467
|
+
)
|
|
468
|
+
.addOption(
|
|
469
|
+
new Option(
|
|
470
|
+
"--health-check-port <port>",
|
|
471
|
+
"Start an http health check endpoint",
|
|
472
|
+
),
|
|
473
|
+
)
|
|
372
474
|
.description(
|
|
373
475
|
"Automatically trigger a new scan job to this target once paper is detected in the automatic document feeder (adf)",
|
|
374
476
|
)
|
|
@@ -383,6 +485,11 @@ async function main() {
|
|
|
383
485
|
|
|
384
486
|
const deviceUpPollingInterval = getDeviceUpPollingInterval(parentOption);
|
|
385
487
|
|
|
488
|
+
const healthCheckSetting = getHealthCheckSetting(options);
|
|
489
|
+
if (healthCheckSetting.isHealthCheckEnabled) {
|
|
490
|
+
startHealthCheckServer(healthCheckSetting.healthCheckPort);
|
|
491
|
+
}
|
|
492
|
+
|
|
386
493
|
const scanConfig = getScanConfiguration(options);
|
|
387
494
|
|
|
388
495
|
const adfScanConfig: AdfAutoScanConfig = {
|
|
@@ -414,4 +521,5 @@ async function main() {
|
|
|
414
521
|
await program.parseAsync(process.argv);
|
|
415
522
|
}
|
|
416
523
|
|
|
524
|
+
console.log(`Current commit ID: ${commitInfo.commitId}`);
|
|
417
525
|
main().catch((err) => console.log(err));
|
package/src/listening.ts
CHANGED
|
@@ -6,9 +6,9 @@ import { DeviceCapabilities } from "./DeviceCapabilities";
|
|
|
6
6
|
export async function waitScanRequest(compEventURI: string): Promise<boolean> {
|
|
7
7
|
const waitMax = 50;
|
|
8
8
|
for (let i = 0; i < waitMax; i++) {
|
|
9
|
-
|
|
9
|
+
const walkupScanToCompEvent =
|
|
10
10
|
await HPApi.getWalkupScanToCompEvent(compEventURI);
|
|
11
|
-
|
|
11
|
+
const message = walkupScanToCompEvent.eventType;
|
|
12
12
|
if (message === "HostSelected") {
|
|
13
13
|
// this ok to wait
|
|
14
14
|
} else if (message === "ScanRequested") {
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fsSync from "fs";
|
|
2
|
+
import FormData from "form-data";
|
|
3
|
+
import axios from "axios";
|
|
4
|
+
import { ScanConfig } from "../scanProcessing";
|
|
5
|
+
import { ScanContent } from "../ScanContent";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import { convertToPdf, mergeToPdf } from "../pdfProcessing";
|
|
8
|
+
import { PaperlessConfig } from "./PaperlessConfig";
|
|
9
|
+
|
|
10
|
+
export async function uploadImagesAsSeparateDocumentsToPaperless(
|
|
11
|
+
scanJobContent: ScanContent,
|
|
12
|
+
paperlessConfig: PaperlessConfig,
|
|
13
|
+
) {
|
|
14
|
+
for (let i = 0; i < scanJobContent.elements.length; ++i) {
|
|
15
|
+
const filePath = scanJobContent.elements[i].path;
|
|
16
|
+
await uploadToPaperless(filePath, paperlessConfig);
|
|
17
|
+
if (!paperlessConfig.keepFiles) {
|
|
18
|
+
await fs.unlink(filePath);
|
|
19
|
+
console.log(
|
|
20
|
+
`Image document ${filePath} has been removed from the filesystem`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function convertImagesToPdfAndUploadAsSeparateDocumentsToPaperless(
|
|
27
|
+
scanJobContent: ScanContent,
|
|
28
|
+
paperlessConfig: PaperlessConfig,
|
|
29
|
+
) {
|
|
30
|
+
for (let i = 0; i < scanJobContent.elements.length; ++i) {
|
|
31
|
+
const pdfFilePath = await convertToPdf(
|
|
32
|
+
scanJobContent.elements[i],
|
|
33
|
+
!paperlessConfig.keepFiles,
|
|
34
|
+
);
|
|
35
|
+
if (pdfFilePath) {
|
|
36
|
+
await uploadToPaperless(pdfFilePath, paperlessConfig);
|
|
37
|
+
await fs.unlink(pdfFilePath);
|
|
38
|
+
} else {
|
|
39
|
+
console.log(
|
|
40
|
+
"Pdf generation has failed, nothing is going to be uploaded to paperless for: " +
|
|
41
|
+
scanJobContent.elements[i].path,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function mergeToPdfAndUploadAsSingleDocumentToPaperless(
|
|
48
|
+
folder: string,
|
|
49
|
+
scanCount: number,
|
|
50
|
+
scanJobContent: ScanContent,
|
|
51
|
+
scanConfig: ScanConfig,
|
|
52
|
+
scanDate: Date,
|
|
53
|
+
paperlessConfig: PaperlessConfig,
|
|
54
|
+
) {
|
|
55
|
+
const pdfFilePath = await mergeToPdf(
|
|
56
|
+
folder,
|
|
57
|
+
scanCount,
|
|
58
|
+
scanJobContent,
|
|
59
|
+
scanConfig.directoryConfig.filePattern,
|
|
60
|
+
scanDate,
|
|
61
|
+
!paperlessConfig.keepFiles,
|
|
62
|
+
);
|
|
63
|
+
if (pdfFilePath) {
|
|
64
|
+
await uploadToPaperless(pdfFilePath, paperlessConfig);
|
|
65
|
+
await fs.unlink(pdfFilePath);
|
|
66
|
+
console.log(
|
|
67
|
+
`Pdf document ${pdfFilePath} has been removed from the filesystem`,
|
|
68
|
+
);
|
|
69
|
+
} else {
|
|
70
|
+
console.log(
|
|
71
|
+
"Pdf generation has failed, nothing is going to be uploaded to paperless",
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function uploadPdfToPaperless(
|
|
77
|
+
pdfFilePath: string | null,
|
|
78
|
+
paperlessConfig: PaperlessConfig,
|
|
79
|
+
) {
|
|
80
|
+
if (pdfFilePath) {
|
|
81
|
+
await uploadToPaperless(pdfFilePath, paperlessConfig);
|
|
82
|
+
if (!paperlessConfig.keepFiles) {
|
|
83
|
+
await fs.unlink(pdfFilePath);
|
|
84
|
+
console.log(
|
|
85
|
+
`Pdf document ${pdfFilePath} has been removed from the filesystem`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
console.log(
|
|
90
|
+
"Pdf generation has failed, nothing is going to be uploaded to paperless",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function uploadToPaperless(
|
|
96
|
+
filePath: string,
|
|
97
|
+
paperlessConfig: PaperlessConfig,
|
|
98
|
+
): Promise<void> {
|
|
99
|
+
const url = paperlessConfig.postDocumentUrl;
|
|
100
|
+
|
|
101
|
+
const authToken = paperlessConfig.authToken;
|
|
102
|
+
|
|
103
|
+
const fileStream = fsSync.createReadStream(filePath);
|
|
104
|
+
|
|
105
|
+
const form = new FormData();
|
|
106
|
+
form.append("document", fileStream);
|
|
107
|
+
|
|
108
|
+
console.log(`Start uploading to paperless: ${filePath}`);
|
|
109
|
+
try {
|
|
110
|
+
const response = await axios.post(url, form, {
|
|
111
|
+
headers: {
|
|
112
|
+
...form.getHeaders(),
|
|
113
|
+
Authorization: `Token ${authToken}`,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
console.log("Document successfully uploaded to paperless:", response.data);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error("Fail to upload document:", error);
|
|
120
|
+
}
|
|
121
|
+
fileStream.close();
|
|
122
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ScanContent, ScanPage } from "./ScanContent";
|
|
2
|
+
import PathHelper from "./PathHelper";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { jsPDF } from "jspdf";
|
|
6
|
+
|
|
7
|
+
export async function mergeToPdf(
|
|
8
|
+
folder: string,
|
|
9
|
+
scanCount: number,
|
|
10
|
+
scanJobContent: ScanContent,
|
|
11
|
+
filePattern: string | undefined,
|
|
12
|
+
date: Date,
|
|
13
|
+
deleteFiles: boolean,
|
|
14
|
+
): Promise<string | null> {
|
|
15
|
+
if (scanJobContent.elements.length > 0) {
|
|
16
|
+
const pdfFilePath: string = PathHelper.getFileForScan(
|
|
17
|
+
folder,
|
|
18
|
+
scanCount,
|
|
19
|
+
filePattern,
|
|
20
|
+
"pdf",
|
|
21
|
+
date,
|
|
22
|
+
);
|
|
23
|
+
await createPdfFrom(scanJobContent, pdfFilePath);
|
|
24
|
+
if (deleteFiles) {
|
|
25
|
+
await Promise.all(scanJobContent.elements.map((e) => fs.unlink(e.path)));
|
|
26
|
+
}
|
|
27
|
+
return pdfFilePath;
|
|
28
|
+
}
|
|
29
|
+
console.log(`No page available to build a pdf file`);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function convertToPdf(
|
|
34
|
+
scanPage: ScanPage,
|
|
35
|
+
deleteFile: boolean,
|
|
36
|
+
): Promise<string | null> {
|
|
37
|
+
const fileName = path.basename(scanPage.path, path.extname(scanPage.path));
|
|
38
|
+
const pdfFilePath = path.join(path.dirname(scanPage.path), `${fileName}.pdf`);
|
|
39
|
+
|
|
40
|
+
await createPdfFrom({ elements: [scanPage] }, pdfFilePath);
|
|
41
|
+
if (deleteFile) {
|
|
42
|
+
await fs.unlink(scanPage.path);
|
|
43
|
+
}
|
|
44
|
+
return pdfFilePath;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function createPdfFrom(
|
|
48
|
+
scanContent: ScanContent,
|
|
49
|
+
destination: string,
|
|
50
|
+
) {
|
|
51
|
+
let doc: jsPDF | null = null;
|
|
52
|
+
for (const element of scanContent.elements) {
|
|
53
|
+
const widthInInches = element.width / element.xResolution;
|
|
54
|
+
const heightInInches = element.height / element.yResolution;
|
|
55
|
+
const format = [widthInInches, heightInInches];
|
|
56
|
+
|
|
57
|
+
if (doc == null) {
|
|
58
|
+
doc = new jsPDF({ unit: "in", floatPrecision: 3, format });
|
|
59
|
+
} else {
|
|
60
|
+
doc.addPage(format);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const imageByteBuffer = await fs.readFile(element.path);
|
|
64
|
+
doc.addImage(imageByteBuffer, "JPEG", 0, 0, widthInInches, heightInInches);
|
|
65
|
+
}
|
|
66
|
+
doc?.save(destination);
|
|
67
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ScanContent } from "./ScanContent";
|
|
2
|
+
import { mergeToPdf } from "./pdfProcessing";
|
|
3
|
+
import {
|
|
4
|
+
convertImagesToPdfAndUploadAsSeparateDocumentsToPaperless,
|
|
5
|
+
mergeToPdfAndUploadAsSingleDocumentToPaperless,
|
|
6
|
+
uploadImagesAsSeparateDocumentsToPaperless,
|
|
7
|
+
uploadPdfToPaperless,
|
|
8
|
+
} from "./paperless/paperless";
|
|
9
|
+
import { ScanConfig } from "./scanProcessing";
|
|
10
|
+
|
|
11
|
+
export async function postProcessing(
|
|
12
|
+
scanConfig: ScanConfig,
|
|
13
|
+
folder: string,
|
|
14
|
+
tempFolder: string,
|
|
15
|
+
scanCount: number,
|
|
16
|
+
scanJobContent: ScanContent,
|
|
17
|
+
scanDate: Date,
|
|
18
|
+
toPdf: boolean,
|
|
19
|
+
) {
|
|
20
|
+
const paperlessConfig = scanConfig.paperlessConfig;
|
|
21
|
+
if (toPdf) {
|
|
22
|
+
const pdfFilePath = await mergeToPdf(
|
|
23
|
+
paperlessConfig ? tempFolder : folder,
|
|
24
|
+
scanCount,
|
|
25
|
+
scanJobContent,
|
|
26
|
+
scanConfig.directoryConfig.filePattern,
|
|
27
|
+
scanDate,
|
|
28
|
+
true,
|
|
29
|
+
);
|
|
30
|
+
displayPdfScan(pdfFilePath, scanJobContent);
|
|
31
|
+
if (paperlessConfig) {
|
|
32
|
+
await uploadPdfToPaperless(pdfFilePath, paperlessConfig);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
displayJpegScan(scanJobContent);
|
|
36
|
+
if (paperlessConfig) {
|
|
37
|
+
if (paperlessConfig.groupMultiPageScanIntoAPdf) {
|
|
38
|
+
await mergeToPdfAndUploadAsSingleDocumentToPaperless(
|
|
39
|
+
folder,
|
|
40
|
+
scanCount,
|
|
41
|
+
scanJobContent,
|
|
42
|
+
scanConfig,
|
|
43
|
+
scanDate,
|
|
44
|
+
paperlessConfig,
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
if (paperlessConfig.alwaysSendAsPdfFile) {
|
|
48
|
+
await convertImagesToPdfAndUploadAsSeparateDocumentsToPaperless(
|
|
49
|
+
scanJobContent,
|
|
50
|
+
paperlessConfig,
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
await uploadImagesAsSeparateDocumentsToPaperless(
|
|
54
|
+
scanJobContent,
|
|
55
|
+
paperlessConfig,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function displayPdfScan(
|
|
64
|
+
pdfFilePath: string | null,
|
|
65
|
+
scanJobContent: ScanContent,
|
|
66
|
+
) {
|
|
67
|
+
if (pdfFilePath === null) {
|
|
68
|
+
console.log(`Pdf generated has not been generated`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
console.log(
|
|
72
|
+
`The following page(s) have been rendered inside '${pdfFilePath}': `,
|
|
73
|
+
);
|
|
74
|
+
scanJobContent.elements.forEach((e) =>
|
|
75
|
+
console.log(
|
|
76
|
+
`\t- page ${e.pageNumber.toString().padStart(3, " ")} - ${e.width}x${
|
|
77
|
+
e.height
|
|
78
|
+
}`,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function displayJpegScan(scanJobContent: ScanContent) {
|
|
84
|
+
scanJobContent.elements.forEach((e) =>
|
|
85
|
+
console.log(
|
|
86
|
+
`\t- page ${e.pageNumber.toString().padStart(3, " ")} - ${e.width}x${
|
|
87
|
+
e.height
|
|
88
|
+
} - ${e.path}`,
|
|
89
|
+
),
|
|
90
|
+
);
|
|
91
|
+
}
|