vidpipe 1.0.0

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 (213) hide show
  1. package/README.md +243 -0
  2. package/assets/fonts/Montserrat-Bold.ttf +0 -0
  3. package/assets/fonts/Montserrat-Regular.ttf +0 -0
  4. package/assets/fonts/OFL.txt +93 -0
  5. package/dist/__tests__/agents.test.d.ts +2 -0
  6. package/dist/__tests__/agents.test.d.ts.map +1 -0
  7. package/dist/__tests__/agents.test.js +434 -0
  8. package/dist/__tests__/agents.test.js.map +1 -0
  9. package/dist/__tests__/aspectRatio.test.d.ts +2 -0
  10. package/dist/__tests__/aspectRatio.test.d.ts.map +1 -0
  11. package/dist/__tests__/aspectRatio.test.js +406 -0
  12. package/dist/__tests__/aspectRatio.test.js.map +1 -0
  13. package/dist/__tests__/captionGenerator.test.d.ts +2 -0
  14. package/dist/__tests__/captionGenerator.test.d.ts.map +1 -0
  15. package/dist/__tests__/captionGenerator.test.js +435 -0
  16. package/dist/__tests__/captionGenerator.test.js.map +1 -0
  17. package/dist/__tests__/config.test.d.ts +2 -0
  18. package/dist/__tests__/config.test.d.ts.map +1 -0
  19. package/dist/__tests__/config.test.js +81 -0
  20. package/dist/__tests__/config.test.js.map +1 -0
  21. package/dist/__tests__/faceDetection.test.d.ts +2 -0
  22. package/dist/__tests__/faceDetection.test.d.ts.map +1 -0
  23. package/dist/__tests__/faceDetection.test.js +372 -0
  24. package/dist/__tests__/faceDetection.test.js.map +1 -0
  25. package/dist/__tests__/ffmpegTools.test.d.ts +2 -0
  26. package/dist/__tests__/ffmpegTools.test.d.ts.map +1 -0
  27. package/dist/__tests__/ffmpegTools.test.js +464 -0
  28. package/dist/__tests__/ffmpegTools.test.js.map +1 -0
  29. package/dist/__tests__/integration/captionBurn.test.d.ts +2 -0
  30. package/dist/__tests__/integration/captionBurn.test.d.ts.map +1 -0
  31. package/dist/__tests__/integration/captionBurn.test.js +103 -0
  32. package/dist/__tests__/integration/captionBurn.test.js.map +1 -0
  33. package/dist/__tests__/integration/clipComposite.test.d.ts +2 -0
  34. package/dist/__tests__/integration/clipComposite.test.d.ts.map +1 -0
  35. package/dist/__tests__/integration/clipComposite.test.js +56 -0
  36. package/dist/__tests__/integration/clipComposite.test.js.map +1 -0
  37. package/dist/__tests__/integration/faceDetection.test.d.ts +2 -0
  38. package/dist/__tests__/integration/faceDetection.test.d.ts.map +1 -0
  39. package/dist/__tests__/integration/faceDetection.test.js +85 -0
  40. package/dist/__tests__/integration/faceDetection.test.js.map +1 -0
  41. package/dist/__tests__/integration/ffmpegPipeline.test.d.ts +2 -0
  42. package/dist/__tests__/integration/ffmpegPipeline.test.d.ts.map +1 -0
  43. package/dist/__tests__/integration/ffmpegPipeline.test.js +88 -0
  44. package/dist/__tests__/integration/ffmpegPipeline.test.js.map +1 -0
  45. package/dist/__tests__/integration/fixture.d.ts +19 -0
  46. package/dist/__tests__/integration/fixture.d.ts.map +1 -0
  47. package/dist/__tests__/integration/fixture.js +112 -0
  48. package/dist/__tests__/integration/fixture.js.map +1 -0
  49. package/dist/__tests__/integration/fixture.test.d.ts +2 -0
  50. package/dist/__tests__/integration/fixture.test.d.ts.map +1 -0
  51. package/dist/__tests__/integration/fixture.test.js +27 -0
  52. package/dist/__tests__/integration/fixture.test.js.map +1 -0
  53. package/dist/__tests__/integration/realCaptions.test.d.ts +2 -0
  54. package/dist/__tests__/integration/realCaptions.test.d.ts.map +1 -0
  55. package/dist/__tests__/integration/realCaptions.test.js +226 -0
  56. package/dist/__tests__/integration/realCaptions.test.js.map +1 -0
  57. package/dist/__tests__/integration/realPipeline.test.d.ts +2 -0
  58. package/dist/__tests__/integration/realPipeline.test.d.ts.map +1 -0
  59. package/dist/__tests__/integration/realPipeline.test.js +210 -0
  60. package/dist/__tests__/integration/realPipeline.test.js.map +1 -0
  61. package/dist/__tests__/integration/silenceRemoval.test.d.ts +2 -0
  62. package/dist/__tests__/integration/silenceRemoval.test.d.ts.map +1 -0
  63. package/dist/__tests__/integration/silenceRemoval.test.js +93 -0
  64. package/dist/__tests__/integration/silenceRemoval.test.js.map +1 -0
  65. package/dist/__tests__/pipeline.test.d.ts +2 -0
  66. package/dist/__tests__/pipeline.test.d.ts.map +1 -0
  67. package/dist/__tests__/pipeline.test.js +434 -0
  68. package/dist/__tests__/pipeline.test.js.map +1 -0
  69. package/dist/__tests__/services.test.d.ts +2 -0
  70. package/dist/__tests__/services.test.d.ts.map +1 -0
  71. package/dist/__tests__/services.test.js +655 -0
  72. package/dist/__tests__/services.test.js.map +1 -0
  73. package/dist/__tests__/silenceRemoval.test.d.ts +2 -0
  74. package/dist/__tests__/silenceRemoval.test.d.ts.map +1 -0
  75. package/dist/__tests__/silenceRemoval.test.js +266 -0
  76. package/dist/__tests__/silenceRemoval.test.js.map +1 -0
  77. package/dist/__tests__/singlePassEdit.test.d.ts +2 -0
  78. package/dist/__tests__/singlePassEdit.test.d.ts.map +1 -0
  79. package/dist/__tests__/singlePassEdit.test.js +321 -0
  80. package/dist/__tests__/singlePassEdit.test.js.map +1 -0
  81. package/dist/__tests__/smoke.test.d.ts +2 -0
  82. package/dist/__tests__/smoke.test.d.ts.map +1 -0
  83. package/dist/__tests__/smoke.test.js +8 -0
  84. package/dist/__tests__/smoke.test.js.map +1 -0
  85. package/dist/__tests__/utilities.test.d.ts +2 -0
  86. package/dist/__tests__/utilities.test.d.ts.map +1 -0
  87. package/dist/__tests__/utilities.test.js +268 -0
  88. package/dist/__tests__/utilities.test.js.map +1 -0
  89. package/dist/agents/BaseAgent.d.ts +52 -0
  90. package/dist/agents/BaseAgent.d.ts.map +1 -0
  91. package/dist/agents/BaseAgent.js +108 -0
  92. package/dist/agents/BaseAgent.js.map +1 -0
  93. package/dist/agents/BlogAgent.d.ts +3 -0
  94. package/dist/agents/BlogAgent.d.ts.map +1 -0
  95. package/dist/agents/BlogAgent.js +163 -0
  96. package/dist/agents/BlogAgent.js.map +1 -0
  97. package/dist/agents/ChapterAgent.d.ts +11 -0
  98. package/dist/agents/ChapterAgent.d.ts.map +1 -0
  99. package/dist/agents/ChapterAgent.js +191 -0
  100. package/dist/agents/ChapterAgent.js.map +1 -0
  101. package/dist/agents/MediumVideoAgent.d.ts +3 -0
  102. package/dist/agents/MediumVideoAgent.d.ts.map +1 -0
  103. package/dist/agents/MediumVideoAgent.js +219 -0
  104. package/dist/agents/MediumVideoAgent.js.map +1 -0
  105. package/dist/agents/ShortsAgent.d.ts +3 -0
  106. package/dist/agents/ShortsAgent.d.ts.map +1 -0
  107. package/dist/agents/ShortsAgent.js +243 -0
  108. package/dist/agents/ShortsAgent.js.map +1 -0
  109. package/dist/agents/SilenceRemovalAgent.d.ts +9 -0
  110. package/dist/agents/SilenceRemovalAgent.d.ts.map +1 -0
  111. package/dist/agents/SilenceRemovalAgent.js +208 -0
  112. package/dist/agents/SilenceRemovalAgent.js.map +1 -0
  113. package/dist/agents/SocialMediaAgent.d.ts +4 -0
  114. package/dist/agents/SocialMediaAgent.d.ts.map +1 -0
  115. package/dist/agents/SocialMediaAgent.js +248 -0
  116. package/dist/agents/SocialMediaAgent.js.map +1 -0
  117. package/dist/agents/SummaryAgent.d.ts +11 -0
  118. package/dist/agents/SummaryAgent.d.ts.map +1 -0
  119. package/dist/agents/SummaryAgent.js +333 -0
  120. package/dist/agents/SummaryAgent.js.map +1 -0
  121. package/dist/config/brand.d.ts +29 -0
  122. package/dist/config/brand.d.ts.map +1 -0
  123. package/dist/config/brand.js +83 -0
  124. package/dist/config/brand.js.map +1 -0
  125. package/dist/config/environment.d.ts +36 -0
  126. package/dist/config/environment.d.ts.map +1 -0
  127. package/dist/config/environment.js +44 -0
  128. package/dist/config/environment.js.map +1 -0
  129. package/dist/config/logger.d.ts +5 -0
  130. package/dist/config/logger.d.ts.map +1 -0
  131. package/dist/config/logger.js +13 -0
  132. package/dist/config/logger.js.map +1 -0
  133. package/dist/index.d.ts +2 -0
  134. package/dist/index.d.ts.map +1 -0
  135. package/dist/index.js +135 -0
  136. package/dist/index.js.map +1 -0
  137. package/dist/pipeline.d.ts +57 -0
  138. package/dist/pipeline.d.ts.map +1 -0
  139. package/dist/pipeline.js +287 -0
  140. package/dist/pipeline.js.map +1 -0
  141. package/dist/services/captionGeneration.d.ts +7 -0
  142. package/dist/services/captionGeneration.d.ts.map +1 -0
  143. package/dist/services/captionGeneration.js +29 -0
  144. package/dist/services/captionGeneration.js.map +1 -0
  145. package/dist/services/fileWatcher.d.ts +19 -0
  146. package/dist/services/fileWatcher.d.ts.map +1 -0
  147. package/dist/services/fileWatcher.js +120 -0
  148. package/dist/services/fileWatcher.js.map +1 -0
  149. package/dist/services/gitOperations.d.ts +3 -0
  150. package/dist/services/gitOperations.d.ts.map +1 -0
  151. package/dist/services/gitOperations.js +43 -0
  152. package/dist/services/gitOperations.js.map +1 -0
  153. package/dist/services/socialPosting.d.ts +38 -0
  154. package/dist/services/socialPosting.d.ts.map +1 -0
  155. package/dist/services/socialPosting.js +102 -0
  156. package/dist/services/socialPosting.js.map +1 -0
  157. package/dist/services/transcription.d.ts +3 -0
  158. package/dist/services/transcription.d.ts.map +1 -0
  159. package/dist/services/transcription.js +100 -0
  160. package/dist/services/transcription.js.map +1 -0
  161. package/dist/services/videoIngestion.d.ts +3 -0
  162. package/dist/services/videoIngestion.d.ts.map +1 -0
  163. package/dist/services/videoIngestion.js +103 -0
  164. package/dist/services/videoIngestion.js.map +1 -0
  165. package/dist/tools/captions/captionGenerator.d.ts +84 -0
  166. package/dist/tools/captions/captionGenerator.d.ts.map +1 -0
  167. package/dist/tools/captions/captionGenerator.js +390 -0
  168. package/dist/tools/captions/captionGenerator.js.map +1 -0
  169. package/dist/tools/ffmpeg/aspectRatio.d.ts +101 -0
  170. package/dist/tools/ffmpeg/aspectRatio.d.ts.map +1 -0
  171. package/dist/tools/ffmpeg/aspectRatio.js +338 -0
  172. package/dist/tools/ffmpeg/aspectRatio.js.map +1 -0
  173. package/dist/tools/ffmpeg/audioExtraction.d.ts +16 -0
  174. package/dist/tools/ffmpeg/audioExtraction.d.ts.map +1 -0
  175. package/dist/tools/ffmpeg/audioExtraction.js +86 -0
  176. package/dist/tools/ffmpeg/audioExtraction.js.map +1 -0
  177. package/dist/tools/ffmpeg/captionBurning.d.ts +8 -0
  178. package/dist/tools/ffmpeg/captionBurning.d.ts.map +1 -0
  179. package/dist/tools/ffmpeg/captionBurning.js +71 -0
  180. package/dist/tools/ffmpeg/captionBurning.js.map +1 -0
  181. package/dist/tools/ffmpeg/clipExtraction.d.ts +23 -0
  182. package/dist/tools/ffmpeg/clipExtraction.d.ts.map +1 -0
  183. package/dist/tools/ffmpeg/clipExtraction.js +178 -0
  184. package/dist/tools/ffmpeg/clipExtraction.js.map +1 -0
  185. package/dist/tools/ffmpeg/faceDetection.d.ts +127 -0
  186. package/dist/tools/ffmpeg/faceDetection.d.ts.map +1 -0
  187. package/dist/tools/ffmpeg/faceDetection.js +500 -0
  188. package/dist/tools/ffmpeg/faceDetection.js.map +1 -0
  189. package/dist/tools/ffmpeg/frameCapture.d.ts +10 -0
  190. package/dist/tools/ffmpeg/frameCapture.d.ts.map +1 -0
  191. package/dist/tools/ffmpeg/frameCapture.js +48 -0
  192. package/dist/tools/ffmpeg/frameCapture.js.map +1 -0
  193. package/dist/tools/ffmpeg/silenceDetection.d.ts +10 -0
  194. package/dist/tools/ffmpeg/silenceDetection.d.ts.map +1 -0
  195. package/dist/tools/ffmpeg/silenceDetection.js +55 -0
  196. package/dist/tools/ffmpeg/silenceDetection.js.map +1 -0
  197. package/dist/tools/ffmpeg/singlePassEdit.d.ts +25 -0
  198. package/dist/tools/ffmpeg/singlePassEdit.d.ts.map +1 -0
  199. package/dist/tools/ffmpeg/singlePassEdit.js +123 -0
  200. package/dist/tools/ffmpeg/singlePassEdit.js.map +1 -0
  201. package/dist/tools/search/exaClient.d.ts +8 -0
  202. package/dist/tools/search/exaClient.d.ts.map +1 -0
  203. package/dist/tools/search/exaClient.js +38 -0
  204. package/dist/tools/search/exaClient.js.map +1 -0
  205. package/dist/tools/whisper/whisperClient.d.ts +3 -0
  206. package/dist/tools/whisper/whisperClient.d.ts.map +1 -0
  207. package/dist/tools/whisper/whisperClient.js +77 -0
  208. package/dist/tools/whisper/whisperClient.js.map +1 -0
  209. package/dist/types/index.d.ts +305 -0
  210. package/dist/types/index.d.ts.map +1 -0
  211. package/dist/types/index.js +44 -0
  212. package/dist/types/index.js.map +1 -0
  213. package/package.json +63 -0
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import path from 'path';
3
+ import { setupFixtures, cleanupFixtures, isFFmpegAvailable, fileExistsWithSize, getVideoDuration, } from './fixture.js';
4
+ import { extractClip, extractCompositeClip, extractCompositeClipWithTransitions } from '../../tools/ffmpeg/clipExtraction.js';
5
+ const ffmpegOk = await isFFmpegAvailable();
6
+ describe.skipIf(!ffmpegOk)('Clip Extraction & Composite', () => {
7
+ let fix;
8
+ beforeAll(async () => { fix = await setupFixtures(); }, 30000);
9
+ afterAll(async () => { await cleanupFixtures(); });
10
+ it('extracts a single clip with correct duration', async () => {
11
+ const output = path.join(fix.dir, 'clip-single.mp4');
12
+ await extractClip(fix.videoPath, 0.5, 2.5, output, 0.5);
13
+ const { exists, size } = await fileExistsWithSize(output);
14
+ expect(exists).toBe(true);
15
+ expect(size).toBeGreaterThan(0);
16
+ const duration = await getVideoDuration(output);
17
+ expect(duration).toBeCloseTo(3, 0); // 0.0–3.0 = 3s (start buffered to 0, end buffered to 3.0)
18
+ }, 90000);
19
+ it('concatenates multiple segments into a composite clip', async () => {
20
+ const output = path.join(fix.dir, 'clip-composite.mp4');
21
+ const segments = [
22
+ { start: 0.5, end: 1.5, description: 'segment 1' },
23
+ { start: 3.0, end: 4.0, description: 'segment 2' },
24
+ ];
25
+ await extractCompositeClip(fix.videoPath, segments, output, 0.5);
26
+ const { exists, size } = await fileExistsWithSize(output);
27
+ expect(exists).toBe(true);
28
+ expect(size).toBeGreaterThan(0);
29
+ const duration = await getVideoDuration(output);
30
+ // Segment 1: buffered 0.0–2.0 = 2s, Segment 2: buffered 2.5–4.5 = 2s → ~4s total
31
+ // But task says "roughly 2-3s" with segments [0.5-1.5] and [3.0-4.0] + 0.5 buffer
32
+ // Actual: seg1 = max(0, 0.5-0.5)=0.0 to 1.5+0.5=2.0 → 2s; seg2 = 3.0-0.5=2.5 to 4.0+0.5=4.5 → 2s; total ~4s
33
+ expect(duration).toBeCloseTo(4, 0);
34
+ }, 90000);
35
+ it('composites segments with xfade transitions', async () => {
36
+ const output = path.join(fix.dir, 'clip-xfade.mp4');
37
+ const segments = [
38
+ { start: 0.0, end: 1.0, description: 'seg a' },
39
+ { start: 2.0, end: 3.0, description: 'seg b' },
40
+ { start: 4.0, end: 5.0, description: 'seg c' },
41
+ ];
42
+ const transitionDuration = 0.3;
43
+ const buffer = 0.5;
44
+ await extractCompositeClipWithTransitions(fix.videoPath, segments, output, transitionDuration, buffer);
45
+ const { exists, size } = await fileExistsWithSize(output);
46
+ expect(exists).toBe(true);
47
+ expect(size).toBeGreaterThan(0);
48
+ // Each segment with 0.5 buffer: seg0=0.0-1.5(1.5s), seg1=1.5-3.5(2s), seg2=3.5-5.0(clamped, ~1.5s but source is 5s so 3.5-5.5→5.0 end = ~1.5s)
49
+ // Actually: seg0 = max(0, 0-0.5)=0 to 1+0.5=1.5 → 1.5s; seg1 = 2-0.5=1.5 to 3+0.5=3.5 → 2s; seg2 = 4-0.5=3.5 to 5+0.5=5.5 → ~1.5-2s (source may clamp)
50
+ // Total before transitions: ~5-5.5s, minus 2×0.3=0.6 → ~4.4-4.9s
51
+ const duration = await getVideoDuration(output);
52
+ expect(duration).toBeGreaterThan(3);
53
+ expect(duration).toBeLessThan(7);
54
+ }, 90000);
55
+ });
56
+ //# sourceMappingURL=clipComposite.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipComposite.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/clipComposite.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=faceDetection.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faceDetection.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/faceDetection.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { execFile } from 'child_process';
5
+ import { promisify } from 'util';
6
+ import { promises as fs } from 'fs';
7
+ import { isFFmpegAvailable } from './fixture.js';
8
+ import { detectWebcamRegion, isSkinTone, calculateCornerConfidence } from '../../tools/ffmpeg/faceDetection.js';
9
+ const execFileAsync = promisify(execFile);
10
+ const ffmpegPath = process.env.FFMPEG_PATH || 'ffmpeg';
11
+ const ffmpegOk = await isFFmpegAvailable();
12
+ describe.skipIf(!ffmpegOk)('faceDetection integration', { timeout: 60_000 }, () => {
13
+ let videoPath;
14
+ let tempDir;
15
+ beforeAll(async () => {
16
+ // Create a dedicated longer video (10s) to avoid edge-case frame extraction at exact duration
17
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vantr-face-integ-'));
18
+ videoPath = path.join(tempDir, 'test-face.mp4');
19
+ await execFileAsync(ffmpegPath, [
20
+ '-y',
21
+ '-f', 'lavfi', '-i', 'testsrc=duration=10:size=640x480:rate=25',
22
+ '-f', 'lavfi', '-i', 'sine=frequency=440:duration=10',
23
+ '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p',
24
+ '-c:a', 'aac', '-b:a', '64k',
25
+ '-shortest',
26
+ videoPath,
27
+ ], { timeout: 30_000 });
28
+ });
29
+ afterAll(async () => {
30
+ await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
31
+ });
32
+ // ── 1. No face detected on synthetic video ─────────────────────────────────
33
+ it('returns null for synthetic test video with no webcam overlay', async () => {
34
+ const result = await detectWebcamRegion(videoPath);
35
+ expect(result).toBeNull();
36
+ });
37
+ // ── 2. Pure function validation with real data ─────────────────────────────
38
+ describe('isSkinTone', () => {
39
+ it('detects typical skin-tone RGB values', () => {
40
+ // Light skin tone
41
+ expect(isSkinTone(200, 150, 120)).toBe(true);
42
+ // Medium skin tone
43
+ expect(isSkinTone(180, 120, 80)).toBe(true);
44
+ });
45
+ it('rejects non-skin-tone RGB values', () => {
46
+ // Pure blue
47
+ expect(isSkinTone(0, 0, 255)).toBe(false);
48
+ // Pure green
49
+ expect(isSkinTone(0, 255, 0)).toBe(false);
50
+ // White
51
+ expect(isSkinTone(255, 255, 255)).toBe(false);
52
+ // Black
53
+ expect(isSkinTone(0, 0, 0)).toBe(false);
54
+ });
55
+ });
56
+ describe('calculateCornerConfidence', () => {
57
+ it('returns 0 for empty scores', () => {
58
+ expect(calculateCornerConfidence([])).toBe(0);
59
+ });
60
+ it('returns 0 when all scores are zero', () => {
61
+ expect(calculateCornerConfidence([0, 0, 0, 0, 0])).toBe(0);
62
+ });
63
+ it('returns a value between 0 and 1 for mixed scores', () => {
64
+ const confidence = calculateCornerConfidence([0.05, 0.1, 0, 0.08, 0]);
65
+ expect(confidence).toBeGreaterThan(0);
66
+ expect(confidence).toBeLessThanOrEqual(1);
67
+ });
68
+ it('returns higher confidence for consistently high scores', () => {
69
+ const low = calculateCornerConfidence([0.01, 0, 0.02, 0, 0]);
70
+ const high = calculateCornerConfidence([0.1, 0.12, 0.09, 0.11, 0.1]);
71
+ expect(high).toBeGreaterThan(low);
72
+ });
73
+ });
74
+ // ── 3. Temp cleanup ────────────────────────────────────────────────────────
75
+ it('cleans up face-detect-* temp directories after detection', async () => {
76
+ const tmpBase = os.tmpdir();
77
+ // Snapshot existing face-detect dirs before running
78
+ const before = (await fs.readdir(tmpBase)).filter(d => d.startsWith('face-detect-'));
79
+ await detectWebcamRegion(videoPath);
80
+ const after = (await fs.readdir(tmpBase)).filter(d => d.startsWith('face-detect-'));
81
+ // No new face-detect directories should remain
82
+ expect(after.length).toBeLessThanOrEqual(before.length);
83
+ });
84
+ });
85
+ //# sourceMappingURL=faceDetection.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faceDetection.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/faceDetection.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ffmpegPipeline.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpegPipeline.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/ffmpegPipeline.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import path from 'path';
3
+ import { setupFixtures, cleanupFixtures, isFFmpegAvailable, fileExistsWithSize, getVideoDuration, } from './fixture.js';
4
+ import { extractAudio } from '../../tools/ffmpeg/audioExtraction.js';
5
+ import { detectSilence } from '../../tools/ffmpeg/silenceDetection.js';
6
+ import { captureFrame, captureFrames } from '../../tools/ffmpeg/frameCapture.js';
7
+ import { extractClip } from '../../tools/ffmpeg/clipExtraction.js';
8
+ const ffmpegOk = await isFFmpegAvailable();
9
+ describe.skipIf(!ffmpegOk)('FFmpeg Pipeline Integration', () => {
10
+ let fix;
11
+ beforeAll(async () => { fix = await setupFixtures(); }, 30000);
12
+ afterAll(async () => { await cleanupFixtures(); });
13
+ // ── Audio Extraction ──────────────────────────────────────────────
14
+ describe('Audio Extraction', () => {
15
+ it('extracts MP3 audio with non-zero size', async () => {
16
+ const out = path.join(fix.dir, 'output-audio.mp3');
17
+ await extractAudio(fix.videoPath, out);
18
+ const { exists, size } = await fileExistsWithSize(out);
19
+ expect(exists).toBe(true);
20
+ expect(size).toBeGreaterThan(0);
21
+ });
22
+ it('extracted audio duration roughly matches video duration', async () => {
23
+ const out = path.join(fix.dir, 'output-audio-dur.mp3');
24
+ await extractAudio(fix.videoPath, out);
25
+ const videoDur = await getVideoDuration(fix.videoPath);
26
+ const audioDur = await getVideoDuration(out);
27
+ expect(audioDur).toBeCloseTo(videoDur, 0);
28
+ });
29
+ });
30
+ // ── Silence Detection ─────────────────────────────────────────────
31
+ describe('Silence Detection', () => {
32
+ it('returns an array for continuous sine-wave audio', async () => {
33
+ const regions = await detectSilence(fix.audioPath, 0.3, '-50dB');
34
+ expect(Array.isArray(regions)).toBe(true);
35
+ });
36
+ it('detects minimal or no silence in a sine wave', async () => {
37
+ const regions = await detectSilence(fix.audioPath, 0.3, '-50dB');
38
+ // Continuous 440 Hz sine wave should have very little silence
39
+ expect(regions.length).toBeLessThanOrEqual(1);
40
+ });
41
+ });
42
+ // ── Frame Capture ─────────────────────────────────────────────────
43
+ describe('Frame Capture', () => {
44
+ it('captures a single frame at t=1.0s', async () => {
45
+ const out = path.join(fix.dir, 'output-frame-1s.png');
46
+ await captureFrame(fix.videoPath, 1.0, out);
47
+ const { exists, size } = await fileExistsWithSize(out);
48
+ expect(exists).toBe(true);
49
+ expect(size).toBeGreaterThan(0);
50
+ });
51
+ it('captures a frame at t=0.0s (start)', async () => {
52
+ const out = path.join(fix.dir, 'output-frame-0s.png');
53
+ await captureFrame(fix.videoPath, 0.0, out);
54
+ const { exists, size } = await fileExistsWithSize(out);
55
+ expect(exists).toBe(true);
56
+ expect(size).toBeGreaterThan(0);
57
+ });
58
+ it('captures multiple frames at specified timestamps', async () => {
59
+ const outDir = path.join(fix.dir, 'output-frames');
60
+ const results = await captureFrames(fix.videoPath, [0.5, 1.5, 2.5], outDir);
61
+ expect(results).toHaveLength(3);
62
+ for (const filePath of results) {
63
+ const { exists, size } = await fileExistsWithSize(filePath);
64
+ expect(exists).toBe(true);
65
+ expect(size).toBeGreaterThan(0);
66
+ }
67
+ });
68
+ });
69
+ // ── Clip Extraction ───────────────────────────────────────────────
70
+ describe('Clip Extraction', () => {
71
+ it('extracts a clip from 1.0s to 3.0s', async () => {
72
+ const out = path.join(fix.dir, 'output-clip.mp4');
73
+ await extractClip(fix.videoPath, 1.0, 3.0, out, 0);
74
+ const { exists, size } = await fileExistsWithSize(out);
75
+ expect(exists).toBe(true);
76
+ expect(size).toBeGreaterThan(0);
77
+ });
78
+ it('clip duration is approximately 2s', async () => {
79
+ const out = path.join(fix.dir, 'output-clip-dur.mp4');
80
+ await extractClip(fix.videoPath, 1.0, 3.0, out, 0);
81
+ const dur = await getVideoDuration(out);
82
+ // Stream copy (-c copy) snaps to keyframes, so duration may exceed requested range
83
+ expect(dur).toBeGreaterThanOrEqual(1.5);
84
+ expect(dur).toBeLessThanOrEqual(4.0);
85
+ });
86
+ });
87
+ });
88
+ //# sourceMappingURL=ffmpegPipeline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpegPipeline.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/ffmpegPipeline.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import 'dotenv/config';
2
+ export interface TestFixtures {
3
+ dir: string;
4
+ videoPath: string;
5
+ audioPath: string;
6
+ transcriptPath: string;
7
+ assPath: string;
8
+ }
9
+ export declare function isFFmpegAvailable(): Promise<boolean>;
10
+ export declare function setupFixtures(): Promise<TestFixtures>;
11
+ export declare function cleanupFixtures(): Promise<void>;
12
+ /** Get video duration via ffprobe */
13
+ export declare function getVideoDuration(videoPath: string): Promise<number>;
14
+ /** Check if file exists and has non-zero size */
15
+ export declare function fileExistsWithSize(filePath: string): Promise<{
16
+ exists: boolean;
17
+ size: number;
18
+ }>;
19
+ //# sourceMappingURL=fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/fixture.ts"],"names":[],"mappings":"AAKA,OAAO,eAAe,CAAC;AAOvB,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAK1D;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,YAAY,CAAC,CAyE3D;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAKrD;AAED,qCAAqC;AACrC,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKzE;AAED,iDAAiD;AACjD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAOrG"}
@@ -0,0 +1,112 @@
1
+ import { execFile } from 'child_process';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { promisify } from 'util';
6
+ import 'dotenv/config';
7
+ const execFileAsync = promisify(execFile);
8
+ const ffmpegPath = process.env.FFMPEG_PATH || 'ffmpeg';
9
+ const ffprobePath = process.env.FFPROBE_PATH || 'ffprobe';
10
+ let fixtures = null;
11
+ export async function isFFmpegAvailable() {
12
+ try {
13
+ await execFileAsync(ffmpegPath, ['-version']);
14
+ return true;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ export async function setupFixtures() {
21
+ if (fixtures)
22
+ return fixtures;
23
+ const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'vantr-integ-'));
24
+ const videoPath = path.join(dir, 'test.mp4');
25
+ const audioPath = path.join(dir, 'test.mp3');
26
+ const transcriptPath = path.join(dir, 'transcript.json');
27
+ const assPath = path.join(dir, 'captions.ass');
28
+ // Generate 5-second synthetic video: test pattern + sine wave audio
29
+ await execFileAsync(ffmpegPath, [
30
+ '-y',
31
+ '-f', 'lavfi', '-i', 'testsrc=duration=5:size=640x480:rate=25',
32
+ '-f', 'lavfi', '-i', 'sine=frequency=440:duration=5',
33
+ '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p',
34
+ '-c:a', 'aac', '-b:a', '64k',
35
+ '-shortest',
36
+ videoPath,
37
+ ], { timeout: 30000 });
38
+ // Extract audio
39
+ await execFileAsync(ffmpegPath, [
40
+ '-y', '-i', videoPath,
41
+ '-vn', '-acodec', 'libmp3lame', '-b:a', '64k',
42
+ audioPath,
43
+ ], { timeout: 15000 });
44
+ // Create mock transcript with word-level timestamps
45
+ const transcript = {
46
+ text: 'Hello world this is a test of the caption system with multiple words',
47
+ language: 'english',
48
+ segments: [
49
+ { id: 0, start: 0.0, end: 2.0, text: 'Hello world this is a test' },
50
+ { id: 1, start: 2.5, end: 4.5, text: 'of the caption system with multiple words' },
51
+ ],
52
+ words: [
53
+ { word: 'Hello', start: 0.0, end: 0.3 },
54
+ { word: 'world', start: 0.4, end: 0.7 },
55
+ { word: 'this', start: 0.8, end: 1.0 },
56
+ { word: 'is', start: 1.1, end: 1.2 },
57
+ { word: 'a', start: 1.3, end: 1.4 },
58
+ { word: 'test', start: 1.5, end: 1.9 },
59
+ { word: 'of', start: 2.5, end: 2.6 },
60
+ { word: 'the', start: 2.7, end: 2.8 },
61
+ { word: 'caption', start: 2.9, end: 3.2 },
62
+ { word: 'system', start: 3.3, end: 3.6 },
63
+ { word: 'with', start: 3.7, end: 3.9 },
64
+ { word: 'multiple', start: 4.0, end: 4.2 },
65
+ { word: 'words', start: 4.3, end: 4.5 },
66
+ ],
67
+ };
68
+ await fs.writeFile(transcriptPath, JSON.stringify(transcript, null, 2));
69
+ // Create a minimal ASS caption file
70
+ const assContent = `[Script Info]
71
+ Title: Test captions
72
+ ScriptType: v4.00+
73
+ PlayResX: 640
74
+ PlayResY: 480
75
+
76
+ [V4+ Styles]
77
+ Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
78
+ Style: Default,Arial,24,&H00FFFFFF,&H0000FFFF,&H00000000,&H80000000,0,0,0,0,100,100,0,0,1,2,1,2,10,10,30,1
79
+
80
+ [Events]
81
+ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
82
+ Dialogue: 0,0:00:00.00,0:00:02.00,Default,,0,0,0,,Hello world this is a test
83
+ Dialogue: 0,0:00:02.50,0:00:04.50,Default,,0,0,0,,of the caption system
84
+ `;
85
+ await fs.writeFile(assPath, assContent);
86
+ fixtures = { dir, videoPath, audioPath, transcriptPath, assPath };
87
+ return fixtures;
88
+ }
89
+ export async function cleanupFixtures() {
90
+ if (fixtures) {
91
+ await fs.rm(fixtures.dir, { recursive: true, force: true }).catch(() => { });
92
+ fixtures = null;
93
+ }
94
+ }
95
+ /** Get video duration via ffprobe */
96
+ export async function getVideoDuration(videoPath) {
97
+ const { stdout } = await execFileAsync(ffprobePath, [
98
+ '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', videoPath,
99
+ ]);
100
+ return parseFloat(stdout.trim());
101
+ }
102
+ /** Check if file exists and has non-zero size */
103
+ export async function fileExistsWithSize(filePath) {
104
+ try {
105
+ const stat = await fs.stat(filePath);
106
+ return { exists: true, size: stat.size };
107
+ }
108
+ catch {
109
+ return { exists: false, size: 0 };
110
+ }
111
+ }
112
+ //# sourceMappingURL=fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.js","sourceRoot":"","sources":["../../../src/__tests__/integration/fixture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fixture.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/fixture.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { setupFixtures, cleanupFixtures, isFFmpegAvailable, fileExistsWithSize } from './fixture.js';
3
+ const ffmpegOk = await isFFmpegAvailable();
4
+ describe.skipIf(!ffmpegOk)('Test Fixtures', () => {
5
+ let fix;
6
+ beforeAll(async () => { fix = await setupFixtures(); }, 30000);
7
+ afterAll(async () => { await cleanupFixtures(); });
8
+ it('generates test video', async () => {
9
+ const { exists, size } = await fileExistsWithSize(fix.videoPath);
10
+ expect(exists).toBe(true);
11
+ expect(size).toBeGreaterThan(1000);
12
+ });
13
+ it('generates test audio', async () => {
14
+ const { exists, size } = await fileExistsWithSize(fix.audioPath);
15
+ expect(exists).toBe(true);
16
+ expect(size).toBeGreaterThan(100);
17
+ });
18
+ it('generates transcript JSON', async () => {
19
+ const { exists } = await fileExistsWithSize(fix.transcriptPath);
20
+ expect(exists).toBe(true);
21
+ });
22
+ it('generates ASS captions', async () => {
23
+ const { exists } = await fileExistsWithSize(fix.assPath);
24
+ expect(exists).toBe(true);
25
+ });
26
+ });
27
+ //# sourceMappingURL=fixture.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/fixture.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAqB,MAAM,cAAc,CAAC;AAExH,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;AAE3C,QAAQ,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,eAAe,EAAE,GAAG,EAAE;IAC/C,IAAI,GAAiB,CAAC;IAEtB,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,GAAG,MAAM,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/D,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,MAAM,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnD,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import 'dotenv/config';
2
+ //# sourceMappingURL=realCaptions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realCaptions.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/realCaptions.test.ts"],"names":[],"mappings":"AAMA,OAAO,eAAe,CAAC"}