@xyo-network/image-thumbnail-plugin 2.75.0 → 2.75.3

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 (94) hide show
  1. package/dist/docs.json +50260 -0
  2. package/dist/node/Diviner/Config.d.cts +11 -0
  3. package/dist/node/Diviner/Config.d.cts.map +1 -0
  4. package/dist/node/Diviner/Config.js +3 -1
  5. package/dist/node/Diviner/Config.js.map +1 -1
  6. package/dist/node/Diviner/Config.mjs +2 -1
  7. package/dist/node/Diviner/Config.mjs.map +1 -1
  8. package/dist/node/Diviner/Diviner.d.cts +30 -0
  9. package/dist/node/Diviner/Diviner.d.cts.map +1 -0
  10. package/dist/node/Diviner/Diviner.js +19 -11
  11. package/dist/node/Diviner/Diviner.js.map +1 -1
  12. package/dist/node/Diviner/Diviner.mjs +17 -10
  13. package/dist/node/Diviner/Diviner.mjs.map +1 -1
  14. package/dist/node/Diviner/Params.d.cts +5 -0
  15. package/dist/node/Diviner/Params.d.cts.map +1 -0
  16. package/dist/node/Diviner/Params.js +2 -0
  17. package/dist/node/Diviner/Params.js.map +1 -1
  18. package/dist/node/Diviner/index.d.cts +4 -0
  19. package/dist/node/Diviner/index.d.cts.map +1 -0
  20. package/dist/node/Diviner/index.js +189 -7
  21. package/dist/node/Diviner/index.js.map +1 -1
  22. package/dist/node/Diviner/index.mjs +180 -3
  23. package/dist/node/Diviner/index.mjs.map +1 -1
  24. package/dist/node/Plugin.d.cts +116 -0
  25. package/dist/node/Plugin.d.cts.map +1 -0
  26. package/dist/node/Plugin.js +517 -7
  27. package/dist/node/Plugin.js.map +1 -1
  28. package/dist/node/Plugin.mjs +504 -5
  29. package/dist/node/Plugin.mjs.map +1 -1
  30. package/dist/node/Witness/Config.d.cts +16 -0
  31. package/dist/node/Witness/Config.d.cts.map +1 -0
  32. package/dist/node/Witness/Config.js +3 -1
  33. package/dist/node/Witness/Config.js.map +1 -1
  34. package/dist/node/Witness/Config.mjs +2 -1
  35. package/dist/node/Witness/Config.mjs.map +1 -1
  36. package/dist/node/Witness/Params.d.cts +7 -0
  37. package/dist/node/Witness/Params.d.cts.map +1 -0
  38. package/dist/node/Witness/Params.js +2 -0
  39. package/dist/node/Witness/Params.js.map +1 -1
  40. package/dist/node/Witness/Witness.d.cts +66 -0
  41. package/dist/node/Witness/Witness.d.cts.map +1 -0
  42. package/dist/node/Witness/Witness.js +78 -29
  43. package/dist/node/Witness/Witness.js.map +1 -1
  44. package/dist/node/Witness/Witness.mjs +70 -22
  45. package/dist/node/Witness/Witness.mjs.map +1 -1
  46. package/dist/node/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.d.cts +8 -0
  47. package/dist/node/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.d.cts.map +1 -0
  48. package/dist/node/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.js +5 -3
  49. package/dist/node/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.js.map +1 -1
  50. package/dist/node/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.mjs +4 -3
  51. package/dist/node/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.mjs.map +1 -1
  52. package/dist/node/Witness/ffmpeg/fluent/index.d.cts +2 -0
  53. package/dist/node/Witness/ffmpeg/fluent/index.d.cts.map +1 -0
  54. package/dist/node/Witness/ffmpeg/fluent/index.js +59 -3
  55. package/dist/node/Witness/ffmpeg/fluent/index.js.map +1 -1
  56. package/dist/node/Witness/ffmpeg/fluent/index.mjs +41 -1
  57. package/dist/node/Witness/ffmpeg/fluent/index.mjs.map +1 -1
  58. package/dist/node/Witness/ffmpeg/index.d.cts +3 -0
  59. package/dist/node/Witness/ffmpeg/index.d.cts.map +1 -0
  60. package/dist/node/Witness/ffmpeg/index.js +89 -5
  61. package/dist/node/Witness/ffmpeg/index.js.map +1 -1
  62. package/dist/node/Witness/ffmpeg/index.mjs +69 -2
  63. package/dist/node/Witness/ffmpeg/index.mjs.map +1 -1
  64. package/dist/node/Witness/ffmpeg/spawn/executeFfmpeg.d.cts +9 -0
  65. package/dist/node/Witness/ffmpeg/spawn/executeFfmpeg.d.cts.map +1 -0
  66. package/dist/node/Witness/ffmpeg/spawn/executeFfmpeg.js +3 -1
  67. package/dist/node/Witness/ffmpeg/spawn/executeFfmpeg.js.map +1 -1
  68. package/dist/node/Witness/ffmpeg/spawn/executeFfmpeg.mjs +2 -1
  69. package/dist/node/Witness/ffmpeg/spawn/executeFfmpeg.mjs.map +1 -1
  70. package/dist/node/Witness/ffmpeg/spawn/getVideoFrameAsImage.d.cts +8 -0
  71. package/dist/node/Witness/ffmpeg/spawn/getVideoFrameAsImage.d.cts.map +1 -0
  72. package/dist/node/Witness/ffmpeg/spawn/getVideoFrameAsImage.js +26 -3
  73. package/dist/node/Witness/ffmpeg/spawn/getVideoFrameAsImage.js.map +1 -1
  74. package/dist/node/Witness/ffmpeg/spawn/getVideoFrameAsImage.mjs +22 -2
  75. package/dist/node/Witness/ffmpeg/spawn/getVideoFrameAsImage.mjs.map +1 -1
  76. package/dist/node/Witness/ffmpeg/spawn/index.d.cts +3 -0
  77. package/dist/node/Witness/ffmpeg/spawn/index.d.cts.map +1 -0
  78. package/dist/node/Witness/ffmpeg/spawn/index.js +38 -5
  79. package/dist/node/Witness/ffmpeg/spawn/index.js.map +1 -1
  80. package/dist/node/Witness/ffmpeg/spawn/index.mjs +29 -2
  81. package/dist/node/Witness/ffmpeg/spawn/index.mjs.map +1 -1
  82. package/dist/node/Witness/index.d.cts +4 -0
  83. package/dist/node/Witness/index.d.cts.map +1 -0
  84. package/dist/node/Witness/index.js +343 -7
  85. package/dist/node/Witness/index.js.map +1 -1
  86. package/dist/node/Witness/index.mjs +324 -3
  87. package/dist/node/Witness/index.mjs.map +1 -1
  88. package/dist/node/index.d.cts +6 -0
  89. package/dist/node/index.d.cts.map +1 -0
  90. package/dist/node/index.js +542 -8
  91. package/dist/node/index.js.map +1 -1
  92. package/dist/node/index.mjs +523 -3
  93. package/dist/node/index.mjs.map +1 -1
  94. package/package.json +19 -19
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Params.d.ts","sourceRoot":"","sources":["../../../src/Witness/Params.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AAEtD,MAAM,MAAM,2BAA2B,GAAG,aAAa,CACrD,eAAe,CAAC,2BAA2B,CAAC,EAC5C;IACE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB,CACF,CAAA"}
@@ -12,6 +12,8 @@ var __copyProps = (to, from, except, desc) => {
12
12
  return to;
13
13
  };
14
14
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/Witness/Params.ts
15
17
  var Params_exports = {};
16
18
  module.exports = __toCommonJS(Params_exports);
17
19
  //# sourceMappingURL=Params.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/Witness/Params.ts"],"sourcesContent":["import { AnyConfigSchema } from '@xyo-network/module'\nimport { WitnessParams } from '@xyo-network/witness'\n\nimport { ImageThumbnailWitnessConfig } from './Config'\n\nexport type ImageThumbnailWitnessParams = WitnessParams<\n AnyConfigSchema<ImageThumbnailWitnessConfig>,\n {\n loaders?: string[]\n }\n>\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../src/Witness/Params.ts"],"sourcesContent":["import { AnyConfigSchema } from '@xyo-network/module'\nimport { WitnessParams } from '@xyo-network/witness'\n\nimport { ImageThumbnailWitnessConfig } from './Config'\n\nexport type ImageThumbnailWitnessParams = WitnessParams<\n AnyConfigSchema<ImageThumbnailWitnessConfig>,\n {\n loaders?: string[]\n }\n>\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,66 @@
1
+ import { ImageThumbnail } from '@xyo-network/image-thumbnail-payload-plugin';
2
+ import { UrlPayload } from '@xyo-network/url-payload-plugin';
3
+ import { AbstractWitness } from '@xyo-network/witness';
4
+ import { LRUCache } from 'lru-cache';
5
+ import { ImageThumbnailEncoding } from './Config';
6
+ import { ImageThumbnailWitnessParams } from './Params';
7
+ export interface ImageThumbnailWitnessError extends Error {
8
+ name: 'ImageThumbnailWitnessError';
9
+ url: string;
10
+ }
11
+ export interface DnsError extends Error {
12
+ code: string;
13
+ }
14
+ export declare class ImageThumbnailWitness<TParams extends ImageThumbnailWitnessParams = ImageThumbnailWitnessParams> extends AbstractWitness<TParams> {
15
+ static configSchemas: "network.xyo.image.thumbnail.witness.config"[];
16
+ private _cache?;
17
+ private _semaphore;
18
+ get cache(): LRUCache<string, import("@xyo-network/payload-model").SchemaFields & import("@xyo-network/payload-model").PayloadFields & {
19
+ http?: {
20
+ dnsError?: string | undefined;
21
+ ipAddress?: string | undefined;
22
+ status?: number | undefined;
23
+ } | undefined;
24
+ mime?: {
25
+ detected?: {
26
+ ext?: string | undefined;
27
+ mime?: string | undefined;
28
+ } | undefined;
29
+ invalid?: boolean | undefined;
30
+ returned?: string | undefined;
31
+ type?: string | undefined;
32
+ } | undefined;
33
+ sourceHash?: string | undefined;
34
+ sourceUrl: string;
35
+ url?: string | undefined;
36
+ } & {
37
+ schema: "network.xyo.image.thumbnail";
38
+ }, unknown>;
39
+ get encoding(): ImageThumbnailEncoding;
40
+ get height(): number;
41
+ get ipfGateway(): string;
42
+ get maxAsyncProcesses(): number;
43
+ get maxCacheBytes(): number;
44
+ get maxCacheEntries(): number;
45
+ get quality(): number;
46
+ get width(): number;
47
+ private static binaryToSha256;
48
+ private static bufferFromDataUrl;
49
+ /**
50
+ * Returns the equivalent IPFS gateway URL for the supplied URL.
51
+ * @param urlToCheck The URL to check
52
+ * @returns If the supplied URL is an IPFS URL, it converts the URL to the
53
+ * equivalent IPFS gateway URL. Otherwise, returns the original URL.
54
+ */
55
+ checkIpfsUrl(urlToCheck: string): string;
56
+ protected observeHandler(payloads?: UrlPayload[]): Promise<ImageThumbnail[]>;
57
+ private createThumbnailDataUrl;
58
+ /**
59
+ * Creates an image thumbnail from a video.
60
+ * @param videoBuffer The input video buffer.
61
+ * @returns An buffer containing an image thumbnail for the video.
62
+ */
63
+ private createThumbnailFromVideo;
64
+ private fromHttp;
65
+ }
66
+ //# sourceMappingURL=Witness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Witness.d.ts","sourceRoot":"","sources":["../../../src/Witness/Witness.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAwB,MAAM,6CAA6C,CAAA;AAClG,OAAO,EAAE,UAAU,EAAa,MAAM,iCAAiC,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAMtD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAIpC,OAAO,EAAE,sBAAsB,EAAqC,MAAM,UAAU,CAAA;AAEpF,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AAStD,MAAM,WAAW,0BAA2B,SAAQ,KAAK;IACvD,IAAI,EAAE,4BAA4B,CAAA;IAClC,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,QAAS,SAAQ,KAAK;IACrC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,iDAAsC;IAEnE,OAAO,CAAC,MAAM,CAAC,CAAkC;IACjD,OAAO,CAAC,UAAU,CAAwC;IAE1D,IAAI,KAAK;;;;;;;;;;;;;;;;;;;;gBAUR;IAED,IAAI,QAAQ,2BAEX;IAED,IAAI,MAAM,WAET;IAED,IAAI,UAAU,WAEb;IAED,IAAI,iBAAiB,WAEpB;IAED,IAAI,aAAa,WAEhB;IAED,IAAI,eAAe,WAElB;IAED,IAAI,OAAO,WAEV;IAED,IAAI,KAAK,WAER;mBAEoB,cAAc;IAanC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAgBhC;;;;;OAKG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM;cAiBN,cAAc,CAAC,QAAQ,GAAE,UAAU,EAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YAuCjF,sBAAsB;IAiBpC;;;;OAIG;YACW,wBAAwB;YAKxB,QAAQ;CA6HvB"}
@@ -26,17 +26,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/Witness/Witness.ts
29
31
  var Witness_exports = {};
30
32
  __export(Witness_exports, {
31
33
  ImageThumbnailWitness: () => ImageThumbnailWitness
32
34
  });
33
35
  module.exports = __toCommonJS(Witness_exports);
34
- var import_node_dns = require("node:dns");
36
+ var import_node_dns = require("dns");
35
37
  var import_lodash = require("@xylabs/lodash");
36
38
  var import_url = require("@xylabs/url");
37
39
  var import_axios = require("@xyo-network/axios");
38
- var import_core = require("@xyo-network/core");
39
- var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
40
+ var import_core2 = require("@xyo-network/core");
41
+ var import_image_thumbnail_payload_plugin2 = require("@xyo-network/image-thumbnail-payload-plugin");
40
42
  var import_url_payload_plugin = require("@xyo-network/url-payload-plugin");
41
43
  var import_witness = require("@xyo-network/witness");
42
44
  var import_async_mutex = require("async-mutex");
@@ -47,11 +49,54 @@ var import_hash_wasm = require("hash-wasm");
47
49
  var import_lru_cache = require("lru-cache");
48
50
  var import_sha = __toESM(require("sha.js"));
49
51
  var import_url_parse = __toESM(require("url-parse"));
50
- var import_Config = require("./Config");
51
- var import_ffmpeg = require("./ffmpeg");
52
- const gm = import_gm.default.subClass({ imageMagick: "7+" });
53
- class ImageThumbnailWitness extends import_witness.AbstractWitness {
54
- static configSchemas = [import_Config.ImageThumbnailWitnessConfigSchema];
52
+
53
+ // src/Witness/Config.ts
54
+ var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
55
+ var ImageThumbnailWitnessConfigSchema = `${import_image_thumbnail_payload_plugin.ImageThumbnailSchema}.witness.config`;
56
+
57
+ // src/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.ts
58
+ var import_core = require("@xyo-network/core");
59
+ var import_fluent_ffmpeg = __toESM(require("fluent-ffmpeg"));
60
+ var import_promises = require("fs/promises");
61
+ var import_os = require("os");
62
+ var import_stream = require("stream");
63
+ var FfmpegOutputStream = class extends import_stream.Writable {
64
+ chunks = [];
65
+ constructor(options) {
66
+ super(options);
67
+ }
68
+ _write(chunk, _encoding, callback) {
69
+ this.chunks.push(chunk);
70
+ callback();
71
+ }
72
+ /**
73
+ * Collects the output from ffmpeg into a buffer.
74
+ * @returns A buffer containing the concatenated
75
+ * output from ffmpeg.
76
+ */
77
+ toBuffer = () => Buffer.concat(this.chunks);
78
+ };
79
+ var getVideoFrameAsImageFluent = async (videoBuffer) => {
80
+ const tmpFile = `/${(0, import_os.tmpdir)()}/${(0, import_core.uuid)()}`;
81
+ try {
82
+ await (0, import_promises.writeFile)(tmpFile, videoBuffer, { encoding: "binary" });
83
+ const imageBuffer = await new Promise((resolve, reject) => {
84
+ const ffmpegOutput = new FfmpegOutputStream();
85
+ (0, import_fluent_ffmpeg.default)().on("error", (err) => reject(err.message)).on("end", () => resolve(ffmpegOutput.toBuffer())).input(tmpFile).takeFrames(1).withNoAudio().outputOptions("-f image2pipe").videoCodec("png").pipe(ffmpegOutput);
86
+ });
87
+ return imageBuffer;
88
+ } finally {
89
+ try {
90
+ await (0, import_promises.unlink)(tmpFile);
91
+ } catch {
92
+ }
93
+ }
94
+ };
95
+
96
+ // src/Witness/Witness.ts
97
+ var gm = import_gm.default.subClass({ imageMagick: "7+" });
98
+ var ImageThumbnailWitness = class _ImageThumbnailWitness extends import_witness.AbstractWitness {
99
+ static configSchemas = [ImageThumbnailWitnessConfigSchema];
55
100
  _cache;
56
101
  _semaphore = new import_async_mutex.Semaphore(this.maxAsyncProcesses);
57
102
  get cache() {
@@ -59,7 +104,10 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
59
104
  max: this.maxCacheEntries,
60
105
  maxSize: this.maxCacheBytes,
61
106
  //just returning the size of the data
62
- sizeCalculation: (value) => value.url?.length ?? 1
107
+ sizeCalculation: (value) => {
108
+ var _a;
109
+ return ((_a = value.url) == null ? void 0 : _a.length) ?? 1;
110
+ }
63
111
  });
64
112
  return this._cache;
65
113
  }
@@ -88,12 +136,12 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
88
136
  return this.config.width ?? 128;
89
137
  }
90
138
  static async binaryToSha256(data) {
91
- await import_core.PayloadHasher.wasmInitialized;
92
- if (import_core.PayloadHasher.wasmSupport.canUseWasm) {
139
+ await import_core2.PayloadHasher.wasmInitialized;
140
+ if (import_core2.PayloadHasher.wasmSupport.canUseWasm) {
93
141
  try {
94
142
  return await (0, import_hash_wasm.sha256)(data);
95
143
  } catch (ex) {
96
- import_core.PayloadHasher.wasmSupport.allowWasm = false;
144
+ import_core2.PayloadHasher.wasmSupport.allowWasm = false;
97
145
  }
98
146
  }
99
147
  return (0, import_sha.default)("sha256").update(data).digest().toString();
@@ -130,7 +178,7 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
130
178
  host = this.ipfGateway;
131
179
  path = url.host === "ipfs" ? `ipfs${path}` : `ipfs/${url.host}${path}`;
132
180
  const root = `${protocol}//${host}/${path}`;
133
- return query?.length > 0 ? `${root}?${query}` : root;
181
+ return (query == null ? void 0 : query.length) > 0 ? `${root}?${query}` : root;
134
182
  } else {
135
183
  return urlToCheck;
136
184
  }
@@ -149,11 +197,11 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
149
197
  return cachedResult;
150
198
  }
151
199
  let result;
152
- const dataBuffer = ImageThumbnailWitness.bufferFromDataUrl(url);
200
+ const dataBuffer = _ImageThumbnailWitness.bufferFromDataUrl(url);
153
201
  if (dataBuffer) {
154
202
  result = {
155
- schema: import_image_thumbnail_payload_plugin.ImageThumbnailSchema,
156
- sourceHash: await ImageThumbnailWitness.binaryToSha256(dataBuffer),
203
+ schema: import_image_thumbnail_payload_plugin2.ImageThumbnailSchema,
204
+ sourceHash: await _ImageThumbnailWitness.binaryToSha256(dataBuffer),
157
205
  sourceUrl: url,
158
206
  url
159
207
  };
@@ -186,10 +234,11 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
186
234
  * @returns An buffer containing an image thumbnail for the video.
187
235
  */
188
236
  async createThumbnailFromVideo(videoBuffer) {
189
- const imageBuffer = await (0, import_ffmpeg.getVideoFrameAsImageFluent)(videoBuffer);
237
+ const imageBuffer = await getVideoFrameAsImageFluent(videoBuffer);
190
238
  return this.createThumbnailDataUrl(imageBuffer);
191
239
  }
192
240
  async fromHttp(url, sourceUrl) {
241
+ var _a, _b, _c, _d, _e, _f;
193
242
  let response;
194
243
  let dnsResult;
195
244
  try {
@@ -201,7 +250,7 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
201
250
  http: {
202
251
  dnsError: error.code
203
252
  },
204
- schema: import_image_thumbnail_payload_plugin.ImageThumbnailSchema,
253
+ schema: import_image_thumbnail_payload_plugin2.ImageThumbnailSchema,
205
254
  sourceUrl: sourceUrl ?? url
206
255
  };
207
256
  return result2;
@@ -216,9 +265,9 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
216
265
  const result2 = {
217
266
  http: {
218
267
  ipAddress: dnsResult[0],
219
- status: axiosError?.response?.status
268
+ status: (_a = axiosError == null ? void 0 : axiosError.response) == null ? void 0 : _a.status
220
269
  },
221
- schema: import_image_thumbnail_payload_plugin.ImageThumbnailSchema,
270
+ schema: import_image_thumbnail_payload_plugin2.ImageThumbnailSchema,
222
271
  sourceUrl: sourceUrl ?? url
223
272
  };
224
273
  return result2;
@@ -230,11 +279,11 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
230
279
  http: {
231
280
  status: response.status
232
281
  },
233
- schema: import_image_thumbnail_payload_plugin.ImageThumbnailSchema,
282
+ schema: import_image_thumbnail_payload_plugin2.ImageThumbnailSchema,
234
283
  sourceUrl: sourceUrl ?? url
235
284
  };
236
285
  if (response.status >= 200 && response.status < 300) {
237
- const contentType = response.headers["content-type"]?.toString();
286
+ const contentType = (_b = response.headers["content-type"]) == null ? void 0 : _b.toString();
238
287
  const [mediaType, fileType] = contentType.split("/");
239
288
  result.mime = result.mime ?? {};
240
289
  result.mime.returned = mediaType;
@@ -243,15 +292,15 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
243
292
  result.mime.detected = await import_file_type.default.fromBuffer(sourceBuffer);
244
293
  } catch (ex) {
245
294
  const error = ex;
246
- this.logger?.error(`FileType error: ${error.message}`);
295
+ (_c = this.logger) == null ? void 0 : _c.error(`FileType error: ${error.message}`);
247
296
  }
248
297
  const processImage = async (encoding2) => {
249
- result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer);
298
+ result.sourceHash = await _ImageThumbnailWitness.binaryToSha256(sourceBuffer);
250
299
  result.url = await this.createThumbnailDataUrl(sourceBuffer, encoding2);
251
300
  };
252
301
  const processVideo = async () => {
253
302
  if (import_hasbin.default.sync("ffmpeg")) {
254
- result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer);
303
+ result.sourceHash = await _ImageThumbnailWitness.binaryToSha256(sourceBuffer);
255
304
  result.url = await this.createThumbnailFromVideo(sourceBuffer);
256
305
  } else {
257
306
  result.mime = result.mime ?? {};
@@ -280,15 +329,15 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
280
329
  break;
281
330
  }
282
331
  default: {
283
- switch (result.mime.detected?.mime) {
332
+ switch ((_d = result.mime.detected) == null ? void 0 : _d.mime) {
284
333
  case "image": {
285
334
  await processImage();
286
- result.mime.type = result.mime.detected?.mime;
335
+ result.mime.type = (_e = result.mime.detected) == null ? void 0 : _e.mime;
287
336
  break;
288
337
  }
289
338
  case "video": {
290
339
  await processVideo();
291
- result.mime.type = result.mime.detected?.mime;
340
+ result.mime.type = (_f = result.mime.detected) == null ? void 0 : _f.mime;
292
341
  break;
293
342
  }
294
343
  default: {
@@ -302,7 +351,7 @@ class ImageThumbnailWitness extends import_witness.AbstractWitness {
302
351
  }
303
352
  return result;
304
353
  }
305
- }
354
+ };
306
355
  // Annotate the CommonJS export names for ESM import in node:
307
356
  0 && (module.exports = {
308
357
  ImageThumbnailWitness
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/Witness/Witness.ts"],"sourcesContent":["/* eslint-disable max-statements */\nimport { promises as dnsPromises } from 'node:dns'\n\nimport { compact } from '@xylabs/lodash'\nimport { URL } from '@xylabs/url'\nimport { axios, AxiosError, AxiosResponse } from '@xyo-network/axios'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { ImageThumbnail, ImageThumbnailSchema } from '@xyo-network/image-thumbnail-payload-plugin'\nimport { UrlPayload, UrlSchema } from '@xyo-network/url-payload-plugin'\nimport { AbstractWitness } from '@xyo-network/witness'\nimport { Semaphore } from 'async-mutex'\nimport FileType from 'file-type'\nimport graphicsMagick from 'gm'\nimport hasbin from 'hasbin'\nimport { sha256 } from 'hash-wasm'\nimport { LRUCache } from 'lru-cache'\nimport shajs from 'sha.js'\nimport Url from 'url-parse'\n\nimport { ImageThumbnailEncoding, ImageThumbnailWitnessConfigSchema } from './Config'\nimport { getVideoFrameAsImageFluent } from './ffmpeg'\nimport { ImageThumbnailWitnessParams } from './Params'\n\n//TODO: Break this into two Witnesses?\n\n// setFfmpegPath(ffmpegPath)\n\n// eslint-disable-next-line import/no-named-as-default-member\nconst gm = graphicsMagick.subClass({ imageMagick: '7+' })\n\nexport interface ImageThumbnailWitnessError extends Error {\n name: 'ImageThumbnailWitnessError'\n url: string\n}\n\nexport interface DnsError extends Error {\n code: string\n}\n\nexport class ImageThumbnailWitness<TParams extends ImageThumbnailWitnessParams = ImageThumbnailWitnessParams> extends AbstractWitness<TParams> {\n static override configSchemas = [ImageThumbnailWitnessConfigSchema]\n\n private _cache?: LRUCache<string, ImageThumbnail>\n private _semaphore = new Semaphore(this.maxAsyncProcesses)\n\n get cache() {\n this._cache =\n this._cache ??\n new LRUCache<string, ImageThumbnail>({\n max: this.maxCacheEntries,\n maxSize: this.maxCacheBytes,\n //just returning the size of the data\n sizeCalculation: (value) => value.url?.length ?? 1,\n })\n return this._cache\n }\n\n get encoding() {\n return this.config.encoding ?? 'PNG'\n }\n\n get height() {\n return this.config.height ?? 128\n }\n\n get ipfGateway() {\n return this.config.ipfsGateway ?? '5d7b6582.beta.decentralnetworkservices.com'\n }\n\n get maxAsyncProcesses() {\n return this.config.maxAsyncProcesses ?? 2\n }\n\n get maxCacheBytes() {\n return this.config.maxCacheBytes ?? 1024 * 1024 * 16 //64MB max size\n }\n\n get maxCacheEntries() {\n return this.config.maxCacheEntries ?? 500\n }\n\n get quality() {\n return this.config.quality ?? 50\n }\n\n get width() {\n return this.config.width ?? 128\n }\n\n private static async binaryToSha256(data: Uint8Array) {\n await PayloadHasher.wasmInitialized\n if (PayloadHasher.wasmSupport.canUseWasm) {\n try {\n return await sha256(data)\n } catch (ex) {\n PayloadHasher.wasmSupport.allowWasm = false\n }\n }\n\n return shajs('sha256').update(data).digest().toString()\n }\n\n private static bufferFromDataUrl(url: string): Buffer | undefined {\n if (url.startsWith('data:image')) {\n const data = url.split(',')[1]\n if (data) {\n return Buffer.from(Uint8Array.from(atob(data), (c) => c.charCodeAt(0)))\n } else {\n const error: ImageThumbnailWitnessError = {\n message: 'Invalid data Url',\n name: 'ImageThumbnailWitnessError',\n url,\n }\n throw error\n }\n }\n }\n\n /**\n * Returns the equivalent IPFS gateway URL for the supplied URL.\n * @param urlToCheck The URL to check\n * @returns If the supplied URL is an IPFS URL, it converts the URL to the\n * equivalent IPFS gateway URL. Otherwise, returns the original URL.\n */\n checkIpfsUrl(urlToCheck: string) {\n const url = new URL(urlToCheck)\n let protocol = url.protocol\n let host = url.host\n let path = url.pathname\n const query = url.search\n if (protocol === 'ipfs:') {\n protocol = 'https:'\n host = this.ipfGateway\n path = url.host === 'ipfs' ? `ipfs${path}` : `ipfs/${url.host}${path}`\n const root = `${protocol}//${host}/${path}`\n return query?.length > 0 ? `${root}?${query}` : root\n } else {\n return urlToCheck\n }\n }\n\n protected override async observeHandler(payloads: UrlPayload[] = []): Promise<ImageThumbnail[]> {\n // eslint-disable-next-line import/no-named-as-default-member\n if (!hasbin.sync('magick')) {\n throw Error('ImageMagick is required for this witness')\n }\n const urlPayloads = payloads.filter((payload) => payload.schema === UrlSchema)\n return await this._semaphore.runExclusive(async () =>\n compact(\n await Promise.all(\n urlPayloads.map<Promise<ImageThumbnail>>(async ({ url }) => {\n const cachedResult = this.cache.get(url)\n if (cachedResult) {\n return cachedResult\n }\n let result: ImageThumbnail\n\n //if it is a data URL, return a Buffer\n const dataBuffer = ImageThumbnailWitness.bufferFromDataUrl(url)\n\n if (dataBuffer) {\n result = {\n schema: ImageThumbnailSchema,\n sourceHash: await ImageThumbnailWitness.binaryToSha256(dataBuffer),\n sourceUrl: url,\n url,\n }\n } else {\n //if it is ipfs, go through cloud flair\n const mutatedUrl = this.checkIpfsUrl(url)\n result = await this.fromHttp(mutatedUrl, url)\n }\n this.cache.set(url, result)\n return result\n }),\n ),\n ),\n )\n }\n\n private async createThumbnailDataUrl(sourceBuffer: Buffer, encoding?: ImageThumbnailEncoding) {\n const thumb = await new Promise<Buffer>((resolve, reject) => {\n gm(sourceBuffer)\n .quality(this.quality)\n .resize(this.width, this.height)\n .flatten()\n .toBuffer(encoding ?? this.encoding, (error, buffer) => {\n if (error) {\n reject(error)\n } else {\n resolve(buffer)\n }\n })\n })\n return `data:image/png;base64,${thumb.toString('base64')}`\n }\n\n /**\n * Creates an image thumbnail from a video.\n * @param videoBuffer The input video buffer.\n * @returns An buffer containing an image thumbnail for the video.\n */\n private async createThumbnailFromVideo(videoBuffer: Buffer) {\n const imageBuffer = await getVideoFrameAsImageFluent(videoBuffer)\n return this.createThumbnailDataUrl(imageBuffer)\n }\n\n private async fromHttp(url: string, sourceUrl?: string): Promise<ImageThumbnail> {\n let response: AxiosResponse\n let dnsResult: string[]\n try {\n const urlObj = new Url(url)\n dnsResult = await dnsPromises.resolve(urlObj.host)\n // console.log(`dnsResult: ${JSON.stringify(dnsResult, null, 2)}`)\n } catch (ex) {\n const error = ex as DnsError\n const result: ImageThumbnail = {\n http: {\n dnsError: error.code,\n },\n schema: ImageThumbnailSchema,\n sourceUrl: sourceUrl ?? url,\n }\n return result\n }\n try {\n response = await axios.get(url, {\n responseType: 'arraybuffer',\n })\n } catch (ex) {\n const axiosError = ex as AxiosError\n if (axiosError.isAxiosError) {\n //selectively pick fields from AxiosError\n const result: ImageThumbnail = {\n http: {\n ipAddress: dnsResult[0],\n status: axiosError?.response?.status,\n },\n schema: ImageThumbnailSchema,\n sourceUrl: sourceUrl ?? url,\n }\n return result\n } else {\n throw ex\n }\n }\n\n const result: ImageThumbnail = {\n http: {\n status: response.status,\n },\n schema: ImageThumbnailSchema,\n sourceUrl: sourceUrl ?? url,\n }\n\n if (response.status >= 200 && response.status < 300) {\n const contentType: string = response.headers['content-type']?.toString()\n const [mediaType, fileType] = contentType.split('/')\n result.mime = result.mime ?? {}\n result.mime.returned = mediaType\n const sourceBuffer = Buffer.from(response.data, 'binary')\n\n try {\n result.mime.detected = await FileType.fromBuffer(sourceBuffer)\n } catch (ex) {\n const error = ex as Error\n this.logger?.error(`FileType error: ${error.message}`)\n }\n\n const processImage = async (encoding?: ImageThumbnailEncoding) => {\n result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer)\n result.url = await this.createThumbnailDataUrl(sourceBuffer, encoding)\n }\n\n const processVideo = async () => {\n // Gracefully handle the case where ffmpeg is not installed.\n // eslint-disable-next-line import/no-named-as-default-member\n if (hasbin.sync('ffmpeg')) {\n result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer)\n result.url = await this.createThumbnailFromVideo(sourceBuffer)\n } else {\n result.mime = result.mime ?? {}\n result.mime.invalid = true\n }\n }\n\n let encoding: ImageThumbnailEncoding = 'PNG'\n\n switch (fileType.toUpperCase()) {\n case 'GIF':\n encoding = 'GIF'\n break\n case 'JPG':\n case 'JPEG':\n encoding = 'JPG'\n break\n }\n\n switch (mediaType) {\n case 'image': {\n await processImage(encoding)\n result.mime.type = mediaType\n break\n }\n case 'video': {\n await processVideo()\n result.mime.type = mediaType\n break\n }\n default: {\n switch (result.mime.detected?.mime) {\n case 'image': {\n await processImage()\n result.mime.type = result.mime.detected?.mime\n break\n }\n case 'video': {\n await processVideo()\n result.mime.type = result.mime.detected?.mime\n break\n }\n default: {\n result.mime.invalid = true\n break\n }\n }\n break\n }\n }\n }\n return result\n }\n}\n"],"mappings":"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","names":["graphicsMagick","shajs","hasbin","Url","dnsPromises","result","FileType","encoding"]}
1
+ {"version":3,"sources":["../../../src/Witness/Witness.ts","../../../src/Witness/Config.ts","../../../src/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.ts"],"sourcesContent":["/* eslint-disable max-statements */\nimport { promises as dnsPromises } from 'node:dns'\n\nimport { compact } from '@xylabs/lodash'\nimport { URL } from '@xylabs/url'\nimport { axios, AxiosError, AxiosResponse } from '@xyo-network/axios'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { ImageThumbnail, ImageThumbnailSchema } from '@xyo-network/image-thumbnail-payload-plugin'\nimport { UrlPayload, UrlSchema } from '@xyo-network/url-payload-plugin'\nimport { AbstractWitness } from '@xyo-network/witness'\nimport { Semaphore } from 'async-mutex'\nimport FileType from 'file-type'\nimport graphicsMagick from 'gm'\nimport hasbin from 'hasbin'\nimport { sha256 } from 'hash-wasm'\nimport { LRUCache } from 'lru-cache'\nimport shajs from 'sha.js'\nimport Url from 'url-parse'\n\nimport { ImageThumbnailEncoding, ImageThumbnailWitnessConfigSchema } from './Config'\nimport { getVideoFrameAsImageFluent } from './ffmpeg'\nimport { ImageThumbnailWitnessParams } from './Params'\n\n//TODO: Break this into two Witnesses?\n\n// setFfmpegPath(ffmpegPath)\n\n// eslint-disable-next-line import/no-named-as-default-member\nconst gm = graphicsMagick.subClass({ imageMagick: '7+' })\n\nexport interface ImageThumbnailWitnessError extends Error {\n name: 'ImageThumbnailWitnessError'\n url: string\n}\n\nexport interface DnsError extends Error {\n code: string\n}\n\nexport class ImageThumbnailWitness<TParams extends ImageThumbnailWitnessParams = ImageThumbnailWitnessParams> extends AbstractWitness<TParams> {\n static override configSchemas = [ImageThumbnailWitnessConfigSchema]\n\n private _cache?: LRUCache<string, ImageThumbnail>\n private _semaphore = new Semaphore(this.maxAsyncProcesses)\n\n get cache() {\n this._cache =\n this._cache ??\n new LRUCache<string, ImageThumbnail>({\n max: this.maxCacheEntries,\n maxSize: this.maxCacheBytes,\n //just returning the size of the data\n sizeCalculation: (value) => value.url?.length ?? 1,\n })\n return this._cache\n }\n\n get encoding() {\n return this.config.encoding ?? 'PNG'\n }\n\n get height() {\n return this.config.height ?? 128\n }\n\n get ipfGateway() {\n return this.config.ipfsGateway ?? '5d7b6582.beta.decentralnetworkservices.com'\n }\n\n get maxAsyncProcesses() {\n return this.config.maxAsyncProcesses ?? 2\n }\n\n get maxCacheBytes() {\n return this.config.maxCacheBytes ?? 1024 * 1024 * 16 //64MB max size\n }\n\n get maxCacheEntries() {\n return this.config.maxCacheEntries ?? 500\n }\n\n get quality() {\n return this.config.quality ?? 50\n }\n\n get width() {\n return this.config.width ?? 128\n }\n\n private static async binaryToSha256(data: Uint8Array) {\n await PayloadHasher.wasmInitialized\n if (PayloadHasher.wasmSupport.canUseWasm) {\n try {\n return await sha256(data)\n } catch (ex) {\n PayloadHasher.wasmSupport.allowWasm = false\n }\n }\n\n return shajs('sha256').update(data).digest().toString()\n }\n\n private static bufferFromDataUrl(url: string): Buffer | undefined {\n if (url.startsWith('data:image')) {\n const data = url.split(',')[1]\n if (data) {\n return Buffer.from(Uint8Array.from(atob(data), (c) => c.charCodeAt(0)))\n } else {\n const error: ImageThumbnailWitnessError = {\n message: 'Invalid data Url',\n name: 'ImageThumbnailWitnessError',\n url,\n }\n throw error\n }\n }\n }\n\n /**\n * Returns the equivalent IPFS gateway URL for the supplied URL.\n * @param urlToCheck The URL to check\n * @returns If the supplied URL is an IPFS URL, it converts the URL to the\n * equivalent IPFS gateway URL. Otherwise, returns the original URL.\n */\n checkIpfsUrl(urlToCheck: string) {\n const url = new URL(urlToCheck)\n let protocol = url.protocol\n let host = url.host\n let path = url.pathname\n const query = url.search\n if (protocol === 'ipfs:') {\n protocol = 'https:'\n host = this.ipfGateway\n path = url.host === 'ipfs' ? `ipfs${path}` : `ipfs/${url.host}${path}`\n const root = `${protocol}//${host}/${path}`\n return query?.length > 0 ? `${root}?${query}` : root\n } else {\n return urlToCheck\n }\n }\n\n protected override async observeHandler(payloads: UrlPayload[] = []): Promise<ImageThumbnail[]> {\n // eslint-disable-next-line import/no-named-as-default-member\n if (!hasbin.sync('magick')) {\n throw Error('ImageMagick is required for this witness')\n }\n const urlPayloads = payloads.filter((payload) => payload.schema === UrlSchema)\n return await this._semaphore.runExclusive(async () =>\n compact(\n await Promise.all(\n urlPayloads.map<Promise<ImageThumbnail>>(async ({ url }) => {\n const cachedResult = this.cache.get(url)\n if (cachedResult) {\n return cachedResult\n }\n let result: ImageThumbnail\n\n //if it is a data URL, return a Buffer\n const dataBuffer = ImageThumbnailWitness.bufferFromDataUrl(url)\n\n if (dataBuffer) {\n result = {\n schema: ImageThumbnailSchema,\n sourceHash: await ImageThumbnailWitness.binaryToSha256(dataBuffer),\n sourceUrl: url,\n url,\n }\n } else {\n //if it is ipfs, go through cloud flair\n const mutatedUrl = this.checkIpfsUrl(url)\n result = await this.fromHttp(mutatedUrl, url)\n }\n this.cache.set(url, result)\n return result\n }),\n ),\n ),\n )\n }\n\n private async createThumbnailDataUrl(sourceBuffer: Buffer, encoding?: ImageThumbnailEncoding) {\n const thumb = await new Promise<Buffer>((resolve, reject) => {\n gm(sourceBuffer)\n .quality(this.quality)\n .resize(this.width, this.height)\n .flatten()\n .toBuffer(encoding ?? this.encoding, (error, buffer) => {\n if (error) {\n reject(error)\n } else {\n resolve(buffer)\n }\n })\n })\n return `data:image/png;base64,${thumb.toString('base64')}`\n }\n\n /**\n * Creates an image thumbnail from a video.\n * @param videoBuffer The input video buffer.\n * @returns An buffer containing an image thumbnail for the video.\n */\n private async createThumbnailFromVideo(videoBuffer: Buffer) {\n const imageBuffer = await getVideoFrameAsImageFluent(videoBuffer)\n return this.createThumbnailDataUrl(imageBuffer)\n }\n\n private async fromHttp(url: string, sourceUrl?: string): Promise<ImageThumbnail> {\n let response: AxiosResponse\n let dnsResult: string[]\n try {\n const urlObj = new Url(url)\n dnsResult = await dnsPromises.resolve(urlObj.host)\n // console.log(`dnsResult: ${JSON.stringify(dnsResult, null, 2)}`)\n } catch (ex) {\n const error = ex as DnsError\n const result: ImageThumbnail = {\n http: {\n dnsError: error.code,\n },\n schema: ImageThumbnailSchema,\n sourceUrl: sourceUrl ?? url,\n }\n return result\n }\n try {\n response = await axios.get(url, {\n responseType: 'arraybuffer',\n })\n } catch (ex) {\n const axiosError = ex as AxiosError\n if (axiosError.isAxiosError) {\n //selectively pick fields from AxiosError\n const result: ImageThumbnail = {\n http: {\n ipAddress: dnsResult[0],\n status: axiosError?.response?.status,\n },\n schema: ImageThumbnailSchema,\n sourceUrl: sourceUrl ?? url,\n }\n return result\n } else {\n throw ex\n }\n }\n\n const result: ImageThumbnail = {\n http: {\n status: response.status,\n },\n schema: ImageThumbnailSchema,\n sourceUrl: sourceUrl ?? url,\n }\n\n if (response.status >= 200 && response.status < 300) {\n const contentType: string = response.headers['content-type']?.toString()\n const [mediaType, fileType] = contentType.split('/')\n result.mime = result.mime ?? {}\n result.mime.returned = mediaType\n const sourceBuffer = Buffer.from(response.data, 'binary')\n\n try {\n result.mime.detected = await FileType.fromBuffer(sourceBuffer)\n } catch (ex) {\n const error = ex as Error\n this.logger?.error(`FileType error: ${error.message}`)\n }\n\n const processImage = async (encoding?: ImageThumbnailEncoding) => {\n result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer)\n result.url = await this.createThumbnailDataUrl(sourceBuffer, encoding)\n }\n\n const processVideo = async () => {\n // Gracefully handle the case where ffmpeg is not installed.\n // eslint-disable-next-line import/no-named-as-default-member\n if (hasbin.sync('ffmpeg')) {\n result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer)\n result.url = await this.createThumbnailFromVideo(sourceBuffer)\n } else {\n result.mime = result.mime ?? {}\n result.mime.invalid = true\n }\n }\n\n let encoding: ImageThumbnailEncoding = 'PNG'\n\n switch (fileType.toUpperCase()) {\n case 'GIF':\n encoding = 'GIF'\n break\n case 'JPG':\n case 'JPEG':\n encoding = 'JPG'\n break\n }\n\n switch (mediaType) {\n case 'image': {\n await processImage(encoding)\n result.mime.type = mediaType\n break\n }\n case 'video': {\n await processVideo()\n result.mime.type = mediaType\n break\n }\n default: {\n switch (result.mime.detected?.mime) {\n case 'image': {\n await processImage()\n result.mime.type = result.mime.detected?.mime\n break\n }\n case 'video': {\n await processVideo()\n result.mime.type = result.mime.detected?.mime\n break\n }\n default: {\n result.mime.invalid = true\n break\n }\n }\n break\n }\n }\n }\n return result\n }\n}\n","import { ImageThumbnailSchema } from '@xyo-network/image-thumbnail-payload-plugin'\nimport { WitnessConfig } from '@xyo-network/witness'\n\nexport const ImageThumbnailWitnessConfigSchema = `${ImageThumbnailSchema}.witness.config` as const\nexport type ImageThumbnailWitnessConfigSchema = typeof ImageThumbnailWitnessConfigSchema\n\nexport type ImageThumbnailEncoding = 'PNG' | 'JPG' | 'GIF'\n\nexport type ImageThumbnailWitnessConfig = WitnessConfig<{\n encoding?: ImageThumbnailEncoding\n height?: number\n ipfsGateway?: string\n maxAsyncProcesses?: number\n maxCacheBytes?: number\n maxCacheEntries?: number\n quality?: number\n schema: ImageThumbnailWitnessConfigSchema\n width?: number\n}>\n","import { uuid } from '@xyo-network/core'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { unlink, writeFile } from 'fs/promises'\nimport { tmpdir } from 'os'\nimport { Writable, WritableOptions } from 'stream'\n\n/**\n * A Writable stream that collects output from ffmpeg.\n */\nclass FfmpegOutputStream extends Writable {\n private readonly chunks: Uint8Array[] = []\n\n constructor(options?: WritableOptions) {\n super(options)\n }\n\n override _write(chunk: never, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {\n this.chunks.push(chunk)\n callback()\n }\n\n /**\n * Collects the output from ffmpeg into a buffer.\n * @returns A buffer containing the concatenated\n * output from ffmpeg.\n */\n toBuffer = () => Buffer.concat(this.chunks)\n}\n\n/**\n * Execute FFmpeg using fluent API with provided input buffer and video thumbnail image.\n * @param videoBuffer Input video buffer.\n * @returns Output buffer containing the video thumbnail image.\n */\nexport const getVideoFrameAsImageFluent = async (videoBuffer: Buffer) => {\n // Get a temp file name\n const tmpFile = `/${tmpdir()}/${uuid()}`\n try {\n // Write videoBuffer to temp file for use as input to ffmpeg to\n // avoid issues with ffmpeg inferring premature EOF from buffer\n // passed via stdin (happens when ffmpeg is trying to infer\n // input video format)\n await writeFile(tmpFile, videoBuffer, { encoding: 'binary' })\n const imageBuffer = await new Promise<Buffer>((resolve, reject) => {\n // Create a Writable stream to collect PNG output from ffmpeg\n const ffmpegOutput = new FfmpegOutputStream()\n // Execute ffmpeg using fluent API\n ffmpeg()\n // NOTE: Uncomment to debug CLI args to ffmpeg\n // .on('start', (commandLine) => console.log('Spawned Ffmpeg with command: ' + commandLine))\n .on('error', (err) => reject(err.message))\n // Listen for the 'end' event to combine the output into a buffer holding the PNG image\n .on('end', () => resolve(ffmpegOutput.toBuffer()))\n .input(tmpFile) // Use temp file as input\n .takeFrames(1) // Only take 1st video frame\n .withNoAudio() // Don't include audio\n .outputOptions('-f image2pipe') // Write output to stdout\n .videoCodec('png') // Force PNG output\n // Start processing and direct ffmpeg stdout to writable stream\n .pipe(ffmpegOutput)\n })\n return imageBuffer\n } finally {\n // Cleanup temp file\n try {\n await unlink(tmpFile)\n } catch {\n // No error here since file doesn't exist\n }\n }\n}\n"],"mappings":"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","names":["import_core","import_image_thumbnail_payload_plugin","ffmpeg","graphicsMagick","shajs","hasbin","Url","dnsPromises","result","FileType","encoding"]}
@@ -1,9 +1,10 @@
1
+ // src/Witness/Witness.ts
1
2
  import { promises as dnsPromises } from "node:dns";
2
3
  import { compact } from "@xylabs/lodash";
3
4
  import { URL } from "@xylabs/url";
4
5
  import { axios } from "@xyo-network/axios";
5
6
  import { PayloadHasher } from "@xyo-network/core";
6
- import { ImageThumbnailSchema } from "@xyo-network/image-thumbnail-payload-plugin";
7
+ import { ImageThumbnailSchema as ImageThumbnailSchema2 } from "@xyo-network/image-thumbnail-payload-plugin";
7
8
  import { UrlSchema } from "@xyo-network/url-payload-plugin";
8
9
  import { AbstractWitness } from "@xyo-network/witness";
9
10
  import { Semaphore } from "async-mutex";
@@ -14,10 +15,53 @@ import { sha256 } from "hash-wasm";
14
15
  import { LRUCache } from "lru-cache";
15
16
  import shajs from "sha.js";
16
17
  import Url from "url-parse";
17
- import { ImageThumbnailWitnessConfigSchema } from "./Config";
18
- import { getVideoFrameAsImageFluent } from "./ffmpeg";
19
- const gm = graphicsMagick.subClass({ imageMagick: "7+" });
20
- class ImageThumbnailWitness extends AbstractWitness {
18
+
19
+ // src/Witness/Config.ts
20
+ import { ImageThumbnailSchema } from "@xyo-network/image-thumbnail-payload-plugin";
21
+ var ImageThumbnailWitnessConfigSchema = `${ImageThumbnailSchema}.witness.config`;
22
+
23
+ // src/Witness/ffmpeg/fluent/getVideoFrameAsImageFluent.ts
24
+ import { uuid } from "@xyo-network/core";
25
+ import ffmpeg from "fluent-ffmpeg";
26
+ import { unlink, writeFile } from "fs/promises";
27
+ import { tmpdir } from "os";
28
+ import { Writable } from "stream";
29
+ var FfmpegOutputStream = class extends Writable {
30
+ chunks = [];
31
+ constructor(options) {
32
+ super(options);
33
+ }
34
+ _write(chunk, _encoding, callback) {
35
+ this.chunks.push(chunk);
36
+ callback();
37
+ }
38
+ /**
39
+ * Collects the output from ffmpeg into a buffer.
40
+ * @returns A buffer containing the concatenated
41
+ * output from ffmpeg.
42
+ */
43
+ toBuffer = () => Buffer.concat(this.chunks);
44
+ };
45
+ var getVideoFrameAsImageFluent = async (videoBuffer) => {
46
+ const tmpFile = `/${tmpdir()}/${uuid()}`;
47
+ try {
48
+ await writeFile(tmpFile, videoBuffer, { encoding: "binary" });
49
+ const imageBuffer = await new Promise((resolve, reject) => {
50
+ const ffmpegOutput = new FfmpegOutputStream();
51
+ ffmpeg().on("error", (err) => reject(err.message)).on("end", () => resolve(ffmpegOutput.toBuffer())).input(tmpFile).takeFrames(1).withNoAudio().outputOptions("-f image2pipe").videoCodec("png").pipe(ffmpegOutput);
52
+ });
53
+ return imageBuffer;
54
+ } finally {
55
+ try {
56
+ await unlink(tmpFile);
57
+ } catch {
58
+ }
59
+ }
60
+ };
61
+
62
+ // src/Witness/Witness.ts
63
+ var gm = graphicsMagick.subClass({ imageMagick: "7+" });
64
+ var ImageThumbnailWitness = class _ImageThumbnailWitness extends AbstractWitness {
21
65
  static configSchemas = [ImageThumbnailWitnessConfigSchema];
22
66
  _cache;
23
67
  _semaphore = new Semaphore(this.maxAsyncProcesses);
@@ -26,7 +70,10 @@ class ImageThumbnailWitness extends AbstractWitness {
26
70
  max: this.maxCacheEntries,
27
71
  maxSize: this.maxCacheBytes,
28
72
  //just returning the size of the data
29
- sizeCalculation: (value) => value.url?.length ?? 1
73
+ sizeCalculation: (value) => {
74
+ var _a;
75
+ return ((_a = value.url) == null ? void 0 : _a.length) ?? 1;
76
+ }
30
77
  });
31
78
  return this._cache;
32
79
  }
@@ -97,7 +144,7 @@ class ImageThumbnailWitness extends AbstractWitness {
97
144
  host = this.ipfGateway;
98
145
  path = url.host === "ipfs" ? `ipfs${path}` : `ipfs/${url.host}${path}`;
99
146
  const root = `${protocol}//${host}/${path}`;
100
- return query?.length > 0 ? `${root}?${query}` : root;
147
+ return (query == null ? void 0 : query.length) > 0 ? `${root}?${query}` : root;
101
148
  } else {
102
149
  return urlToCheck;
103
150
  }
@@ -116,11 +163,11 @@ class ImageThumbnailWitness extends AbstractWitness {
116
163
  return cachedResult;
117
164
  }
118
165
  let result;
119
- const dataBuffer = ImageThumbnailWitness.bufferFromDataUrl(url);
166
+ const dataBuffer = _ImageThumbnailWitness.bufferFromDataUrl(url);
120
167
  if (dataBuffer) {
121
168
  result = {
122
- schema: ImageThumbnailSchema,
123
- sourceHash: await ImageThumbnailWitness.binaryToSha256(dataBuffer),
169
+ schema: ImageThumbnailSchema2,
170
+ sourceHash: await _ImageThumbnailWitness.binaryToSha256(dataBuffer),
124
171
  sourceUrl: url,
125
172
  url
126
173
  };
@@ -157,6 +204,7 @@ class ImageThumbnailWitness extends AbstractWitness {
157
204
  return this.createThumbnailDataUrl(imageBuffer);
158
205
  }
159
206
  async fromHttp(url, sourceUrl) {
207
+ var _a, _b, _c, _d, _e, _f;
160
208
  let response;
161
209
  let dnsResult;
162
210
  try {
@@ -168,7 +216,7 @@ class ImageThumbnailWitness extends AbstractWitness {
168
216
  http: {
169
217
  dnsError: error.code
170
218
  },
171
- schema: ImageThumbnailSchema,
219
+ schema: ImageThumbnailSchema2,
172
220
  sourceUrl: sourceUrl ?? url
173
221
  };
174
222
  return result2;
@@ -183,9 +231,9 @@ class ImageThumbnailWitness extends AbstractWitness {
183
231
  const result2 = {
184
232
  http: {
185
233
  ipAddress: dnsResult[0],
186
- status: axiosError?.response?.status
234
+ status: (_a = axiosError == null ? void 0 : axiosError.response) == null ? void 0 : _a.status
187
235
  },
188
- schema: ImageThumbnailSchema,
236
+ schema: ImageThumbnailSchema2,
189
237
  sourceUrl: sourceUrl ?? url
190
238
  };
191
239
  return result2;
@@ -197,11 +245,11 @@ class ImageThumbnailWitness extends AbstractWitness {
197
245
  http: {
198
246
  status: response.status
199
247
  },
200
- schema: ImageThumbnailSchema,
248
+ schema: ImageThumbnailSchema2,
201
249
  sourceUrl: sourceUrl ?? url
202
250
  };
203
251
  if (response.status >= 200 && response.status < 300) {
204
- const contentType = response.headers["content-type"]?.toString();
252
+ const contentType = (_b = response.headers["content-type"]) == null ? void 0 : _b.toString();
205
253
  const [mediaType, fileType] = contentType.split("/");
206
254
  result.mime = result.mime ?? {};
207
255
  result.mime.returned = mediaType;
@@ -210,15 +258,15 @@ class ImageThumbnailWitness extends AbstractWitness {
210
258
  result.mime.detected = await FileType.fromBuffer(sourceBuffer);
211
259
  } catch (ex) {
212
260
  const error = ex;
213
- this.logger?.error(`FileType error: ${error.message}`);
261
+ (_c = this.logger) == null ? void 0 : _c.error(`FileType error: ${error.message}`);
214
262
  }
215
263
  const processImage = async (encoding2) => {
216
- result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer);
264
+ result.sourceHash = await _ImageThumbnailWitness.binaryToSha256(sourceBuffer);
217
265
  result.url = await this.createThumbnailDataUrl(sourceBuffer, encoding2);
218
266
  };
219
267
  const processVideo = async () => {
220
268
  if (hasbin.sync("ffmpeg")) {
221
- result.sourceHash = await ImageThumbnailWitness.binaryToSha256(sourceBuffer);
269
+ result.sourceHash = await _ImageThumbnailWitness.binaryToSha256(sourceBuffer);
222
270
  result.url = await this.createThumbnailFromVideo(sourceBuffer);
223
271
  } else {
224
272
  result.mime = result.mime ?? {};
@@ -247,15 +295,15 @@ class ImageThumbnailWitness extends AbstractWitness {
247
295
  break;
248
296
  }
249
297
  default: {
250
- switch (result.mime.detected?.mime) {
298
+ switch ((_d = result.mime.detected) == null ? void 0 : _d.mime) {
251
299
  case "image": {
252
300
  await processImage();
253
- result.mime.type = result.mime.detected?.mime;
301
+ result.mime.type = (_e = result.mime.detected) == null ? void 0 : _e.mime;
254
302
  break;
255
303
  }
256
304
  case "video": {
257
305
  await processVideo();
258
- result.mime.type = result.mime.detected?.mime;
306
+ result.mime.type = (_f = result.mime.detected) == null ? void 0 : _f.mime;
259
307
  break;
260
308
  }
261
309
  default: {
@@ -269,7 +317,7 @@ class ImageThumbnailWitness extends AbstractWitness {
269
317
  }
270
318
  return result;
271
319
  }
272
- }
320
+ };
273
321
  export {
274
322
  ImageThumbnailWitness
275
323
  };