@gannochenko/staticstripes 0.0.1
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/.prettierrc +8 -0
- package/Makefile +69 -0
- package/dist/asset-manager.d.ts +16 -0
- package/dist/asset-manager.d.ts.map +1 -0
- package/dist/asset-manager.js +50 -0
- package/dist/asset-manager.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +257 -0
- package/dist/cli.js.map +1 -0
- package/dist/container-renderer.d.ts +21 -0
- package/dist/container-renderer.d.ts.map +1 -0
- package/dist/container-renderer.js +149 -0
- package/dist/container-renderer.js.map +1 -0
- package/dist/expression-parser.d.ts +63 -0
- package/dist/expression-parser.d.ts.map +1 -0
- package/dist/expression-parser.js +145 -0
- package/dist/expression-parser.js.map +1 -0
- package/dist/ffmpeg.d.ts +375 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +997 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/ffprobe.d.ts +2 -0
- package/dist/ffprobe.d.ts.map +1 -0
- package/dist/ffprobe.js +31 -0
- package/dist/ffprobe.js.map +1 -0
- package/dist/html-parser.d.ts +56 -0
- package/dist/html-parser.d.ts.map +1 -0
- package/dist/html-parser.js +208 -0
- package/dist/html-parser.js.map +1 -0
- package/dist/html-project-parser.d.ts +169 -0
- package/dist/html-project-parser.d.ts.map +1 -0
- package/dist/html-project-parser.js +954 -0
- package/dist/html-project-parser.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/label-generator.d.ts +35 -0
- package/dist/label-generator.d.ts.map +1 -0
- package/dist/label-generator.js +69 -0
- package/dist/label-generator.js.map +1 -0
- package/dist/project.d.ts +29 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +137 -0
- package/dist/project.js.map +1 -0
- package/dist/sample-sequences.d.ts +5 -0
- package/dist/sample-sequences.d.ts.map +1 -0
- package/dist/sample-sequences.js +199 -0
- package/dist/sample-sequences.js.map +1 -0
- package/dist/sample-streams.d.ts +2 -0
- package/dist/sample-streams.d.ts.map +1 -0
- package/dist/sample-streams.js +109 -0
- package/dist/sample-streams.js.map +1 -0
- package/dist/sequence.d.ts +21 -0
- package/dist/sequence.d.ts.map +1 -0
- package/dist/sequence.js +269 -0
- package/dist/sequence.js.map +1 -0
- package/dist/stream.d.ts +135 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +779 -0
- package/dist/stream.js.map +1 -0
- package/dist/type.d.ts +73 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/type.js +3 -0
- package/dist/type.js.map +1 -0
- package/eslint.config.js +44 -0
- package/package.json +50 -0
- package/src/asset-manager.ts +55 -0
- package/src/cli.ts +306 -0
- package/src/container-renderer.ts +190 -0
- package/src/expression-parser.test.ts +459 -0
- package/src/expression-parser.ts +199 -0
- package/src/ffmpeg.ts +1403 -0
- package/src/ffprobe.ts +29 -0
- package/src/html-parser.ts +221 -0
- package/src/html-project-parser.ts +1195 -0
- package/src/index.ts +9 -0
- package/src/label-generator.ts +74 -0
- package/src/project.ts +180 -0
- package/src/sample-sequences.ts +225 -0
- package/src/sample-streams.ts +142 -0
- package/src/sequence.ts +330 -0
- package/src/stream.ts +1012 -0
- package/src/type.ts +81 -0
- package/tsconfig.json +24 -0
package/.prettierrc
ADDED
package/Makefile
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.PHONY: install build link unlink lint lint-fix format format-check clean test test-ui demo demo-all demo-prod demo-all-prod help
|
|
2
|
+
|
|
3
|
+
# Install dependencies
|
|
4
|
+
install:
|
|
5
|
+
npm install
|
|
6
|
+
|
|
7
|
+
# Build the project
|
|
8
|
+
build:
|
|
9
|
+
npm run build
|
|
10
|
+
|
|
11
|
+
# Link the package globally (makes 'staticstripes' command available)
|
|
12
|
+
link:
|
|
13
|
+
npm link
|
|
14
|
+
|
|
15
|
+
# Unlink the package globally (removes 'staticstripes' command)
|
|
16
|
+
unlink:
|
|
17
|
+
npm unlink -g
|
|
18
|
+
|
|
19
|
+
# Run linter
|
|
20
|
+
lint:
|
|
21
|
+
npm run lint
|
|
22
|
+
|
|
23
|
+
# Run linter with auto-fix
|
|
24
|
+
lint-fix:
|
|
25
|
+
npm run lint:fix
|
|
26
|
+
|
|
27
|
+
# Format code
|
|
28
|
+
format:
|
|
29
|
+
npm run format
|
|
30
|
+
|
|
31
|
+
# Check code formatting
|
|
32
|
+
format-check:
|
|
33
|
+
npm run format:check
|
|
34
|
+
|
|
35
|
+
# Run tests
|
|
36
|
+
test:
|
|
37
|
+
npm run test:run
|
|
38
|
+
|
|
39
|
+
# Run tests with UI
|
|
40
|
+
test-ui:
|
|
41
|
+
npm run test:ui
|
|
42
|
+
|
|
43
|
+
# Generate demo video (youtube output) with fast preset for development
|
|
44
|
+
demo:
|
|
45
|
+
node dist/cli.js generate -p ../../examples/demo -o youtube -d
|
|
46
|
+
|
|
47
|
+
# Generate demo video with production quality (medium preset)
|
|
48
|
+
demo-prod:
|
|
49
|
+
node dist/cli.js generate -p ../../examples/demo -o youtube
|
|
50
|
+
|
|
51
|
+
# Generate all demo outputs with fast preset
|
|
52
|
+
demo-all:
|
|
53
|
+
node dist/cli.js generate -p ../../examples/demo -d
|
|
54
|
+
|
|
55
|
+
# Generate all demo outputs with production quality
|
|
56
|
+
demo-all-prod:
|
|
57
|
+
node dist/cli.js generate -p ../../examples/demo
|
|
58
|
+
|
|
59
|
+
# Clean build artifacts and dependencies
|
|
60
|
+
clean:
|
|
61
|
+
rm -rf node_modules dist *.tsbuildinfo
|
|
62
|
+
rm -f package-lock.json
|
|
63
|
+
|
|
64
|
+
# Clean cache in demo project
|
|
65
|
+
clean-cache:
|
|
66
|
+
rm -rf ../../examples/demo/.cache
|
|
67
|
+
|
|
68
|
+
# Full build
|
|
69
|
+
all: install build
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Label } from './ffmpeg';
|
|
2
|
+
import { Asset } from './type';
|
|
3
|
+
export declare class AssetManager {
|
|
4
|
+
private assets;
|
|
5
|
+
private assetIndexMap;
|
|
6
|
+
constructor(assets: Asset[]);
|
|
7
|
+
getAssetIndexMap(): Map<string, number>;
|
|
8
|
+
getAssetByName(name: string): Asset | undefined;
|
|
9
|
+
getVideoInputLabelByAssetName(name: string): Label;
|
|
10
|
+
getAudioInputLabelByAssetName(name: string): Label;
|
|
11
|
+
/**
|
|
12
|
+
* Adds a virtual asset (e.g., rendered container screenshot)
|
|
13
|
+
*/
|
|
14
|
+
addVirtualAsset(asset: Asset): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=asset-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-manager.d.ts","sourceRoot":"","sources":["../src/asset-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,qBAAa,YAAY;IAGX,OAAO,CAAC,MAAM;IAF1B,OAAO,CAAC,aAAa,CAAkC;gBAEnC,MAAM,EAAE,KAAK,EAAE;IAO5B,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAIvC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAI/C,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAalD,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IASzD;;OAEG;IACI,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAQ3C"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AssetManager = void 0;
|
|
4
|
+
class AssetManager {
|
|
5
|
+
assets;
|
|
6
|
+
assetIndexMap = new Map();
|
|
7
|
+
constructor(assets) {
|
|
8
|
+
this.assets = assets;
|
|
9
|
+
let index = 0;
|
|
10
|
+
for (const asset of assets) {
|
|
11
|
+
this.assetIndexMap.set(asset.name, index++);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
getAssetIndexMap() {
|
|
15
|
+
return this.assetIndexMap;
|
|
16
|
+
}
|
|
17
|
+
getAssetByName(name) {
|
|
18
|
+
return this.assets.find((assetItem) => assetItem.name === name);
|
|
19
|
+
}
|
|
20
|
+
getVideoInputLabelByAssetName(name) {
|
|
21
|
+
const assetIndex = this.assetIndexMap.get(name);
|
|
22
|
+
const asset = this.getAssetByName(name);
|
|
23
|
+
if (asset && asset.type === 'audio') {
|
|
24
|
+
throw new Error('trying to get video stream from an audio only asset');
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
tag: `${assetIndex}:v`,
|
|
28
|
+
isAudio: false,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
getAudioInputLabelByAssetName(name) {
|
|
32
|
+
const assetIndex = this.assetIndexMap.get(name);
|
|
33
|
+
return {
|
|
34
|
+
tag: `${assetIndex}:a`,
|
|
35
|
+
isAudio: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Adds a virtual asset (e.g., rendered container screenshot)
|
|
40
|
+
*/
|
|
41
|
+
addVirtualAsset(asset) {
|
|
42
|
+
// Add to assets array
|
|
43
|
+
this.assets.push(asset);
|
|
44
|
+
// Assign next available index
|
|
45
|
+
const nextIndex = this.assetIndexMap.size;
|
|
46
|
+
this.assetIndexMap.set(asset.name, nextIndex);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.AssetManager = AssetManager;
|
|
50
|
+
//# sourceMappingURL=asset-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-manager.js","sourceRoot":"","sources":["../src/asset-manager.ts"],"names":[],"mappings":";;;AAGA,MAAa,YAAY;IAGH;IAFZ,aAAa,GAAwB,IAAI,GAAG,EAAE,CAAC;IAEvD,YAAoB,MAAe;QAAf,WAAM,GAAN,MAAM,CAAS;QACjC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAEM,gBAAgB;QACrB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAEM,cAAc,CAAC,IAAY;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClE,CAAC;IAEM,6BAA6B,CAAC,IAAY;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QAED,OAAO;YACL,GAAG,EAAE,GAAG,UAAU,IAAI;YACtB,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAEM,6BAA6B,CAAC,IAAY;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEhD,OAAO;YACL,GAAG,EAAE,GAAG,UAAU,IAAI;YACtB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,eAAe,CAAC,KAAY;QACjC,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAExB,8BAA8B;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;QAC1C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAChD,CAAC;CACF;AAnDD,oCAmDC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_2 = require("path");
|
|
8
|
+
const html_parser_js_1 = require("./html-parser.js");
|
|
9
|
+
const html_project_parser_js_1 = require("./html-project-parser.js");
|
|
10
|
+
const ffmpeg_js_1 = require("./ffmpeg.js");
|
|
11
|
+
const ffprobe_js_1 = require("./ffprobe.js");
|
|
12
|
+
const program = new commander_1.Command();
|
|
13
|
+
program
|
|
14
|
+
.name('staticstripes')
|
|
15
|
+
.description('CLI tool for rendering video projects')
|
|
16
|
+
.version('0.1.0');
|
|
17
|
+
program
|
|
18
|
+
.command('generate')
|
|
19
|
+
.description('Generate video output from a project')
|
|
20
|
+
.option('-p, --project <path>', 'Path to project directory', '.')
|
|
21
|
+
.option('-o, --output <name>', 'Output name to render (renders all if not specified)')
|
|
22
|
+
.option('-d, --dev', 'Use fast encoding preset for development (ultrafast)')
|
|
23
|
+
.action(async (options) => {
|
|
24
|
+
try {
|
|
25
|
+
// Check if FFmpeg is installed
|
|
26
|
+
console.log('🔍 Checking for FFmpeg...');
|
|
27
|
+
await (0, ffmpeg_js_1.checkFFmpegInstalled)();
|
|
28
|
+
console.log('✅ FFmpeg found\n');
|
|
29
|
+
// Resolve project path
|
|
30
|
+
const projectPath = (0, path_1.resolve)(process.cwd(), options.project);
|
|
31
|
+
const projectFilePath = (0, path_1.resolve)(projectPath, 'project.html');
|
|
32
|
+
// Validate project.html exists
|
|
33
|
+
if (!(0, fs_1.existsSync)(projectFilePath)) {
|
|
34
|
+
console.error(`Error: project.html not found in ${projectPath}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
console.log(`📁 Project: ${projectPath}`);
|
|
38
|
+
console.log(`📄 Loading: ${projectFilePath}\n`);
|
|
39
|
+
// Parse the project HTML file
|
|
40
|
+
const parser = new html_project_parser_js_1.HTMLProjectParser(await new html_parser_js_1.HTMLParser().parseFile(projectFilePath), projectFilePath);
|
|
41
|
+
const project = await parser.parse();
|
|
42
|
+
// Determine which outputs to render
|
|
43
|
+
const allOutputs = Array.from(project.getOutputs().keys());
|
|
44
|
+
const outputsToRender = options.output ? [options.output] : allOutputs;
|
|
45
|
+
if (outputsToRender.length === 0) {
|
|
46
|
+
console.error('Error: No outputs defined in project.html');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
// Validate requested output exists
|
|
50
|
+
if (options.output && !allOutputs.includes(options.output)) {
|
|
51
|
+
console.error(`Error: Output "${options.output}" not found in project.html`);
|
|
52
|
+
console.error(`Available outputs: ${allOutputs.join(', ')}`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
// Determine encoding preset based on -d flag
|
|
56
|
+
const preset = options.dev ? 'ultrafast' : 'medium';
|
|
57
|
+
console.log(`⚡ Encoding preset: ${preset}`);
|
|
58
|
+
console.log(`🎬 Rendering outputs: ${outputsToRender.join(', ')}\n`);
|
|
59
|
+
// Render each output
|
|
60
|
+
for (const outputName of outputsToRender) {
|
|
61
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
62
|
+
console.log(`📹 Rendering: ${outputName}`);
|
|
63
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
64
|
+
// Get output info and ensure output directory exists
|
|
65
|
+
const output = project.getOutput(outputName);
|
|
66
|
+
if (!output) {
|
|
67
|
+
throw new Error(`Output "${outputName}" not found`);
|
|
68
|
+
}
|
|
69
|
+
const outputDir = (0, path_1.dirname)(output.path);
|
|
70
|
+
if (!(0, fs_1.existsSync)(outputDir)) {
|
|
71
|
+
console.log(`📂 Creating output directory: ${outputDir}`);
|
|
72
|
+
(0, fs_1.mkdirSync)(outputDir, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
// Render containers for this output
|
|
75
|
+
await project.renderContainers(outputName);
|
|
76
|
+
// Print project statistics
|
|
77
|
+
project.printStats();
|
|
78
|
+
// Build filter graph
|
|
79
|
+
const filterBuf = await project.build(outputName);
|
|
80
|
+
const filter = filterBuf.render();
|
|
81
|
+
console.log('\n=== Filter Graph ===\n');
|
|
82
|
+
console.log(filter);
|
|
83
|
+
// Generate FFmpeg command with appropriate preset
|
|
84
|
+
const ffmpegCommand = (0, ffmpeg_js_1.makeFFmpegCommand)(project, filter, outputName, preset);
|
|
85
|
+
console.log('\n=== Starting Render ===\n');
|
|
86
|
+
// Run FFmpeg
|
|
87
|
+
await (0, ffmpeg_js_1.runFFMpeg)(ffmpegCommand);
|
|
88
|
+
const resultPath = output.path;
|
|
89
|
+
console.log(`\n✅ Output file: ${resultPath}`);
|
|
90
|
+
const resultDuration = await (0, ffprobe_js_1.getAssetDuration)(resultPath);
|
|
91
|
+
console.log(`⏱️ Duration: ${resultDuration}ms`);
|
|
92
|
+
}
|
|
93
|
+
console.log('\n🎉 All outputs rendered successfully!\n');
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error('\n❌ Error:', error);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
program
|
|
101
|
+
.command('upload')
|
|
102
|
+
.description('Upload video to platforms (not yet implemented)')
|
|
103
|
+
.option('-p, --project <path>', 'Path to project directory', '.')
|
|
104
|
+
.option('-u, --upload <platform>', 'Platform to upload to (e.g., youtube)')
|
|
105
|
+
.action(() => {
|
|
106
|
+
console.log('Upload command is not yet implemented.');
|
|
107
|
+
console.log('This feature will allow uploading videos to platforms like YouTube.');
|
|
108
|
+
process.exit(0);
|
|
109
|
+
});
|
|
110
|
+
program
|
|
111
|
+
.command('bootstrap')
|
|
112
|
+
.description('Create a new project from template')
|
|
113
|
+
.requiredOption('-n, --name <name>', 'Name of the new project')
|
|
114
|
+
.action((options) => {
|
|
115
|
+
try {
|
|
116
|
+
const projectName = options.name;
|
|
117
|
+
const targetPath = (0, path_1.resolve)(process.cwd(), projectName);
|
|
118
|
+
// Check if target directory already exists
|
|
119
|
+
if ((0, fs_1.existsSync)(targetPath)) {
|
|
120
|
+
console.error(`Error: Directory "${projectName}" already exists`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
// Get the template path (relative to the CLI script location)
|
|
124
|
+
// When built, cli.js is in apps/renderer/dist/, and template is at ../../../examples/template
|
|
125
|
+
// Use realpathSync to resolve symlinks when globally linked via npm link
|
|
126
|
+
const scriptPath = (0, fs_1.realpathSync)(process.argv[1]);
|
|
127
|
+
const scriptDir = (0, path_1.dirname)(scriptPath);
|
|
128
|
+
const templatePath = (0, path_1.resolve)(scriptDir, '../../../examples/template');
|
|
129
|
+
// Validate template exists
|
|
130
|
+
if (!(0, fs_1.existsSync)(templatePath)) {
|
|
131
|
+
console.error(`Error: Template directory not found at ${templatePath}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
console.log(`📦 Creating new project "${projectName}"...`);
|
|
135
|
+
console.log(`📂 Template: ${templatePath}`);
|
|
136
|
+
console.log(`🎯 Target: ${targetPath}\n`);
|
|
137
|
+
// Create target directory and copy template contents
|
|
138
|
+
(0, fs_1.mkdirSync)(targetPath, { recursive: true });
|
|
139
|
+
(0, fs_1.cpSync)(templatePath, targetPath, { recursive: true });
|
|
140
|
+
console.log(`✅ Project "${projectName}" created successfully!\n`);
|
|
141
|
+
console.log('Next steps:');
|
|
142
|
+
console.log(` cd ${projectName}`);
|
|
143
|
+
console.log(' # Edit project.html to customize your video');
|
|
144
|
+
console.log(` staticstripes generate -p . -o youtube -d\n`);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error('\n❌ Error:', error);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
program
|
|
152
|
+
.command('add-assets')
|
|
153
|
+
.description('Scan for media files and add them as assets to project.html')
|
|
154
|
+
.option('-p, --project <path>', 'Path to project directory', '.')
|
|
155
|
+
.action((options) => {
|
|
156
|
+
try {
|
|
157
|
+
// Resolve project path
|
|
158
|
+
const projectPath = (0, path_1.resolve)(process.cwd(), options.project);
|
|
159
|
+
const projectFilePath = (0, path_1.resolve)(projectPath, 'project.html');
|
|
160
|
+
// Validate project.html exists
|
|
161
|
+
if (!(0, fs_1.existsSync)(projectFilePath)) {
|
|
162
|
+
console.error(`Error: project.html not found in ${projectPath}`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
console.log(`📁 Project: ${projectPath}`);
|
|
166
|
+
console.log(`📄 Scanning for media files...\n`);
|
|
167
|
+
// Find all media files recursively
|
|
168
|
+
const mediaFiles = [];
|
|
169
|
+
const scanDirectory = (dir) => {
|
|
170
|
+
const entries = (0, fs_1.readdirSync)(dir);
|
|
171
|
+
for (const entry of entries) {
|
|
172
|
+
const fullPath = (0, path_2.join)(dir, entry);
|
|
173
|
+
const stat = (0, fs_1.statSync)(fullPath);
|
|
174
|
+
if (stat.isDirectory()) {
|
|
175
|
+
scanDirectory(fullPath);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const ext = entry.toLowerCase().split('.').pop();
|
|
179
|
+
let type = null;
|
|
180
|
+
if (ext === 'mp4') {
|
|
181
|
+
type = 'video';
|
|
182
|
+
}
|
|
183
|
+
else if (ext === 'mp3') {
|
|
184
|
+
type = 'audio';
|
|
185
|
+
}
|
|
186
|
+
else if (ext === 'jpg' || ext === 'png') {
|
|
187
|
+
type = 'image';
|
|
188
|
+
}
|
|
189
|
+
if (type) {
|
|
190
|
+
const relativePath = (0, path_1.relative)(projectPath, fullPath);
|
|
191
|
+
mediaFiles.push({ path: fullPath, relativePath, type });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
scanDirectory(projectPath);
|
|
197
|
+
// Sort by relative path (name)
|
|
198
|
+
mediaFiles.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
199
|
+
// Group by type and assign names
|
|
200
|
+
const videos = mediaFiles.filter(f => f.type === 'video');
|
|
201
|
+
const audios = mediaFiles.filter(f => f.type === 'audio');
|
|
202
|
+
const images = mediaFiles.filter(f => f.type === 'image');
|
|
203
|
+
console.log(`Found ${videos.length} video(s), ${audios.length} audio(s), ${images.length} image(s)\n`);
|
|
204
|
+
if (mediaFiles.length === 0) {
|
|
205
|
+
console.log('No media files found.');
|
|
206
|
+
process.exit(0);
|
|
207
|
+
}
|
|
208
|
+
// Generate asset tags
|
|
209
|
+
const assetTags = [];
|
|
210
|
+
videos.forEach((file, index) => {
|
|
211
|
+
const name = `clip_${index + 1}`;
|
|
212
|
+
assetTags.push(` <asset data-name="${name}" data-path="./${file.relativePath}" />`);
|
|
213
|
+
console.log(`${name}: ${file.relativePath}`);
|
|
214
|
+
});
|
|
215
|
+
audios.forEach((file, index) => {
|
|
216
|
+
const name = `track_${index + 1}`;
|
|
217
|
+
assetTags.push(` <asset data-name="${name}" data-path="./${file.relativePath}" />`);
|
|
218
|
+
console.log(`${name}: ${file.relativePath}`);
|
|
219
|
+
});
|
|
220
|
+
images.forEach((file, index) => {
|
|
221
|
+
const name = `image_${index + 1}`;
|
|
222
|
+
assetTags.push(` <asset data-name="${name}" data-path="./${file.relativePath}" />`);
|
|
223
|
+
console.log(`${name}: ${file.relativePath}`);
|
|
224
|
+
});
|
|
225
|
+
// Read project.html
|
|
226
|
+
let content = (0, fs_1.readFileSync)(projectFilePath, 'utf-8');
|
|
227
|
+
// Check if <assets> section exists
|
|
228
|
+
const assetsMatch = content.match(/<assets>([\s\S]*?)<\/assets>/);
|
|
229
|
+
if (assetsMatch) {
|
|
230
|
+
// Replace existing assets section
|
|
231
|
+
const newAssetsSection = `<assets>\n${assetTags.join('\n')}\n</assets>`;
|
|
232
|
+
content = content.replace(/<assets>[\s\S]*?<\/assets>/, newAssetsSection);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Add assets section before </project> or at the end
|
|
236
|
+
const newAssetsSection = `\n<assets>\n${assetTags.join('\n')}\n</assets>\n`;
|
|
237
|
+
if (content.includes('</outputs>')) {
|
|
238
|
+
content = content.replace('</outputs>', `</outputs>${newAssetsSection}`);
|
|
239
|
+
}
|
|
240
|
+
else if (content.includes('</style>')) {
|
|
241
|
+
content = content.replace('</style>', `</style>${newAssetsSection}`);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
content += newAssetsSection;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Write back to project.html
|
|
248
|
+
(0, fs_1.writeFileSync)(projectFilePath, content, 'utf-8');
|
|
249
|
+
console.log(`\n✅ Assets added to ${projectFilePath}`);
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
console.error('\n❌ Error:', error);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
program.parse(process.argv);
|
|
257
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Container } from './type';
|
|
2
|
+
export interface RenderContainerOptions {
|
|
3
|
+
container: Container;
|
|
4
|
+
cssText: string;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
projectDir: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ContainerRenderResult {
|
|
10
|
+
container: Container;
|
|
11
|
+
screenshotPath: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Renders a container to a PNG screenshot using Puppeteer
|
|
15
|
+
*/
|
|
16
|
+
export declare function renderContainer(options: RenderContainerOptions): Promise<ContainerRenderResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Renders multiple containers in sequence
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderContainers(containers: Container[], cssText: string, width: number, height: number, projectDir: string): Promise<ContainerRenderResult[]>;
|
|
21
|
+
//# sourceMappingURL=container-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-renderer.d.ts","sourceRoot":"","sources":["../src/container-renderer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnC,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAYD;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAyFhC;AAgCD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAwBlC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.renderContainer = renderContainer;
|
|
7
|
+
exports.renderContainers = renderContainers;
|
|
8
|
+
const puppeteer_1 = __importDefault(require("puppeteer"));
|
|
9
|
+
const promises_1 = require("fs/promises");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
/**
|
|
14
|
+
* Generates a hash from container content and CSS
|
|
15
|
+
*/
|
|
16
|
+
function generateCacheKey(containerHtml, cssText) {
|
|
17
|
+
const hash = (0, crypto_1.createHash)('sha256');
|
|
18
|
+
hash.update(containerHtml);
|
|
19
|
+
hash.update(cssText);
|
|
20
|
+
return hash.digest('hex').substring(0, 16);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Renders a container to a PNG screenshot using Puppeteer
|
|
24
|
+
*/
|
|
25
|
+
async function renderContainer(options) {
|
|
26
|
+
const { container, cssText, width, height, projectDir } = options;
|
|
27
|
+
// Create cache directory
|
|
28
|
+
const cacheDir = (0, path_1.resolve)(projectDir, '.cache', 'containers');
|
|
29
|
+
if (!(0, fs_1.existsSync)(cacheDir)) {
|
|
30
|
+
await (0, promises_1.mkdir)(cacheDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
// Generate cache key from content hash
|
|
33
|
+
const cacheKey = generateCacheKey(container.htmlContent, cssText);
|
|
34
|
+
const screenshotPath = (0, path_1.resolve)(cacheDir, `${cacheKey}.png`);
|
|
35
|
+
// Check if cached version exists
|
|
36
|
+
if ((0, fs_1.existsSync)(screenshotPath)) {
|
|
37
|
+
console.log(`Using cached container "${container.id}" (hash: ${cacheKey}) from ${screenshotPath}`);
|
|
38
|
+
return {
|
|
39
|
+
container,
|
|
40
|
+
screenshotPath,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Build complete HTML document
|
|
44
|
+
const html = `
|
|
45
|
+
<!DOCTYPE html>
|
|
46
|
+
<html>
|
|
47
|
+
<head>
|
|
48
|
+
<meta charset="UTF-8">
|
|
49
|
+
<style>
|
|
50
|
+
* {
|
|
51
|
+
margin: 0;
|
|
52
|
+
padding: 0;
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
}
|
|
55
|
+
body {
|
|
56
|
+
width: ${width}px;
|
|
57
|
+
height: ${height}px;
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
background: transparent;
|
|
60
|
+
font-size: 16px;
|
|
61
|
+
}
|
|
62
|
+
${cssText}
|
|
63
|
+
</style>
|
|
64
|
+
</head>
|
|
65
|
+
<body>
|
|
66
|
+
${container.htmlContent}
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
69
|
+
`.trim();
|
|
70
|
+
// Launch browser and render
|
|
71
|
+
const browser = await puppeteer_1.default.launch({
|
|
72
|
+
headless: true,
|
|
73
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
const page = await browser.newPage();
|
|
77
|
+
await page.setViewport({ width, height });
|
|
78
|
+
await page.setContent(html, { waitUntil: 'networkidle0' });
|
|
79
|
+
// Take screenshot with transparent background
|
|
80
|
+
const screenshot = await page.screenshot({
|
|
81
|
+
type: 'png',
|
|
82
|
+
omitBackground: true,
|
|
83
|
+
clip: {
|
|
84
|
+
x: 0,
|
|
85
|
+
y: 0,
|
|
86
|
+
width,
|
|
87
|
+
height,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
// Save to file
|
|
91
|
+
await (0, promises_1.writeFile)(screenshotPath, screenshot);
|
|
92
|
+
console.log(`Rendered container "${container.id}" (hash: ${cacheKey}) to ${screenshotPath}`);
|
|
93
|
+
return {
|
|
94
|
+
container,
|
|
95
|
+
screenshotPath,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await browser.close();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Cleans up stale cache entries that are not in the active set
|
|
104
|
+
*/
|
|
105
|
+
async function cleanupStaleCache(cacheDir, activeCacheKeys) {
|
|
106
|
+
if (!(0, fs_1.existsSync)(cacheDir)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const files = await (0, promises_1.readdir)(cacheDir);
|
|
110
|
+
const pngFiles = files.filter((file) => file.endsWith('.png'));
|
|
111
|
+
let removedCount = 0;
|
|
112
|
+
for (const file of pngFiles) {
|
|
113
|
+
const cacheKey = file.replace('.png', '');
|
|
114
|
+
if (!activeCacheKeys.has(cacheKey)) {
|
|
115
|
+
const filePath = (0, path_1.resolve)(cacheDir, file);
|
|
116
|
+
await (0, promises_1.unlink)(filePath);
|
|
117
|
+
console.log(`Removed stale cache entry: ${file}`);
|
|
118
|
+
removedCount++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (removedCount > 0) {
|
|
122
|
+
console.log(`Cleaned up ${removedCount} stale cache entries`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Renders multiple containers in sequence
|
|
127
|
+
*/
|
|
128
|
+
async function renderContainers(containers, cssText, width, height, projectDir) {
|
|
129
|
+
const results = [];
|
|
130
|
+
const activeCacheKeys = new Set();
|
|
131
|
+
// Render all containers and collect active cache keys
|
|
132
|
+
for (const container of containers) {
|
|
133
|
+
const cacheKey = generateCacheKey(container.htmlContent, cssText);
|
|
134
|
+
activeCacheKeys.add(cacheKey);
|
|
135
|
+
const result = await renderContainer({
|
|
136
|
+
container,
|
|
137
|
+
cssText,
|
|
138
|
+
width,
|
|
139
|
+
height,
|
|
140
|
+
projectDir,
|
|
141
|
+
});
|
|
142
|
+
results.push(result);
|
|
143
|
+
}
|
|
144
|
+
// Clean up stale cache entries
|
|
145
|
+
const cacheDir = (0, path_1.resolve)(projectDir, '.cache', 'containers');
|
|
146
|
+
await cleanupStaleCache(cacheDir, activeCacheKeys);
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=container-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-renderer.js","sourceRoot":"","sources":["../src/container-renderer.ts"],"names":[],"mappings":"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"}
|