polotno-node 2.10.0 → 2.10.2

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/dist/index.html CHANGED
@@ -8,7 +8,7 @@
8
8
  }
9
9
  </style>
10
10
  <meta name="viewport" content="width=device-width, initial-scale=1" />
11
- <script type="module" crossorigin src="./assets/index-BWNdW2kw.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-D56TTNQ-.js"></script>
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
package/instance.js CHANGED
@@ -75,6 +75,8 @@ module.exports.jsonToBlob = async (page, json, attrs) => {
75
75
 
76
76
  const busyPages = [];
77
77
 
78
+ const createdInstances = [];
79
+
78
80
  module.exports.createInstance = async ({
79
81
  key,
80
82
  url,
@@ -272,8 +274,9 @@ module.exports.createInstance = async ({
272
274
  return blob;
273
275
  };
274
276
 
275
- return {
277
+ const instance = {
276
278
  close: async () => {
279
+ createdInstances.splice(createdInstances.indexOf(instance), 1);
277
280
  await browser.close();
278
281
  },
279
282
  firstPage,
@@ -288,4 +291,33 @@ module.exports.createInstance = async ({
288
291
  jsonToGIFBase64,
289
292
  createPage: async () => await module.exports.createPage(browser, visitPage),
290
293
  };
294
+
295
+ createdInstances.push(instance);
296
+ return instance;
291
297
  };
298
+
299
+ // Function to close all created instances in parallel
300
+ const closeAllInstances = async () => {
301
+ await Promise.all(createdInstances.map((instance) => instance.close()));
302
+ };
303
+
304
+ // Register the function to be called on process exit
305
+ process.on('beforeExit', () => {
306
+ closeAllInstances().catch((error) => {
307
+ console.error('Error closing instances:', error);
308
+ });
309
+ });
310
+
311
+ // Also handle other termination signals
312
+ ['SIGINT', 'SIGTERM', 'SIGQUIT', 'exit', 'beforeExit'].forEach((signal) => {
313
+ process.on(signal, () => {
314
+ closeAllInstances()
315
+ .then(() => {
316
+ process.exit(0);
317
+ })
318
+ .catch((error) => {
319
+ console.error('Error closing instances:', error);
320
+ process.exit(1);
321
+ });
322
+ });
323
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polotno-node",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "description": "Polotno workflow from NodeJS",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,31 +12,30 @@
12
12
  "dist",
13
13
  "index.js",
14
14
  "instance.js",
15
- "video.js",
16
15
  "video-parallel.js",
17
16
  "README.md"
18
17
  ],
19
18
  "browserslist": "> 0.5%, last 2 versions, not dead",
20
19
  "devDependencies": {
21
20
  "ava": "^6.1.3",
22
- "axios": "^1.7.2",
21
+ "axios": "^1.7.5",
23
22
  "canvas": "^2.11.2",
24
23
  "dotenv": "^16.4.5",
25
24
  "fluent-ffmpeg": "^2.1.3",
26
25
  "gifencoder": "^2.0.1",
27
26
  "pixelmatch": "^6.0.0",
28
27
  "pngjs": "^7.0.0",
29
- "polotno": "^2.11.5",
28
+ "polotno": "^2.12.2",
30
29
  "react": "^18.3.1",
31
30
  "react-dom": "^18.3.1",
32
- "vite": "^5.3.4"
31
+ "vite": "^5.4.2"
33
32
  },
34
33
  "author": "Anton Lavrenov",
35
34
  "license": "MIT",
36
35
  "dependencies": {
37
- "@sparticuz/chromium": "126.0.0",
38
- "puppeteer": "22.13.0",
39
- "puppeteer-core": "22.13.0",
36
+ "@sparticuz/chromium": "127.0.0",
37
+ "puppeteer": "23.1.1",
38
+ "puppeteer-core": "23.1.1",
40
39
  "tmp": "^0.2.3"
41
40
  },
42
41
  "bugs": {
package/video-parallel.js CHANGED
@@ -153,11 +153,10 @@ module.exports.jsonToVideo = async function jsonToVideo(
153
153
  chunks.push(frames.slice(i, i + chunkSize));
154
154
  }
155
155
 
156
+ let lastTime = 0;
156
157
  const pages = json.pages.map((p, index) => {
157
- const previousPage = json.pages[index - 1];
158
- const startTime = previousPage
159
- ? previousPage.startTime + previousPage.duration
160
- : 0;
158
+ const startTime = lastTime;
159
+ lastTime = startTime + p.duration;
161
160
  return {
162
161
  id: p.id,
163
162
  startTime,
@@ -171,16 +170,19 @@ module.exports.jsonToVideo = async function jsonToVideo(
171
170
  chunks.map(async (chunk, chunkIndex) => {
172
171
  const instance = typeof inst === 'function' ? await inst() : inst;
173
172
  const page = await instance.createPage();
173
+ await page.evaluate(() => {
174
+ if (window.config?.onLoadError) {
175
+ window.config.onLoadError((error) => {
176
+ window._polotnoError = error;
177
+ });
178
+ } else {
179
+ console.error(
180
+ 'onLoadError function is not defined in the client. Error handling will not work.'
181
+ );
182
+ }
183
+ });
174
184
  page.setDefaultNavigationTimeout(60000); // Increase timeout to 60 seconds
175
185
 
176
- await page.evaluate(async (json) => {
177
- store.loadJSON(json);
178
- await store.waitLoading();
179
- await new Promise((resolve) => {
180
- setTimeout(resolve, 100);
181
- });
182
- }, json);
183
-
184
186
  let lastPageIndex = -1;
185
187
  for (const frameIndex of chunk) {
186
188
  let currentTime = frameIndex * timePerFrame;
@@ -199,9 +201,23 @@ module.exports.jsonToVideo = async function jsonToVideo(
199
201
  );
200
202
  });
201
203
  if (storePageIndex !== lastPageIndex) {
204
+ await page.evaluate(async (json) => {
205
+ store.loadJSON(json);
206
+ await store.waitLoading();
207
+ await new Promise((resolve) => {
208
+ setTimeout(resolve, 100);
209
+ });
210
+ }, json);
202
211
  await page.evaluate(async (currentTime) => {
203
212
  store.setCurrentTime(currentTime);
213
+ store.checkActivePage();
214
+ store.activePage.set({
215
+ _rendering: true,
216
+ });
204
217
  await store.waitLoading();
218
+ await new Promise((resolve) => {
219
+ setTimeout(resolve, 100);
220
+ });
205
221
  if (window.config.unstable_setTextOverflow) {
206
222
  window.config.unstable_setTextOverflow('resize');
207
223
  } else {
@@ -209,7 +225,8 @@ module.exports.jsonToVideo = async function jsonToVideo(
209
225
  // 'Can not set text overflow mode. Define window.config.unstable_setTextOverflow function'
210
226
  // );
211
227
  }
212
- });
228
+ }, currentTime);
229
+ lastPageIndex = storePageIndex;
213
230
  }
214
231
  const startTime = Date.now();
215
232
  const dataURL = await page.evaluate(
@@ -233,6 +250,25 @@ module.exports.jsonToVideo = async function jsonToVideo(
233
250
  attrs || {},
234
251
  currentTime
235
252
  );
253
+ const error = await page.evaluate(() => window._polotnoError);
254
+ if (error) {
255
+ // clear error
256
+ await page.evaluate(() => {
257
+ window._polotnoError = null;
258
+ });
259
+ const message = error.toString();
260
+ const isFontError =
261
+ message.indexOf('Timeout for loading font') >= 0;
262
+ const skipError = isFontError && attrs.skipFontError;
263
+
264
+ const isImageError = message.indexOf('image ') >= 0;
265
+ const skipImageError = isImageError && attrs.skipImageError;
266
+
267
+ if (!skipError && !skipImageError) {
268
+ throw new Error(error);
269
+ }
270
+ }
271
+ // TODO: add error handling!!!!
236
272
  fs.writeFileSync(
237
273
  `${tempFolder.name}/${frameIndex}.jpeg`,
238
274
  dataURL.split(',')[1],