node-hp-scan-to 1.2.2 → 1.3.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.
Files changed (283) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -10
  3. package/dist/Destination.js +36 -84
  4. package/dist/Destination.js.map +1 -1
  5. package/dist/DeviceCapabilities.d.ts +4 -0
  6. package/dist/DeviceCapabilities.js +3 -0
  7. package/dist/DeviceCapabilities.js.map +1 -0
  8. package/dist/DiscoveryTree.d.ts +16 -0
  9. package/dist/DiscoveryTree.js +38 -0
  10. package/dist/DiscoveryTree.js.map +1 -0
  11. package/dist/Event.d.ts +1 -1
  12. package/dist/Event.js +24 -39
  13. package/dist/Event.js.map +1 -1
  14. package/dist/EventTable.d.ts +5 -0
  15. package/dist/EventTable.js +24 -18
  16. package/dist/EventTable.js.map +1 -1
  17. package/dist/HPApi.d.ts +26 -18
  18. package/dist/HPApi.js +386 -461
  19. package/dist/HPApi.js.map +1 -1
  20. package/dist/Job.d.ts +8 -7
  21. package/dist/Job.js +69 -86
  22. package/dist/Job.js.map +1 -1
  23. package/dist/JpegUtil.js +73 -82
  24. package/dist/JpegUtil.js.map +1 -1
  25. package/dist/KnownShortcut.d.ts +1 -0
  26. package/dist/KnownShortcut.js +3 -0
  27. package/dist/KnownShortcut.js.map +1 -0
  28. package/dist/PathHelper.d.ts +2 -1
  29. package/dist/PathHelper.js +41 -68
  30. package/dist/PathHelper.js.map +1 -1
  31. package/dist/ScanCaps.d.ts +7 -0
  32. package/dist/ScanCaps.js +17 -0
  33. package/dist/ScanCaps.js.map +1 -0
  34. package/dist/ScanContent.js +18 -73
  35. package/dist/ScanContent.js.map +1 -1
  36. package/dist/ScanJobManifest.d.ts +23 -0
  37. package/dist/ScanJobManifest.js +24 -0
  38. package/dist/ScanJobManifest.js.map +1 -0
  39. package/dist/ScanJobSettings.d.ts +3 -1
  40. package/dist/ScanJobSettings.js +48 -88
  41. package/dist/ScanJobSettings.js.map +1 -1
  42. package/dist/ScanStatus.d.ts +1 -0
  43. package/dist/ScanStatus.js +27 -28
  44. package/dist/ScanStatus.js.map +1 -1
  45. package/dist/WalkupScanDestination.d.ts +11 -13
  46. package/dist/WalkupScanDestination.js +32 -35
  47. package/dist/WalkupScanDestination.js.map +1 -1
  48. package/dist/WalkupScanDestinations.d.ts +1 -0
  49. package/dist/WalkupScanDestinations.js +21 -18
  50. package/dist/WalkupScanDestinations.js.map +1 -1
  51. package/dist/WalkupScanManifest.d.ts +23 -0
  52. package/dist/WalkupScanManifest.js +25 -0
  53. package/dist/WalkupScanManifest.js.map +1 -0
  54. package/dist/WalkupScanToCompCaps.d.ts +12 -0
  55. package/dist/WalkupScanToCompCaps.js +20 -0
  56. package/dist/WalkupScanToCompCaps.js.map +1 -0
  57. package/dist/WalkupScanToCompDestination.d.ts +10 -14
  58. package/dist/WalkupScanToCompDestination.js +32 -38
  59. package/dist/WalkupScanToCompDestination.js.map +1 -1
  60. package/dist/WalkupScanToCompDestinations.d.ts +1 -0
  61. package/dist/WalkupScanToCompDestinations.js +21 -18
  62. package/dist/WalkupScanToCompDestinations.js.map +1 -1
  63. package/dist/WalkupScanToCompEvent.d.ts +2 -1
  64. package/dist/WalkupScanToCompEvent.js +14 -11
  65. package/dist/WalkupScanToCompEvent.js.map +1 -1
  66. package/dist/WalkupScanToCompManifest.d.ts +23 -0
  67. package/dist/WalkupScanToCompManifest.js +25 -0
  68. package/dist/WalkupScanToCompManifest.js.map +1 -0
  69. package/dist/delay.d.ts +1 -0
  70. package/dist/delay.js +10 -0
  71. package/dist/delay.js.map +1 -0
  72. package/dist/fixJpegSize.d.ts +19 -0
  73. package/dist/fixJpegSize.js +292 -0
  74. package/dist/fixJpegSize.js.map +1 -0
  75. package/dist/index.js +209 -607
  76. package/dist/index.js.map +1 -1
  77. package/dist/listening.d.ts +9 -0
  78. package/dist/listening.js +108 -0
  79. package/dist/listening.js.map +1 -0
  80. package/dist/models/Destination.d.ts +8 -0
  81. package/dist/models/Destination.js +68 -0
  82. package/dist/models/Destination.js.map +1 -0
  83. package/dist/models/DiscoveryTree.d.ts +16 -0
  84. package/dist/models/DiscoveryTree.js +38 -0
  85. package/dist/models/DiscoveryTree.js.map +1 -0
  86. package/dist/models/Event.d.ts +21 -0
  87. package/dist/models/Event.js +32 -0
  88. package/dist/models/Event.js.map +1 -0
  89. package/dist/models/EventTable.d.ts +16 -0
  90. package/dist/models/EventTable.js +33 -0
  91. package/dist/models/EventTable.js.map +1 -0
  92. package/dist/models/Job.d.ts +37 -0
  93. package/dist/models/Job.js +78 -0
  94. package/dist/models/Job.js.map +1 -0
  95. package/dist/models/ScanCaps.d.ts +7 -0
  96. package/dist/models/ScanCaps.js +17 -0
  97. package/dist/models/ScanCaps.js.map +1 -0
  98. package/dist/models/ScanJobManifest.d.ts +23 -0
  99. package/dist/models/ScanJobManifest.js +24 -0
  100. package/dist/models/ScanJobManifest.js.map +1 -0
  101. package/dist/models/ScanJobSettings.d.ts +8 -0
  102. package/dist/models/ScanJobSettings.js +56 -0
  103. package/dist/models/ScanJobSettings.js.map +1 -0
  104. package/dist/models/WalkupScanDestination.d.ts +22 -0
  105. package/dist/models/WalkupScanDestination.js +38 -0
  106. package/dist/models/WalkupScanDestination.js.map +1 -0
  107. package/dist/models/WalkupScanDestinations.d.ts +12 -0
  108. package/dist/models/WalkupScanDestinations.js +30 -0
  109. package/dist/models/WalkupScanDestinations.js.map +1 -0
  110. package/dist/models/WalkupScanManifest.d.ts +23 -0
  111. package/dist/models/WalkupScanManifest.js +25 -0
  112. package/dist/models/WalkupScanManifest.js.map +1 -0
  113. package/dist/models/WalkupScanToCompCaps.d.ts +12 -0
  114. package/dist/models/WalkupScanToCompCaps.js +20 -0
  115. package/dist/models/WalkupScanToCompCaps.js.map +1 -0
  116. package/dist/models/WalkupScanToCompDestination.d.ts +22 -0
  117. package/dist/models/WalkupScanToCompDestination.js +38 -0
  118. package/dist/models/WalkupScanToCompDestination.js.map +1 -0
  119. package/dist/models/WalkupScanToCompDestinations.d.ts +12 -0
  120. package/dist/models/WalkupScanToCompDestinations.js +30 -0
  121. package/dist/models/WalkupScanToCompDestinations.js.map +1 -0
  122. package/dist/models/WalkupScanToCompEvent.d.ts +11 -0
  123. package/dist/models/WalkupScanToCompEvent.js +20 -0
  124. package/dist/models/WalkupScanToCompEvent.js.map +1 -0
  125. package/dist/models/WalkupScanToCompManifest.d.ts +23 -0
  126. package/dist/models/WalkupScanToCompManifest.js +25 -0
  127. package/dist/models/WalkupScanToCompManifest.js.map +1 -0
  128. package/dist/readDeviceCapabilities.d.ts +2 -0
  129. package/dist/readDeviceCapabilities.js +41 -0
  130. package/dist/readDeviceCapabilities.js.map +1 -0
  131. package/dist/scanProcess.d.ts +19 -0
  132. package/dist/scanProcess.js +292 -0
  133. package/dist/scanProcess.js.map +1 -0
  134. package/dist/scanProcessing.d.ts +20 -0
  135. package/dist/scanProcessing.js +320 -0
  136. package/dist/scanProcessing.js.map +1 -0
  137. package/dist/src/Destination.d.ts +8 -0
  138. package/dist/src/Destination.js +68 -0
  139. package/dist/src/Destination.js.map +1 -0
  140. package/dist/src/DiscoveryTree.d.ts +16 -0
  141. package/dist/src/DiscoveryTree.js +38 -0
  142. package/dist/src/DiscoveryTree.js.map +1 -0
  143. package/dist/src/Event.d.ts +21 -0
  144. package/dist/src/Event.js +32 -0
  145. package/dist/src/Event.js.map +1 -0
  146. package/dist/src/EventTable.d.ts +16 -0
  147. package/dist/src/EventTable.js +33 -0
  148. package/dist/src/EventTable.js.map +1 -0
  149. package/dist/src/HPApi.d.ts +50 -0
  150. package/dist/src/HPApi.js +454 -0
  151. package/dist/src/HPApi.js.map +1 -0
  152. package/dist/src/Job.d.ts +37 -0
  153. package/dist/src/Job.js +78 -0
  154. package/dist/src/Job.js.map +1 -0
  155. package/dist/src/JpegUtil.d.ts +26 -0
  156. package/dist/src/JpegUtil.js +229 -0
  157. package/dist/src/JpegUtil.js.map +1 -0
  158. package/dist/src/KnownShortcut.d.ts +1 -0
  159. package/dist/src/KnownShortcut.js +3 -0
  160. package/dist/src/KnownShortcut.js.map +1 -0
  161. package/dist/src/PathHelper.d.ts +6 -0
  162. package/dist/src/PathHelper.js +52 -0
  163. package/dist/src/PathHelper.js.map +1 -0
  164. package/dist/src/ScanCaps.d.ts +7 -0
  165. package/dist/src/ScanCaps.js +17 -0
  166. package/dist/src/ScanCaps.js.map +1 -0
  167. package/dist/src/ScanJobManifest.d.ts +23 -0
  168. package/dist/src/ScanJobManifest.js +24 -0
  169. package/dist/src/ScanJobManifest.js.map +1 -0
  170. package/dist/src/ScanJobSettings.d.ts +8 -0
  171. package/dist/src/ScanJobSettings.js +56 -0
  172. package/dist/src/ScanJobSettings.js.map +1 -0
  173. package/dist/src/ScanStatus.d.ts +19 -0
  174. package/dist/src/ScanStatus.js +35 -0
  175. package/dist/src/ScanStatus.js.map +1 -0
  176. package/dist/src/WalkupScanDestination.d.ts +22 -0
  177. package/dist/src/WalkupScanDestination.js +38 -0
  178. package/dist/src/WalkupScanDestination.js.map +1 -0
  179. package/dist/src/WalkupScanDestinations.d.ts +12 -0
  180. package/dist/src/WalkupScanDestinations.js +30 -0
  181. package/dist/src/WalkupScanDestinations.js.map +1 -0
  182. package/dist/src/WalkupScanManifest.d.ts +23 -0
  183. package/dist/src/WalkupScanManifest.js +25 -0
  184. package/dist/src/WalkupScanManifest.js.map +1 -0
  185. package/dist/src/WalkupScanToCompCaps.d.ts +12 -0
  186. package/dist/src/WalkupScanToCompCaps.js +20 -0
  187. package/dist/src/WalkupScanToCompCaps.js.map +1 -0
  188. package/dist/src/WalkupScanToCompDestination.d.ts +22 -0
  189. package/dist/src/WalkupScanToCompDestination.js +38 -0
  190. package/dist/src/WalkupScanToCompDestination.js.map +1 -0
  191. package/dist/src/WalkupScanToCompDestinations.d.ts +12 -0
  192. package/dist/src/WalkupScanToCompDestinations.js +30 -0
  193. package/dist/src/WalkupScanToCompDestinations.js.map +1 -0
  194. package/dist/src/WalkupScanToCompEvent.d.ts +11 -0
  195. package/dist/src/WalkupScanToCompEvent.js +20 -0
  196. package/dist/src/WalkupScanToCompEvent.js.map +1 -0
  197. package/dist/src/WalkupScanToCompManifest.d.ts +23 -0
  198. package/dist/src/WalkupScanToCompManifest.js +25 -0
  199. package/dist/src/WalkupScanToCompManifest.js.map +1 -0
  200. package/dist/src/delay.d.ts +1 -0
  201. package/dist/src/delay.js +10 -0
  202. package/dist/src/delay.js.map +1 -0
  203. package/dist/test/DiscoveryTree.test.d.ts +1 -0
  204. package/dist/test/DiscoveryTree.test.js +68 -0
  205. package/dist/test/DiscoveryTree.test.js.map +1 -0
  206. package/dist/test/EtagEventTable.test.d.ts +1 -0
  207. package/dist/test/EtagEventTable.test.js +93 -0
  208. package/dist/test/EtagEventTable.test.js.map +1 -0
  209. package/dist/test/Job.test.d.ts +1 -0
  210. package/dist/test/Job.test.js +104 -0
  211. package/dist/test/Job.test.js.map +1 -0
  212. package/dist/test/JpegUtil.test.d.ts +1 -0
  213. package/dist/test/JpegUtil.test.js +51 -0
  214. package/dist/test/JpegUtil.test.js.map +1 -0
  215. package/dist/test/PathHelper.test.d.ts +1 -0
  216. package/dist/test/PathHelper.test.js +99 -0
  217. package/dist/test/PathHelper.test.js.map +1 -0
  218. package/dist/test/ScanJobManifest.test.d.ts +1 -0
  219. package/dist/test/ScanJobManifest.test.js +56 -0
  220. package/dist/test/ScanJobManifest.test.js.map +1 -0
  221. package/dist/test/ScanJobSettings.test.d.ts +1 -0
  222. package/dist/test/ScanJobSettings.test.js +53 -0
  223. package/dist/test/ScanJobSettings.test.js.map +1 -0
  224. package/dist/test/ScanStatus.test.d.ts +1 -0
  225. package/dist/test/ScanStatus.test.js +75 -0
  226. package/dist/test/ScanStatus.test.js.map +1 -0
  227. package/dist/test/WalkupScanDestination.test.d.ts +1 -0
  228. package/dist/test/WalkupScanDestination.test.js +80 -0
  229. package/dist/test/WalkupScanDestination.test.js.map +1 -0
  230. package/dist/test/WalkupScanDestinations.test.d.ts +1 -0
  231. package/dist/test/WalkupScanDestinations.test.js +68 -0
  232. package/dist/test/WalkupScanDestinations.test.js.map +1 -0
  233. package/dist/test/WalkupScanManifest.test.d.ts +1 -0
  234. package/dist/test/WalkupScanManifest.test.js +46 -0
  235. package/dist/test/WalkupScanManifest.test.js.map +1 -0
  236. package/dist/test/WalkupScanToCompCaps.test.d.ts +1 -0
  237. package/dist/test/WalkupScanToCompCaps.test.js +56 -0
  238. package/dist/test/WalkupScanToCompCaps.test.js.map +1 -0
  239. package/dist/test/WalkupScanToCompDestination.test.d.ts +1 -0
  240. package/dist/test/WalkupScanToCompDestination.test.js +58 -0
  241. package/dist/test/WalkupScanToCompDestination.test.js.map +1 -0
  242. package/dist/test/WalkupScanToCompDestinations.test.d.ts +1 -0
  243. package/dist/test/WalkupScanToCompDestinations.test.js +58 -0
  244. package/dist/test/WalkupScanToCompDestinations.test.js.map +1 -0
  245. package/dist/test/WalkupScanToCompEvent.test.d.ts +1 -0
  246. package/dist/test/WalkupScanToCompEvent.test.js +46 -0
  247. package/dist/test/WalkupScanToCompEvent.test.js.map +1 -0
  248. package/dist/test/WalkupScanToCompManifest.test.d.ts +1 -0
  249. package/dist/test/WalkupScanToCompManifest.test.js +46 -0
  250. package/dist/test/WalkupScanToCompManifest.test.js.map +1 -0
  251. package/dist/test/clean.d.ts +1 -0
  252. package/dist/test/clean.js +21 -0
  253. package/dist/test/clean.js.map +1 -0
  254. package/package.json +27 -18
  255. package/src/Destination.ts +1 -1
  256. package/src/DeviceCapabilities.ts +4 -0
  257. package/src/DiscoveryTree.ts +56 -0
  258. package/src/Event.ts +17 -7
  259. package/src/EventTable.ts +20 -0
  260. package/src/HPApi.ts +245 -103
  261. package/src/Job.ts +51 -29
  262. package/src/JpegUtil.ts +8 -4
  263. package/src/KnownShortcut.ts +6 -0
  264. package/src/PathHelper.ts +47 -13
  265. package/src/ScanCaps.ts +19 -0
  266. package/src/ScanContent.ts +4 -1
  267. package/src/ScanJobManifest.ts +55 -0
  268. package/src/ScanJobSettings.ts +18 -3
  269. package/src/ScanStatus.ts +9 -0
  270. package/src/WalkupScanDestination.ts +42 -18
  271. package/src/WalkupScanDestinations.ts +12 -0
  272. package/src/WalkupScanManifest.ts +59 -0
  273. package/src/WalkupScanToCompCaps.ts +36 -0
  274. package/src/WalkupScanToCompDestination.ts +38 -24
  275. package/src/WalkupScanToCompDestinations.ts +12 -0
  276. package/src/WalkupScanToCompEvent.ts +15 -3
  277. package/src/WalkupScanToCompManifest.ts +59 -0
  278. package/src/delay.ts +5 -0
  279. package/src/index.ts +267 -465
  280. package/src/listening.ts +145 -0
  281. package/src/readDeviceCapabilities.ts +46 -0
  282. package/src/scanProcessing.ts +535 -0
  283. package/tsconfig.json +1 -1
package/src/index.ts CHANGED
@@ -4,498 +4,147 @@
4
4
  "use strict";
5
5
 
6
6
  import os from "os";
7
- import fs from "fs/promises";
8
- import { Command } from "commander";
7
+ import { Command, Option, OptionValues, program } from "commander";
9
8
  import Bonjour from "bonjour";
10
-
11
- import Destination from "./Destination";
12
- import ScanJobSettings from "./ScanJobSettings";
13
- import Event from "./Event";
9
+ import config from "config";
14
10
  import HPApi from "./HPApi";
15
- import Job from "./Job";
16
- import WalkupScanDestination from "./WalkupScanDestination";
17
- import WalkupScanToCompDestination from "./WalkupScanToCompDestination";
18
- import JpegUtil from "./JpegUtil";
19
11
  import PathHelper from "./PathHelper";
20
- import { createPdfFrom, ScanContent, ScanPage } from "./ScanContent";
21
-
22
- const program = new Command();
23
-
24
- function delay(t: number): Promise<void> {
25
- return new Promise(function (resolve) {
26
- setTimeout(resolve, t);
27
- });
28
- }
29
-
30
- async function waitForScanEvent(
31
- resourceURI: string,
32
- afterEtag: string | null = null
33
- ): Promise<Event> {
34
- console.log("Start listening for new ScanEvent");
35
-
36
- let eventTable = await HPApi.getEvents(afterEtag ?? "");
37
- let acceptedScanEvent = null;
38
- let currentEtag = eventTable.etag;
39
- while (acceptedScanEvent == null) {
40
- eventTable = await HPApi.getEvents(currentEtag, 1200);
41
- currentEtag = eventTable.etag;
42
-
43
- acceptedScanEvent = eventTable.eventTable.events.find(
44
- (ev) =>
45
- ev.isScanEvent &&
46
- ev.destinationURI &&
47
- ev.destinationURI.indexOf(resourceURI) >= 0
48
- );
49
- }
50
- return acceptedScanEvent;
51
- }
52
-
53
- async function waitPrinterUntilItIsReadyToUploadOrCompleted(
54
- jobUrl: string
55
- ): Promise<Job> {
56
- let job = null;
57
- let isReadyToUpload = false;
58
- do {
59
- job = await HPApi.getJob(jobUrl);
60
- if (job.jobState === "Canceled") {
61
- return job;
62
- } else if (
63
- job.pageState === "ReadyToUpload" ||
64
- job.jobState === "Completed"
65
- ) {
66
- isReadyToUpload = true;
67
- } else if (job.jobState == "Processing") {
68
- isReadyToUpload = false;
69
- } else {
70
- console.log(`Unknown jobState: ${job.jobState}`);
71
- }
72
- await delay(300);
73
- } while (!isReadyToUpload);
74
- return job;
75
- }
76
-
77
- async function register(): Promise<string> {
78
- let destination;
79
- const hostname = os.hostname();
80
- const toComp = await HPApi.getWalkupScanToCompCaps();
81
-
82
- if (toComp) {
83
- const walkupScanDestinations =
84
- await HPApi.getWalkupScanToCompDestinations();
85
- const destinations = walkupScanDestinations.destinations;
86
-
87
- console.log(
88
- "Host destinations fetched:",
89
- destinations.map((d) => d.name).join(", ")
90
- );
91
-
92
- destination = destinations.find((x) => x.name === hostname);
93
- } else {
94
- const walkupScanDestinations = await HPApi.getWalkupScanDestinations();
95
- const destinations = walkupScanDestinations.destinations;
96
-
97
- console.log(
98
- "Host destinations fetched:",
99
- destinations.map((d) => d.name).join(", ")
100
- );
101
-
102
- destination = destinations.find((x) => x.name === hostname);
103
- }
104
-
105
- let resourceURI;
106
- if (destination) {
107
- console.log(
108
- `Re-using existing destination: ${hostname} - ${destination.resourceURI}`
109
- );
110
- resourceURI = destination.resourceURI;
111
- } else {
112
- resourceURI = await HPApi.registerDestination(
113
- new Destination(hostname, hostname, toComp),
114
- toComp
115
- );
116
- console.log(`New Destination registered: ${hostname} - ${resourceURI}`);
117
- }
118
- return resourceURI;
119
- }
120
-
121
- async function TryGetDestination(event: Event) {
122
- //this code can in some cases be executed before the user actually chooses between Document or Photo
123
- //so lets fetch the contentType (Document or Photo) until we get a value
124
- let destination: WalkupScanDestination | WalkupScanToCompDestination | null =
125
- null;
126
-
127
- for (let i = 0; i < 20; i++) {
128
- const destinationURI = event.destinationURI;
129
- if (destinationURI) {
130
- destination = await HPApi.getDestination(destinationURI);
131
-
132
- const shortcut = destination.shortcut;
133
- if (shortcut !== "") {
134
- return destination;
135
- }
136
- } else {
137
- console.log(`No destination URI found`);
138
- }
139
-
140
- console.log(`No shortcut yet available, attempt: ${i + 1}/20`);
141
- await new Promise((resolve) => setTimeout(resolve, 1000)); //wait 1s
142
- }
143
-
144
- console.log("Failing to detect destination shortcut");
145
- console.log(JSON.stringify(destination));
146
- return null;
147
- }
148
-
149
- async function fixJpegSize(filePath: string): Promise<number | null> {
150
- const buffer: Buffer = await fs.readFile(filePath);
151
-
152
- let height = JpegUtil.fixSizeWithDNL(buffer);
153
- if (height != null) {
154
- // rewrite the fixed file
155
- await fs.writeFile(filePath, buffer);
156
- return height;
157
- }
158
- return null;
159
- }
160
-
161
- function createScanPage(
162
- job: Job,
163
- currentPageNumber: number,
164
- filePath: string,
165
- sizeFixed: number | null
166
- ): ScanPage {
167
- let height = sizeFixed ?? job.imageHeight;
168
- return {
169
- path: filePath,
170
- pageNumber: currentPageNumber,
171
- width: job.imageWidth,
172
- height,
173
- xResolution: job.xResolution,
174
- yResolution: job.yResolution,
175
- };
176
- }
177
-
178
- async function handleProcessingState(
179
- job: Job,
180
- inputSource: "Adf" | "Platen",
181
- folder: string,
182
- scanCount: number,
183
- currentPageNumber: number
184
- ): Promise<ScanPage | null> {
185
- if (
186
- job.pageState == "ReadyToUpload" &&
187
- job.binaryURL != null &&
188
- job.currentPageNumber != null
189
- ) {
190
- console.log(
191
- `Ready to download page job page ${job.currentPageNumber} at:`,
192
- job.binaryURL
193
- );
194
-
195
- const destinationFilePath = PathHelper.getFileForPage(
196
- folder,
197
- scanCount,
198
- currentPageNumber,
199
- program.opts().pattern,
200
- "jpg"
201
- );
202
- const filePath = await HPApi.downloadPage(
203
- job.binaryURL,
204
- destinationFilePath
205
- );
206
- console.log("Page downloaded to:", filePath);
207
-
208
- let sizeFixed: null | number = null;
209
- if (inputSource == "Adf") {
210
- sizeFixed = await fixJpegSize(filePath);
211
- if (sizeFixed == null) {
212
- console.log(
213
- `File size has not been fixed, DNF may not have been found and approximate height is: ${job.imageHeight}`
214
- );
215
- }
216
- }
217
- return createScanPage(job, currentPageNumber, filePath, sizeFixed);
218
- } else {
219
- console.log(`Unknown pageState: ${job.pageState}`);
220
- await delay(200);
221
- return null;
222
- }
223
- }
224
-
225
- async function waitScanRequest(compEventURI: string): Promise<boolean> {
226
- const waitMax = 50;
227
- for (let i = 0; i < waitMax; i++) {
228
- let walkupScanToCompEvent = await HPApi.getWalkupScanToCompEvent(
229
- compEventURI
230
- );
231
- let message = walkupScanToCompEvent.eventType;
232
- if (message === "HostSelected") {
233
- // this ok to wait
234
- } else if (message === "ScanRequested") {
235
- break;
236
- } else if (message === "ScanNewPageRequested") {
237
- break;
238
- } else if (message === "ScanPagesComplete") {
239
- console.log("no more page to scan, scan is finished");
240
- return false;
241
- } else {
242
- console.log(`Unknown eventType: ${message}`);
243
- return false;
244
- }
12
+ import { delay } from "./delay";
13
+ import { readDeviceCapabilities } from "./readDeviceCapabilities";
14
+ import { clearRegistrations, RegistrationConfig, waitScanEvent } from "./listening";
15
+ import { AdfAutoScanConfig, DirectoryConfig, saveScan, ScanConfig, scanFromAdf, waitAdfLoaded } from "./scanProcessing";
245
16
 
246
- console.log(`Waiting user input: ${i + 1}/${waitMax}`);
247
- await new Promise((resolve) => setTimeout(resolve, 1000)); //wait 1s
248
- }
249
- return true;
250
- }
17
+ let iteration = 0;
251
18
 
252
- async function executeScanJob(
253
- scanJobSettings: ScanJobSettings,
254
- inputSource: "Adf" | "Platen",
255
- folder: string,
256
- scanCount: number,
257
- scanJobContent: ScanContent
19
+ async function listenCmd(
20
+ registrationConfig: RegistrationConfig,
21
+ scanConfig: ScanConfig,
22
+ deviceUpPollingInterval: number
258
23
  ) {
259
- const jobUrl = await HPApi.postJob(scanJobSettings);
24
+ // first make sure the device is reachable
25
+ await HPApi.waitDeviceUp(deviceUpPollingInterval);
26
+ let deviceUp = true;
260
27
 
261
- console.log("New job created:", jobUrl);
28
+ const folder = await PathHelper.getOutputFolder(
29
+ scanConfig.directoryConfig.directory
30
+ );
31
+ console.log(`Target folder: ${folder}`);
262
32
 
263
- let job = await HPApi.getJob(jobUrl);
264
- while (job.jobState !== "Completed") {
265
- job = await waitPrinterUntilItIsReadyToUploadOrCompleted(jobUrl);
33
+ const tempFolder = await PathHelper.getOutputFolder(
34
+ scanConfig.directoryConfig.tempDirectory
35
+ );
36
+ console.log(`Temp folder: ${tempFolder}`);
266
37
 
267
- if (job.jobState == "Completed") {
268
- continue;
269
- }
38
+ const deviceCapabilities = await readDeviceCapabilities();
270
39
 
271
- if (job.jobState === "Processing") {
272
- const page = await handleProcessingState(
273
- job,
274
- inputSource,
40
+ let scanCount = 0;
41
+ let keepActive = true;
42
+ let errorCount = 0;
43
+ while (keepActive) {
44
+ console.log(`Running iteration: ${iteration} - errorCount: ${errorCount}`);
45
+ try {
46
+ const event = await waitScanEvent(deviceCapabilities, registrationConfig);
47
+ scanCount++;
48
+ console.log(`Scan event captured, saving scan #${scanCount}`);
49
+ await saveScan(
50
+ event,
275
51
  folder,
52
+ tempFolder,
276
53
  scanCount,
277
- scanJobContent.elements.length + 1
54
+ deviceCapabilities,
55
+ scanConfig
278
56
  );
279
- if (page != null) {
280
- scanJobContent.elements.push(page);
57
+ } catch (e) {
58
+ console.log(e);
59
+ if (await HPApi.isAlive()) {
60
+ errorCount++;
61
+ } else {
62
+ deviceUp = false;
281
63
  }
282
- } else if (job.jobState === "Canceled") {
283
- console.log("Job cancelled by device");
284
- break;
285
- } else {
286
- console.log(`Unhandled jobState: ${job.jobState}`);
287
- await delay(200);
288
64
  }
289
- }
290
- console.log(
291
- `Job state: ${job.jobState}, totalPages: ${job.totalPageNumber}:`
292
- );
293
- }
294
65
 
295
- async function waitScanNewPageRequest(compEventURI: string): Promise<boolean> {
296
- let startNewScanJob = false;
297
- let wait = true;
298
- while (wait) {
299
- await new Promise((resolve) => setTimeout(resolve, 1000)); //wait 1s
66
+ if (errorCount === 50) {
67
+ keepActive = false;
68
+ }
300
69
 
301
- let walkupScanToCompEvent = await HPApi.getWalkupScanToCompEvent(
302
- compEventURI
303
- );
304
- let message = walkupScanToCompEvent.eventType;
305
-
306
- if (message === "ScanNewPageRequested") {
307
- startNewScanJob = true;
308
- wait = false;
309
- } else if (message === "ScanPagesComplete") {
310
- wait = false;
311
- } else if (message === "ScanRequested") {
312
- // continue waiting
70
+ if (!deviceUp) {
71
+ await HPApi.waitDeviceUp(deviceUpPollingInterval);
313
72
  } else {
314
- wait = false;
315
- console.log(`Unknown eventType: ${message}`);
73
+ await delay(1000);
316
74
  }
317
75
  }
318
- return startNewScanJob;
319
76
  }
320
77
 
321
- async function executeScanJobs(
322
- scanJobSettings: ScanJobSettings,
323
- inputSource: "Adf" | "Platen",
324
- folder: string,
325
- scanCount: number,
326
- scanJobContent: ScanContent,
327
- firstEvent: Event
78
+ async function adfAutoscanCmd(
79
+ adfAutoScanConfig: AdfAutoScanConfig,
80
+ deviceUpPollingInterval: number
328
81
  ) {
329
- await executeScanJob(
330
- scanJobSettings,
331
- inputSource,
332
- folder,
333
- scanCount,
334
- scanJobContent
335
- );
336
- let lastEvent = firstEvent;
337
- if (
338
- lastEvent.compEventURI &&
339
- inputSource !== "Adf" &&
340
- lastEvent.destinationURI
341
- ) {
342
- lastEvent = await waitForScanEvent(
343
- lastEvent.destinationURI,
344
- lastEvent.agingStamp
345
- );
346
- if (!lastEvent.compEventURI) {
347
- return;
348
- }
349
- let startNewScanJob = await waitScanNewPageRequest(lastEvent.compEventURI);
350
- while (startNewScanJob) {
351
- await executeScanJob(
352
- scanJobSettings,
353
- inputSource,
354
- folder,
355
- scanCount,
356
- scanJobContent
357
- );
358
- if (!lastEvent.destinationURI) {
359
- break;
360
- }
361
- lastEvent = await waitForScanEvent(
362
- lastEvent.destinationURI,
363
- lastEvent.agingStamp
364
- );
365
- if (!lastEvent.compEventURI) {
366
- return;
367
- }
368
- startNewScanJob = await waitScanNewPageRequest(lastEvent.compEventURI);
369
- }
370
- }
371
- }
372
-
373
- async function mergeToPdf(folder: string, scanCount: number, scanJobContent: ScanContent) {
374
- const pdfFilePath = PathHelper.getFileForScan(
375
- folder,
376
- scanCount,
377
- program.opts().pattern,
378
- "pdf"
379
- );
380
- await createPdfFrom(scanJobContent, pdfFilePath);
381
- scanJobContent.elements.forEach((e) => fs.unlink(e.path));
382
- return pdfFilePath;
383
- }
82
+ // first make sure the device is reachable
83
+ await HPApi.waitDeviceUp(deviceUpPollingInterval);
84
+ let deviceUp = true;
384
85
 
385
- function displayPdfScan(pdfFilePath: string, scanJobContent: ScanContent) {
386
- console.log(
387
- `The following page(s) have been rendered inside '${pdfFilePath}': `
388
- );
389
- scanJobContent.elements.forEach((e) =>
390
- console.log(
391
- `\t- page ${e.pageNumber.toString().padStart(3, " ")} - ${e.width}x${
392
- e.height
393
- }`
394
- )
395
- );
396
- }
397
-
398
- function displayJpegScan(scanJobContent: ScanContent) {
399
- scanJobContent.elements.forEach((e) =>
400
- console.log(
401
- `\t- page ${e.pageNumber.toString().padStart(3, " ")} - ${e.width}x${
402
- e.height
403
- } - ${e.path}`
404
- )
405
- );
406
- }
407
-
408
- async function saveScan(
409
- event: Event,
410
- folder: string,
411
- scanCount: number
412
- ): Promise<void> {
413
- if (event.compEventURI) {
414
- const proceedToScan = await waitScanRequest(event.compEventURI);
415
- if (!proceedToScan) {
416
- return;
417
- }
418
- }
419
-
420
- const destination = await TryGetDestination(event);
421
- if (!destination) {
422
- console.log("No shortcut selected!");
423
- return;
424
- }
425
- console.log("Selected shortcut: " + destination.shortcut);
426
-
427
- const contentType = destination.getContentType();
428
- const toPdf =
429
- destination.shortcut === "SavePDF" || destination.shortcut === "EmailPDF";
430
-
431
- const scanStatus = await HPApi.getScanStatus();
432
- console.log("Afd is : " + scanStatus.adfState);
433
-
434
- let inputSource = scanStatus.getInputSource();
435
-
436
- let scanJobSettings = new ScanJobSettings(inputSource, contentType);
437
-
438
- let scanJobContent: ScanContent = { elements: [] };
439
-
440
- await executeScanJobs(
441
- scanJobSettings,
442
- inputSource,
443
- folder,
444
- scanCount,
445
- scanJobContent,
446
- event
86
+ const folder = await PathHelper.getOutputFolder(
87
+ adfAutoScanConfig.directoryConfig.directory
447
88
  );
89
+ console.log(`Target folder: ${folder}`);
448
90
 
449
- console.log(
450
- `Scan of page(s) completed totalPages: ${scanJobContent.elements.length}:`
91
+ const tempFolder = await PathHelper.getOutputFolder(
92
+ adfAutoScanConfig.directoryConfig.tempDirectory
451
93
  );
452
-
453
- if (toPdf) {
454
- const pdfFilePath = await mergeToPdf(folder, scanCount, scanJobContent);
455
- displayPdfScan(pdfFilePath, scanJobContent);
456
- } else {
457
- displayJpegScan(scanJobContent);
458
- }
459
- }
460
-
461
- let iteration = 0;
462
- async function init() {
463
- const folder = await PathHelper.getOutputFolder(program.opts().directory);
464
- console.log(`Target folder: ${folder}`);
94
+ console.log(`Temp folder: ${tempFolder}`);
465
95
 
466
96
  let scanCount = 0;
467
-
468
97
  let keepActive = true;
469
98
  let errorCount = 0;
470
99
  while (keepActive) {
471
100
  console.log(`Running iteration: ${iteration} - errorCount: ${errorCount}`);
472
101
  try {
473
- let resourceURI = await register();
474
-
475
- console.log("Waiting scan event for:", resourceURI);
476
- const event = await waitForScanEvent(resourceURI);
102
+ await waitAdfLoaded(
103
+ adfAutoScanConfig.pollingInterval,
104
+ adfAutoScanConfig.startScanDelay
105
+ );
477
106
 
478
107
  scanCount++;
108
+
479
109
  console.log(`Scan event captured, saving scan #${scanCount}`);
480
- await saveScan(event, folder, scanCount);
110
+
111
+ await scanFromAdf(scanCount, folder, tempFolder, adfAutoScanConfig);
481
112
  } catch (e) {
482
- errorCount++;
483
- console.error(e);
484
113
  console.log(e);
114
+ if (await HPApi.isAlive()) {
115
+ errorCount++;
116
+ } else {
117
+ deviceUp = false;
118
+ }
485
119
  }
486
120
 
487
121
  if (errorCount === 50) {
488
122
  keepActive = false;
489
123
  }
490
124
 
491
- await delay(1000);
125
+ if (!deviceUp) {
126
+ await HPApi.waitDeviceUp(deviceUpPollingInterval);
127
+ } else {
128
+ await delay(1000);
129
+ }
492
130
  }
493
131
  }
494
132
 
495
- function findOfficejetIp(): Promise<string> {
133
+ async function clearRegistrationsCmd(cmd: Command) {
134
+ const parentOption = cmd.parent!.opts();
135
+
136
+ const ip = await getDeviceIp(parentOption);
137
+ HPApi.setDeviceIP(ip);
138
+
139
+ const isDebug = getIsDebug(parentOption);
140
+ HPApi.setDebug(isDebug);
141
+ await clearRegistrations();
142
+ }
143
+
144
+ function findOfficejetIp(deviceNamePrefix: string): Promise<string> {
496
145
  return new Promise((resolve) => {
497
146
  const bonjour = Bonjour();
498
- console.log("Searching printer...");
147
+ console.log("Searching device...");
499
148
  let browser = bonjour.find(
500
149
  {
501
150
  type: "http",
@@ -503,7 +152,7 @@ function findOfficejetIp(): Promise<string> {
503
152
  (service) => {
504
153
  console.log(".");
505
154
  if (
506
- service.name.startsWith(program.opts().name) &&
155
+ service.name.startsWith(deviceNamePrefix) &&
507
156
  service.port === 80 &&
508
157
  service.type === "http" &&
509
158
  service.addresses != null
@@ -519,37 +168,190 @@ function findOfficejetIp(): Promise<string> {
519
168
  });
520
169
  }
521
170
 
522
- async function main() {
523
- program.option(
524
- "-ip, --address <ip>",
525
- "IP address of the printer (this overrides -p)"
526
- );
527
- program.option(
528
- "-n, --name <name>",
529
- "Name of the printer for service discovery",
530
- "HP Smart Tank Plus 570 series"
531
- ); //or i.e. 'Deskjet 3520 series'
532
- program.option(
171
+ function getConfig<T>(name: string): T | undefined {
172
+ return config.has(name) ? config.get<T>(name) : undefined;
173
+ }
174
+
175
+ function setupScanParameters(command: Command): Command {
176
+ command.option(
533
177
  "-d, --directory <dir>",
534
- "Directory where scans are saved (defaults to /tmp/scan-to-pc<random>)"
178
+ "Directory where scans are saved (default: /tmp/scan-to-pc<random>)"
535
179
  );
536
- program.option(
180
+ command.option(
181
+ "-t, --temp-directory <dir>",
182
+ "Temp directory used for processing (default: /tmp/scan-to-pc<random>)"
183
+ );
184
+ command.option(
537
185
  "-p, --pattern <pattern>",
538
186
  'Pattern for filename (i.e. "scan"_dd.mm.yyyy_hh:MM:ss, without this its scanPage<number>)'
539
187
  );
540
- program.option("-D, --debug", "Enable debug");
541
- program.parse(process.argv);
188
+ command.option(
189
+ "-r, --resolution <dpi>",
190
+ "Resolution in DPI of the scans (default: 200)"
191
+ );
192
+ return command;
193
+ }
194
+
195
+ function setupParameterOpts(command: Command): Command {
196
+ command.option(
197
+ "-ip, --address <ip>",
198
+ "IP address of the device (this overrides -p)"
199
+ );
200
+ command.option(
201
+ "--device-up-polling-interval <deviceUpPollingInterval>",
202
+ "Device up polling interval in milliseconds",
203
+ parseFloat
204
+ );
205
+ command.option(
206
+ "-n, --name <name>",
207
+ "Name of the device for service discovery"
208
+ ); // i.e. 'Deskjet 3520 series'
542
209
 
543
- let ip = program.opts().address || "192.168.1.53";
210
+ command.option("-D, --debug", "Enable debug");
211
+ return command;
212
+ }
213
+
214
+ async function getDeviceIp(options: OptionValues) {
215
+ let ip = options.address || getConfig("ip");
544
216
  if (!ip) {
545
- ip = await findOfficejetIp();
217
+ const name = options.name || getConfig("name");
218
+ ip = await findOfficejetIp(name || "HP Smart Tank Plus 570 series");
546
219
  }
220
+ console.log(`Using device ip: ${ip}`);
221
+ return ip;
222
+ }
223
+
224
+ function getIsDebug(options: OptionValues) {
225
+ const debug =
226
+ options.debug != null ? true : getConfig<boolean>("debug") || false;
227
+
228
+ if (debug) {
229
+ console.log(`IsDebug: ${debug}`);
230
+ }
231
+ return debug;
232
+ }
233
+
234
+ function getScanConfiguration(parentOption: OptionValues) {
235
+ const directoryConfig: DirectoryConfig = {
236
+ directory: parentOption.directory || getConfig("directory"),
237
+ tempDirectory: parentOption.tempDirectory || getConfig("tempDirectory"),
238
+ filePattern: parentOption.pattern || getConfig("pattern"),
239
+ };
240
+
241
+ const scanConfig: ScanConfig = {
242
+ resolution: parseInt(
243
+ parentOption.resolution || getConfig("resolution") || 200,
244
+ 10
245
+ ),
246
+ directoryConfig,
247
+ };
248
+ return scanConfig;
249
+ }
250
+
251
+ function getDeviceUpPollingInterval(parentOption: OptionValues) {
252
+ return (
253
+ parentOption.deviceUpPollingInterval ||
254
+ getConfig("deviceUpPollingInterval") ||
255
+ 1000
256
+ );
257
+ }
258
+
259
+
260
+ async function main() {
261
+ setupParameterOpts(program);
262
+ const cmdListen = program.createCommand("listen");
263
+ setupScanParameters(cmdListen)
264
+ .description("Listen the device for new scan job to save to this target")
265
+ .option(
266
+ "-l, --label <label>",
267
+ "The label to display on the device (the default is the hostname)"
268
+ )
269
+ .action(async (options, cmd) => {
270
+ const parentOption = cmd.parent.opts();
547
271
 
548
- const debug = program.opts().debug != null;
272
+ const ip = await getDeviceIp(parentOption);
273
+ HPApi.setDeviceIP(ip);
549
274
 
550
- HPApi.setDebug(debug);
551
- HPApi.setPrinterIP(ip);
552
- await init();
275
+ const isDebug = getIsDebug(parentOption);
276
+ HPApi.setDebug(isDebug);
277
+
278
+ const registrationConfig: RegistrationConfig = {
279
+ label: options.label || getConfig("label") || os.hostname(),
280
+ };
281
+
282
+ const deviceUpPollingInterval = getDeviceUpPollingInterval(parentOption);
283
+
284
+ const scanConfig = getScanConfiguration(options);
285
+
286
+ await listenCmd(registrationConfig, scanConfig, deviceUpPollingInterval);
287
+ });
288
+ program.addCommand(cmdListen, { isDefault: true });
289
+
290
+ const cmdAdfAutoscan = program.createCommand("adf-autoscan");
291
+ setupScanParameters(cmdAdfAutoscan)
292
+ .addOption(
293
+ new Option("--duplex", "If specified, the scan will be in duplex")
294
+ )
295
+ .addOption(
296
+ new Option(
297
+ "--pdf",
298
+ "If specified, the scan result will be a pdf document, the default is multiple jpeg files"
299
+ )
300
+ )
301
+ .addOption(
302
+ new Option(
303
+ "--pollingInterval <pollingInterval>",
304
+ "Time interval in millisecond between each lookup for content in the automatic document feeder",
305
+ )
306
+ )
307
+ .description(
308
+ "Automatically trigger a new scan job to this target once paper is detected in the automatic document feeder (adf)"
309
+ )
310
+ .addOption(
311
+ new Option(
312
+ "--start-scan-delay <startScanDelay>",
313
+ "Once document are detected to be in the adf, this specify the wait delay in millisecond before triggering the scan",
314
+ )
315
+ )
316
+ .description(
317
+ "Automatically trigger a new scan job to this target once paper is detected in the automatic document feeder (adf)"
318
+ )
319
+ .action(async (options, cmd) => {
320
+ const parentOption = cmd.parent.opts();
321
+
322
+ const ip = await getDeviceIp(parentOption);
323
+ HPApi.setDeviceIP(ip);
324
+
325
+ const isDebug = getIsDebug(parentOption);
326
+ HPApi.setDebug(isDebug);
327
+
328
+ const deviceUpPollingInterval = getDeviceUpPollingInterval(parentOption);
329
+
330
+ const scanConfig = getScanConfiguration(options);
331
+
332
+ const adfScanConfig: AdfAutoScanConfig = {
333
+ ...scanConfig,
334
+ isDuplex: options.isDuplex || getConfig("autoscan_duplex") || false,
335
+ generatePdf: options.pdf || getConfig("autoscan_pdf") || false,
336
+ pollingInterval:
337
+ options.pollingInterval || getConfig("autoscan_pollingInterval") || 1000,
338
+ startScanDelay:
339
+ options.startScanDelay || getConfig("autoscan_startScanDelay") || 5000,
340
+ };
341
+
342
+ await adfAutoscanCmd(adfScanConfig, deviceUpPollingInterval);
343
+ });
344
+ program.addCommand(cmdAdfAutoscan);
345
+
346
+ const cmdClearRegistrations = program.createCommand("clear-registrations");
347
+ cmdClearRegistrations
348
+ .description("Clear the list or registered target on the device")
349
+ .action(async (options, cmd) => {
350
+ await clearRegistrationsCmd(cmd);
351
+ });
352
+ program.addCommand(cmdClearRegistrations);
353
+
354
+ await program.parseAsync(process.argv);
553
355
  }
554
356
 
555
- main();
357
+ main().catch((err) => console.log(err));