shiveshnavin commited on
Commit
5635fbe
·
1 Parent(s): 59d8ec1

Add bubble fullscreenre

Browse files
render-server.js CHANGED
@@ -1,5 +1,5 @@
1
  import app from './app.js';
2
- let port = process.env.PORT || 8083
3
  import Bubble from './utils/bubble/Bubble.js';
4
  import express from 'express';
5
  import { createServer } from 'http';
 
1
  import app from './app.js';
2
+ let port = process.env.PORT || 8089
3
  import Bubble from './utils/bubble/Bubble.js';
4
  import express from 'express';
5
  import { createServer } from 'http';
utils/bubble/Bubble.js CHANGED
@@ -334,22 +334,32 @@ class BubbleMaker {
334
 
335
  const imgExts = ['.png', '.jpg', '.jpeg', '.webp', '.bmp', '.gif'];
336
  const isImageFile = imgExts.includes(path.extname(overlayPath).toLowerCase());
337
- const padX = extra.paddingX || 5;
338
- const padY = extra.paddingY || 5;
339
  let ow = null, oh = null;
340
  if (extra.size === 'half') ow = Math.round(vw * 0.45);
341
  else if (extra.size !== 'full') ow = Math.round(vw * 0.30);
342
 
343
  let overlayMeta;
344
  try { overlayMeta = await FFMpegUtils.getMediaMetadata(overlayPath); } catch (e) { overlayMeta = null; }
 
 
 
345
  if (extra.size === 'full') {
346
- const maxW = Math.max(1, Math.round(vw * (1 - 2 * padX / 100)));
347
- ow = maxW;
348
  if (overlayMeta && overlayMeta.video && overlayMeta.video.width && overlayMeta.video.height) {
349
- const ar = overlayMeta.video.width / overlayMeta.video.height;
350
- oh = Math.max(1, Math.round(ow / ar));
 
 
 
 
 
 
351
  } else {
352
- oh = Math.max(1, Math.round(vh * (1 - 2 * padY / 100)));
 
353
  }
354
  } else if (overlayMeta && overlayMeta.video && overlayMeta.video.width && overlayMeta.video.height) {
355
  const ar = overlayMeta.video.width / overlayMeta.video.height;
@@ -386,7 +396,14 @@ class BubbleMaker {
386
  : `-i "${overlayPath}"`;
387
  inputs.push(overlayFlag);
388
 
389
- let scalePart = `[${inputIndex}:v]scale=${ow}:${oh},format=rgba`;
 
 
 
 
 
 
 
390
  if (isFade) scalePart += `,fade=t=in:st=${from}:d=${animDur}:alpha=1,fade=t=out:st=${fadeOut}:d=${animDur}:alpha=1`;
391
  scalePart += `[ov${inputIndex}]`;
392
  filterParts.push(scalePart);
@@ -423,8 +440,8 @@ class BubbleMaker {
423
  if (isMedia) {
424
  const imgExts = ['.png', '.jpg', '.jpeg', '.webp', '.bmp', '.gif'];
425
  const isImageFile = imgExts.includes(path.extname(overlayPath).toLowerCase());
426
- const padX = extra.paddingX || 5;
427
- const padY = extra.paddingY || 5;
428
  let ow = null, oh = null;
429
  if (extra.size === 'half') ow = Math.round(vw * 0.45);
430
  else if (extra.size !== 'full') ow = Math.round(vw * 0.30);
@@ -475,7 +492,14 @@ class BubbleMaker {
475
  ? (mainDuration > 0 ? `-loop 1 -t ${mainDuration} -i "${overlayPath}"` : `-loop 1 -i "${overlayPath}"`)
476
  : `-i "${overlayPath}"`;
477
 
478
- let overlayFilter = `[1:v]scale=${ow}:${oh},format=rgba`;
 
 
 
 
 
 
 
479
  if (isFade) overlayFilter += `,fade=t=in:st=${from}:d=${animDur}:alpha=1,fade=t=out:st=${fadeOut}:d=${animDur}:alpha=1`;
480
  overlayFilter += `[ov];[0:v][ov]overlay=${xExpr}:${yExpr}:enable='between(t,${from},${to})'[vout]`;
481
 
@@ -487,8 +511,8 @@ class BubbleMaker {
487
  const fontColor = t.fontColor || '#FFFFFF';
488
  const posX = extra.positionX || 'center';
489
  const posY = extra.positionY || 'center';
490
- const padX = extra.paddingX || 5;
491
- const padY = extra.paddingY || 5;
492
 
493
  let fontfilePath = null;
494
  if (t.fontName) {
 
334
 
335
  const imgExts = ['.png', '.jpg', '.jpeg', '.webp', '.bmp', '.gif'];
336
  const isImageFile = imgExts.includes(path.extname(overlayPath).toLowerCase());
337
+ const padX = typeof extra.paddingX === 'number' ? extra.paddingX : 5;
338
+ const padY = typeof extra.paddingY === 'number' ? extra.paddingY : 5;
339
  let ow = null, oh = null;
340
  if (extra.size === 'half') ow = Math.round(vw * 0.45);
341
  else if (extra.size !== 'full') ow = Math.round(vw * 0.30);
342
 
343
  let overlayMeta;
344
  try { overlayMeta = await FFMpegUtils.getMediaMetadata(overlayPath); } catch (e) { overlayMeta = null; }
345
+ let cropOverlay = false;
346
+ let scaledW = null;
347
+ let scaledH = null;
348
  if (extra.size === 'full') {
349
+ const targetW = Math.max(1, Math.round(vw * (1 - 2 * padX / 100)));
350
+ const targetH = Math.max(1, Math.round(vh * (1 - 2 * padY / 100)));
351
  if (overlayMeta && overlayMeta.video && overlayMeta.video.width && overlayMeta.video.height) {
352
+ const srcW = overlayMeta.video.width;
353
+ const srcH = overlayMeta.video.height;
354
+ const scaleFactor = Math.max(targetW / srcW, targetH / srcH);
355
+ scaledW = Math.max(1, Math.round(srcW * scaleFactor));
356
+ scaledH = Math.max(1, Math.round(srcH * scaleFactor));
357
+ ow = targetW;
358
+ oh = targetH;
359
+ cropOverlay = true;
360
  } else {
361
+ ow = targetW;
362
+ oh = targetH;
363
  }
364
  } else if (overlayMeta && overlayMeta.video && overlayMeta.video.width && overlayMeta.video.height) {
365
  const ar = overlayMeta.video.width / overlayMeta.video.height;
 
396
  : `-i "${overlayPath}"`;
397
  inputs.push(overlayFlag);
398
 
399
+ let scalePart;
400
+ if (cropOverlay && scaledW && scaledH) {
401
+ const cropX = Math.max(0, Math.round((scaledW - ow) / 2));
402
+ const cropY = Math.max(0, Math.round((scaledH - oh) / 2));
403
+ scalePart = `[${inputIndex}:v]scale=${scaledW}:${scaledH},crop=${ow}:${oh}:${cropX}:${cropY},format=rgba`;
404
+ } else {
405
+ scalePart = `[${inputIndex}:v]scale=${ow}:${oh},format=rgba`;
406
+ }
407
  if (isFade) scalePart += `,fade=t=in:st=${from}:d=${animDur}:alpha=1,fade=t=out:st=${fadeOut}:d=${animDur}:alpha=1`;
408
  scalePart += `[ov${inputIndex}]`;
409
  filterParts.push(scalePart);
 
440
  if (isMedia) {
441
  const imgExts = ['.png', '.jpg', '.jpeg', '.webp', '.bmp', '.gif'];
442
  const isImageFile = imgExts.includes(path.extname(overlayPath).toLowerCase());
443
+ const padX = typeof extra.paddingX === 'number' ? extra.paddingX : 5;
444
+ const padY = typeof extra.paddingY === 'number' ? extra.paddingY : 5;
445
  let ow = null, oh = null;
446
  if (extra.size === 'half') ow = Math.round(vw * 0.45);
447
  else if (extra.size !== 'full') ow = Math.round(vw * 0.30);
 
492
  ? (mainDuration > 0 ? `-loop 1 -t ${mainDuration} -i "${overlayPath}"` : `-loop 1 -i "${overlayPath}"`)
493
  : `-i "${overlayPath}"`;
494
 
495
+ let overlayFilter;
496
+ if (cropOverlay && scaledW && scaledH) {
497
+ const cropX = Math.max(0, Math.round((scaledW - ow) / 2));
498
+ const cropY = Math.max(0, Math.round((scaledH - oh) / 2));
499
+ overlayFilter = `[1:v]scale=${scaledW}:${scaledH},crop=${ow}:${oh}:${cropX}:${cropY},format=rgba`;
500
+ } else {
501
+ overlayFilter = `[1:v]scale=${ow}:${oh},format=rgba`;
502
+ }
503
  if (isFade) overlayFilter += `,fade=t=in:st=${from}:d=${animDur}:alpha=1,fade=t=out:st=${fadeOut}:d=${animDur}:alpha=1`;
504
  overlayFilter += `[ov];[0:v][ov]overlay=${xExpr}:${yExpr}:enable='between(t,${from},${to})'[vout]`;
505
 
 
511
  const fontColor = t.fontColor || '#FFFFFF';
512
  const posX = extra.positionX || 'center';
513
  const posY = extra.positionY || 'center';
514
+ const padX = typeof extra.paddingX === 'number' ? extra.paddingX : 5;
515
+ const padY = typeof extra.paddingY === 'number' ? extra.paddingY : 5;
516
 
517
  let fontfilePath = null;
518
  if (t.fontName) {
utils/bubble/bubble-templates.js CHANGED
@@ -37,11 +37,11 @@ export const BaseBubbleTemplates = {
37
  durationSec: 0.1
38
  },
39
  bubbleExtra: {
40
- positionX: 'center',
41
- positionY: 'top',
42
  size: 'full', // | 'half' // useful for images and videos
43
- paddingX: 10, // number in percentage
44
- paddingY: 10 // number in percentage
45
  }
46
  }
47
  };
 
37
  durationSec: 0.1
38
  },
39
  bubbleExtra: {
40
+ positionX: 'full',
41
+ positionY: 'full',
42
  size: 'full', // | 'half' // useful for images and videos
43
+ paddingX: 0, // number in percentage
44
+ paddingY: 0 // number in percentage
45
  }
46
  }
47
  };
utils/bubble/layout.js CHANGED
@@ -1,13 +1,13 @@
1
  export function scaleTemplate(value, scale) {
2
  if (typeof value === 'number') return Math.round(value * scale);
3
- if (typeof value === 'string' && value.match(/^\d+(px)?$/)) return Math.round(parseInt(value,10) * scale);
4
  return value;
5
  }
6
 
7
  // compute overlay x,y from overlay width/height, extra positioning and video size
8
  export function computeXY(overlayW, overlayH, extra = {}, vw = 0, vh = 0) {
9
- const padX = extra.paddingX || 5;
10
- const padY = extra.paddingY || 5;
11
  const posX = extra.positionX || 'center';
12
  const posY = extra.positionY || 'center';
13
  let x = 0, y = 0;
 
1
  export function scaleTemplate(value, scale) {
2
  if (typeof value === 'number') return Math.round(value * scale);
3
+ if (typeof value === 'string' && value.match(/^\d+(px)?$/)) return Math.round(parseInt(value, 10) * scale);
4
  return value;
5
  }
6
 
7
  // compute overlay x,y from overlay width/height, extra positioning and video size
8
  export function computeXY(overlayW, overlayH, extra = {}, vw = 0, vh = 0) {
9
+ const padX = typeof extra.paddingX === 'number' ? extra.paddingX : 5;
10
+ const padY = typeof extra.paddingY === 'number' ? extra.paddingY : 5;
11
  const posX = extra.positionX || 'center';
12
  const posY = extra.positionY || 'center';
13
  let x = 0, y = 0;