@shaztech/video-pipeline 1.0.1 → 1.0.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.
- package/README.md +220 -0
- package/package.json +14 -2
- package/screenshot.png +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# video-pipeline
|
|
2
|
+
|
|
3
|
+
[](https://github.com/shaztechio/video-pipeline/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@shaztech/video-pipeline)
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
A visual node-based pipeline tool for composing video processing workflows using [`video-cutter`](https://github.com/shaztechio/video-cutter) and [`video-stitcher`](https://github.com/shaztechio/video-stitcher).
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Create pipelines by connecting nodes on a visual canvas. Each node is an instance of a CLI tool. The pipeline is stored as a JSON spec file on disk and can be executed directly from the command line.
|
|
13
|
+
|
|
14
|
+
**Node types:**
|
|
15
|
+
|
|
16
|
+
- **Input File** — provides a single file path. Connect to a Cutter node as its input source.
|
|
17
|
+
- **Input Folder** — scans a folder and provides all matching file paths (with optional glob filter). Connect to a Cutter node to batch-process every file in the folder.
|
|
18
|
+
- **Video Cutter** — cuts a video into N segments (equal count, fixed duration, or scene detection). Input comes from a connected Input File or Input Folder node. Segments are written to a `cutter-output/` folder next to the input file by default, or to a connected Output Folder node.
|
|
19
|
+
- **Video Stitcher** — for each cutter segment, stitches fixed inputs + that segment into one output file. Outputs go to a `stitch-output/` folder next to the cutter's input file by default, or to a connected Output Folder node. When an Input Folder feeds multiple files through the cutter, stitcher outputs are organised into per-source subfolders (e.g. `stitch-output/movie1/seg_01.mp4`).
|
|
20
|
+
- **Output Folder** — specifies an explicit output directory. Connect one or more Output Folder nodes to a Cutter or Stitcher to override the default output location. When multiple Output Folder nodes are connected, outputs are written to the first and copied to the rest.
|
|
21
|
+
|
|
22
|
+
**Data flow:** Each segment produced by a cutter node generates a separate output from the connected stitcher. For example, a cutter producing 3 segments with a stitcher configured as `[intro, EDGE(cutter), credits]` produces 3 output files — one per segment — each wrapped with the fixed inputs.
|
|
23
|
+
|
|
24
|
+
**Batch mode:** When an Input Folder node is connected to a Cutter, every file in the folder is cut independently. All resulting segments flow into the downstream Stitcher, which organises outputs into per-source subfolders automatically.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g @shaztech/video-pipeline
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Requires Node.js 20+ and FFmpeg installed on your system.
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Create a new pipeline spec
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
video-pipeline create my-workflow
|
|
40
|
+
# Creates my-workflow.json in the current directory
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Open the visual editor
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
video-pipeline edit my-workflow.json
|
|
47
|
+
# Starts a local server and opens the editor in your browser
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The editor lets you:
|
|
51
|
+
- Drag **Input File**, **Input Folder**, **Cutter**, **Stitcher**, and **Output Folder** nodes onto the canvas — new nodes appear centred in the current viewport
|
|
52
|
+
- Connect Input File or Input Folder to a Cutter's left handle to supply its input
|
|
53
|
+
- Connect a Cutter or Stitcher output handle to one or more Output Folder nodes
|
|
54
|
+
- Configure each node's parameters directly on the node
|
|
55
|
+
- Click the pipeline name in the toolbar to rename it (saved with the spec)
|
|
56
|
+
- Use the native OS file/folder picker (📁) on any file field
|
|
57
|
+
- Set a glob filter on Input Folder nodes (e.g. `*.mp4`; blank = all files)
|
|
58
|
+
- Drag inputs to reorder them within a Stitcher node
|
|
59
|
+
- Set per-image duration overrides (✎ pencil icon on image inputs)
|
|
60
|
+
- Delete nodes with the **×** button that appears on hover
|
|
61
|
+
- Save with **⌘S** (macOS) / **Ctrl+S** (Windows/Linux) or the Save button
|
|
62
|
+
|
|
63
|
+
### Execute a pipeline
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
video-pipeline run my-workflow.json
|
|
67
|
+
|
|
68
|
+
# Keep intermediate temp files
|
|
69
|
+
video-pipeline run my-workflow.json --keep-temp
|
|
70
|
+
|
|
71
|
+
# Dry run — print execution plan without running
|
|
72
|
+
video-pipeline run my-workflow.json --dry-run
|
|
73
|
+
|
|
74
|
+
# Overwrite existing output files (clears the cutter output directory before running)
|
|
75
|
+
video-pipeline run my-workflow.json --overwrite
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Validate a spec
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
video-pipeline validate my-workflow.json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Runs both JSON Schema validation (structure and types) and semantic checks (duplicate node IDs, valid edge references). Exits with a non-zero code and prints all errors on failure.
|
|
85
|
+
|
|
86
|
+
You can also enable editor autocomplete and inline validation by adding a `$schema` reference to any workflow file:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"$schema": "../../pipeline.schema.json",
|
|
91
|
+
"version": "1",
|
|
92
|
+
"name": "my-workflow",
|
|
93
|
+
...
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The schema file is at `pipeline.schema.json` in the project root.
|
|
98
|
+
|
|
99
|
+
## Pipeline Spec Format
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"version": "1",
|
|
104
|
+
"name": "my-workflow",
|
|
105
|
+
"nodes": [
|
|
106
|
+
{
|
|
107
|
+
"id": "in-1",
|
|
108
|
+
"type": "input-file",
|
|
109
|
+
"label": "Source video",
|
|
110
|
+
"position": { "x": 0, "y": 200 },
|
|
111
|
+
"config": { "path": "/path/to/source.mp4" }
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "cutter-1",
|
|
115
|
+
"type": "video-cutter",
|
|
116
|
+
"label": "Cut into 3",
|
|
117
|
+
"position": { "x": 300, "y": 200 },
|
|
118
|
+
"config": {
|
|
119
|
+
"segments": 3,
|
|
120
|
+
"duration": null,
|
|
121
|
+
"sceneDetect": null,
|
|
122
|
+
"output": null,
|
|
123
|
+
"verify": false,
|
|
124
|
+
"reEncode": false
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "stitcher-1",
|
|
129
|
+
"type": "video-stitcher",
|
|
130
|
+
"label": "Stitch with intro and credits",
|
|
131
|
+
"position": { "x": 650, "y": 200 },
|
|
132
|
+
"config": {
|
|
133
|
+
"inputOrder": [
|
|
134
|
+
{ "type": "fixed", "value": "/path/to/intro.mp4" },
|
|
135
|
+
{ "type": "edge", "nodeId": "cutter-1" },
|
|
136
|
+
{ "type": "fixed", "value": "/path/to/credits.png", "imageDuration": 5 }
|
|
137
|
+
],
|
|
138
|
+
"imageDuration": 1,
|
|
139
|
+
"bgAudio": null,
|
|
140
|
+
"bgAudioVolume": 1.0
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"id": "out-1",
|
|
145
|
+
"type": "output-folder",
|
|
146
|
+
"label": "Final Output",
|
|
147
|
+
"position": { "x": 1000, "y": 200 },
|
|
148
|
+
"config": { "path": "/path/to/output/folder" }
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"edges": [
|
|
152
|
+
{ "id": "e1", "source": "in-1", "sourceHandle": "output", "target": "cutter-1", "targetHandle": "input" },
|
|
153
|
+
{ "id": "e2", "source": "cutter-1", "sourceHandle": "output", "target": "stitcher-1","targetHandle": "inputs" },
|
|
154
|
+
{ "id": "e3", "source": "stitcher-1","sourceHandle": "video-out", "target": "out-1", "targetHandle": "input" }
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
In this example the pipeline:
|
|
160
|
+
1. Takes `source.mp4` from the Input File node
|
|
161
|
+
2. Cuts it into 3 equal segments
|
|
162
|
+
3. For each segment, stitches `intro.mp4` + segment + `credits.png` (at 5s) → 3 output files
|
|
163
|
+
4. Writes the stitched files to `/path/to/output/folder/`
|
|
164
|
+
|
|
165
|
+
### Batch example (Input Folder)
|
|
166
|
+
|
|
167
|
+
Replace `input-file` with `input-folder` and connect it the same way:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"id": "in-1",
|
|
172
|
+
"type": "input-folder",
|
|
173
|
+
"config": { "path": "/videos/season2", "filter": "*.mp4" }
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Every `.mp4` in the folder is cut and stitched independently. Stitcher outputs are written into per-source subfolders: `stitch-output/episode01/seg_01.mp4`, `stitch-output/episode02/seg_01.mp4`, etc.
|
|
178
|
+
|
|
179
|
+
### Output folder defaults
|
|
180
|
+
|
|
181
|
+
| Node | Default output location |
|
|
182
|
+
|------|------------------------|
|
|
183
|
+
| Video Cutter | `cutter-output/` next to the input file |
|
|
184
|
+
| Video Stitcher | `stitch-output/` next to the cutter's input file |
|
|
185
|
+
|
|
186
|
+
Connect an **Output Folder** node to override. Multiple Output Folder nodes can be connected — outputs are written to the first and copied to the rest.
|
|
187
|
+
|
|
188
|
+
### `inputOrder` items (Stitcher)
|
|
189
|
+
|
|
190
|
+
| Field | Type | Description |
|
|
191
|
+
|-------|------|-------------|
|
|
192
|
+
| `type` | `"fixed"` \| `"edge"` | Fixed file path or upstream cutter output |
|
|
193
|
+
| `value` | `string` | File path (fixed items only) |
|
|
194
|
+
| `nodeId` | `string` | Source node id (edge items only) |
|
|
195
|
+
| `imageDuration` | `number` | Per-image duration override in seconds (fixed image items only) |
|
|
196
|
+
|
|
197
|
+
### `input-folder` config
|
|
198
|
+
|
|
199
|
+
| Field | Type | Description |
|
|
200
|
+
|-------|------|-------------|
|
|
201
|
+
| `path` | `string` | Folder to scan |
|
|
202
|
+
| `filter` | `string` | Glob pattern (e.g. `*.mp4`). Blank = all files in the folder |
|
|
203
|
+
|
|
204
|
+
## Development
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
git clone https://github.com/shaztechio/video-pipeline
|
|
208
|
+
cd video-pipeline
|
|
209
|
+
npm install # installs all workspaces and builds the editor
|
|
210
|
+
npm run dev # start Vite dev server for the editor UI
|
|
211
|
+
npm test # run CLI unit tests (Vitest, 100% coverage)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
To run the CLI locally without installing:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
node packages/cli/bin.js create workflows/test
|
|
218
|
+
node packages/cli/bin.js edit workflows/test.json
|
|
219
|
+
node packages/cli/bin.js run workflows/test.json --dry-run
|
|
220
|
+
```
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaztech/video-pipeline",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Visual node-based video processing pipeline CLI",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/shaztechio/video-pipeline.git",
|
|
9
|
+
"directory": "packages/cli"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/shaztechio/video-pipeline#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/shaztechio/video-pipeline/issues"
|
|
14
|
+
},
|
|
6
15
|
"type": "module",
|
|
7
16
|
"bin": {
|
|
8
17
|
"video-pipeline": "./bin.js"
|
|
@@ -10,7 +19,8 @@
|
|
|
10
19
|
"files": [
|
|
11
20
|
"bin.js",
|
|
12
21
|
"src/",
|
|
13
|
-
"dist/"
|
|
22
|
+
"dist/",
|
|
23
|
+
"screenshot.png"
|
|
14
24
|
],
|
|
15
25
|
"engines": {
|
|
16
26
|
"node": ">=20.0.0"
|
|
@@ -33,6 +43,8 @@
|
|
|
33
43
|
"access": "public"
|
|
34
44
|
},
|
|
35
45
|
"scripts": {
|
|
46
|
+
"prepack": "cp ../../README.md ./README.md && cp ../../screenshot.png ./screenshot.png",
|
|
47
|
+
"postpack": "rm -f ./README.md ./screenshot.png",
|
|
36
48
|
"test": "vitest run --coverage"
|
|
37
49
|
},
|
|
38
50
|
"devDependencies": {
|
package/screenshot.png
ADDED
|
Binary file
|