simple-ffmpegjs 0.5.2 → 0.5.4

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/README.md CHANGED
@@ -4,8 +4,11 @@
4
4
 
5
5
  <p align="center">
6
6
  <a href="https://www.npmjs.com/package/simple-ffmpegjs"><img src="https://img.shields.io/npm/v/simple-ffmpegjs.svg" alt="npm version"></a>
7
+ <a href="https://github.com/Fats403/simple-ffmpeg/actions/workflows/ci.yml"><img src="https://github.com/Fats403/simple-ffmpeg/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
8
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
8
- <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node.js ≥18"></a>
9
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg" alt="Node.js ≥20"></a>
10
+ <a href="https://codecov.io/gh/Fats403/simple-ffmpegjs"><img src="https://codecov.io/gh/Fats403/simple-ffmpegjs/branch/main/graph/badge.svg" alt="Coverage"></a>
11
+ <img src="https://img.shields.io/badge/dependencies-0-brightgreen.svg" alt="Zero Dependencies">
9
12
  </p>
10
13
 
11
14
  <p align="center">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simple-ffmpegjs",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Declarative video composition for Node.js — define clips, transitions, text, and audio as simple objects, and let FFmpeg handle the rest.",
5
5
  "author": "Brayden Blackwell <braydenblackwell21@gmail.com> (https://github.com/Fats403)",
6
6
  "license": "MIT",
@@ -33,13 +33,16 @@
33
33
  ],
34
34
  "sideEffects": false,
35
35
  "engines": {
36
- "node": ">=18"
36
+ "node": ">=20"
37
37
  },
38
38
  "scripts": {
39
39
  "test": "vitest run",
40
40
  "test:watch": "vitest",
41
41
  "test:unit": "vitest run tests/unit",
42
- "test:integration": "vitest run tests/integration"
42
+ "test:integration": "vitest run tests/integration",
43
+ "test:coverage": "vitest run --coverage",
44
+ "lint": "eslint .",
45
+ "lint:fix": "eslint . --fix"
43
46
  },
44
47
  "keywords": [
45
48
  "ffmpeg",
@@ -73,6 +76,10 @@
73
76
  "nodejs"
74
77
  ],
75
78
  "devDependencies": {
79
+ "@eslint/js": "^10.0.1",
80
+ "@stylistic/eslint-plugin": "^5.9.0",
81
+ "@vitest/coverage-v8": "^3.2.4",
82
+ "eslint": "^10.0.2",
76
83
  "vitest": "^3.0.0"
77
84
  }
78
85
  }
@@ -114,7 +114,7 @@ async function probeMedia(filePath) {
114
114
  } catch (error) {
115
115
  throw new MediaNotFoundError(
116
116
  `Failed to probe "${filePath}": ${error.message}`,
117
- { path: filePath }
117
+ { path: filePath },
118
118
  );
119
119
  }
120
120
 
@@ -124,14 +124,14 @@ async function probeMedia(filePath) {
124
124
  } catch (parseError) {
125
125
  throw new MediaNotFoundError(
126
126
  `Invalid JSON response from ffprobe for "${filePath}": ${parseError.message}`,
127
- { path: filePath }
127
+ { path: filePath },
128
128
  );
129
129
  }
130
130
 
131
131
  if (!metadata || !Array.isArray(metadata.streams)) {
132
132
  throw new MediaNotFoundError(
133
133
  `Invalid metadata structure for "${filePath}": missing or invalid 'streams' array`,
134
- { path: filePath }
134
+ { path: filePath },
135
135
  );
136
136
  }
137
137
 
@@ -147,8 +147,8 @@ async function probeMedia(filePath) {
147
147
  const duration = Number.isFinite(formatDuration)
148
148
  ? formatDuration
149
149
  : Number.isFinite(streamDuration)
150
- ? streamDuration
151
- : null;
150
+ ? streamDuration
151
+ : null;
152
152
 
153
153
  // ── FPS ─────────────────────────────────────────────────────────────────
154
154
  // Prefer avg_frame_rate, fall back to r_frame_rate
@@ -11,6 +11,10 @@
11
11
  * `position`, it is placed immediately after the previous clip on the
12
12
  * same track (visual or audio). The first clip defaults to position 0.
13
13
  *
14
+ * 3. **fullDuration**: If an effect or text clip has `fullDuration: true`,
15
+ * its position defaults to 0 and end is resolved later in _prepareExport()
16
+ * once the visual timeline duration is known.
17
+ *
14
18
  * Clips are shallow-cloned — the caller's original objects are not mutated.
15
19
  */
16
20
 
@@ -48,6 +52,35 @@ function resolveClips(clips) {
48
52
  const c = { ...clip };
49
53
  const path = `clips[${index}]`;
50
54
 
55
+ // ── fullDuration shorthand ─────────────────────────────────────────
56
+ if (c.fullDuration === true) {
57
+ if (c.end != null) {
58
+ errors.push({
59
+ code: "INVALID_VALUE",
60
+ path: `${path}`,
61
+ message:
62
+ "Cannot specify both 'fullDuration' and 'end'. fullDuration spans the entire visual timeline automatically.",
63
+ received: { fullDuration: true, end: c.end },
64
+ });
65
+ return c;
66
+ }
67
+ if (c.duration != null) {
68
+ errors.push({
69
+ code: "INVALID_VALUE",
70
+ path: `${path}`,
71
+ message:
72
+ "Cannot specify both 'fullDuration' and 'duration'. fullDuration spans the entire visual timeline automatically.",
73
+ received: { fullDuration: true, duration: c.duration },
74
+ });
75
+ return c;
76
+ }
77
+ // Default position to 0; end is resolved in _prepareExport()
78
+ if (c.position == null) {
79
+ c.position = 0;
80
+ }
81
+ return c;
82
+ }
83
+
51
84
  // ── Conflict check: duration + end ──────────────────────────────────
52
85
  if (c.duration != null && c.end != null) {
53
86
  errors.push({
@@ -51,7 +51,7 @@ function unrotateVideo(inputUrl, options = {}) {
51
51
  new FFmpegError(`ffmpeg process error: ${error.message}`, {
52
52
  stderr,
53
53
  command: `ffmpeg ${args.join(" ")}`,
54
- })
54
+ }),
55
55
  );
56
56
  });
57
57
 
@@ -65,8 +65,8 @@ function unrotateVideo(inputUrl, options = {}) {
65
65
  {
66
66
  stderr,
67
67
  command: `ffmpeg ${args.join(" ")}`,
68
- }
69
- )
68
+ },
69
+ ),
70
70
  );
71
71
  return;
72
72
  }
@@ -81,7 +81,7 @@ function unrotateVideo(inputUrl, options = {}) {
81
81
  stderr,
82
82
  command: `ffmpeg ${args.join(" ")}`,
83
83
  exitCode: code,
84
- })
84
+ }),
85
85
  );
86
86
  return;
87
87
  }