n8n-nodes-sb-render 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.
- package/LICENSE +21 -0
- package/README.md +442 -0
- package/dist/nodes/SbRender/SbRender.node.d.ts +10 -0
- package/dist/nodes/SbRender/SbRender.node.d.ts.map +1 -0
- package/dist/nodes/SbRender/SbRender.node.js +768 -0
- package/dist/nodes/SbRender/SbRender.node.js.map +1 -0
- package/dist/nodes/SbRender/interfaces/index.d.ts +155 -0
- package/dist/nodes/SbRender/interfaces/index.d.ts.map +1 -0
- package/dist/nodes/SbRender/interfaces/index.js +41 -0
- package/dist/nodes/SbRender/interfaces/index.js.map +1 -0
- package/dist/nodes/SbRender/sbrender.svg +7 -0
- package/dist/nodes/SbRender/services/AudioMixer.d.ts +26 -0
- package/dist/nodes/SbRender/services/AudioMixer.d.ts.map +1 -0
- package/dist/nodes/SbRender/services/AudioMixer.js +120 -0
- package/dist/nodes/SbRender/services/AudioMixer.js.map +1 -0
- package/dist/nodes/SbRender/services/FileManager.d.ts +37 -0
- package/dist/nodes/SbRender/services/FileManager.d.ts.map +1 -0
- package/dist/nodes/SbRender/services/FileManager.js +157 -0
- package/dist/nodes/SbRender/services/FileManager.js.map +1 -0
- package/dist/nodes/SbRender/services/SubtitleEngine.d.ts +64 -0
- package/dist/nodes/SbRender/services/SubtitleEngine.d.ts.map +1 -0
- package/dist/nodes/SbRender/services/SubtitleEngine.js +213 -0
- package/dist/nodes/SbRender/services/SubtitleEngine.js.map +1 -0
- package/dist/nodes/SbRender/services/VideoComposer.d.ts +28 -0
- package/dist/nodes/SbRender/services/VideoComposer.d.ts.map +1 -0
- package/dist/nodes/SbRender/services/VideoComposer.js +228 -0
- package/dist/nodes/SbRender/services/VideoComposer.js.map +1 -0
- package/dist/nodes/SbRender/utils/ffmpeg.d.ts +32 -0
- package/dist/nodes/SbRender/utils/ffmpeg.d.ts.map +1 -0
- package/dist/nodes/SbRender/utils/ffmpeg.js +107 -0
- package/dist/nodes/SbRender/utils/ffmpeg.js.map +1 -0
- package/dist/nodes/SbRender/utils/validation.d.ts +32 -0
- package/dist/nodes/SbRender/utils/validation.d.ts.map +1 -0
- package/dist/nodes/SbRender/utils/validation.js +210 -0
- package/dist/nodes/SbRender/utils/validation.js.map +1 -0
- package/index.js +3 -0
- package/package.json +69 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FFmpeg utility functions
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.formatTime = formatTime;
|
|
40
|
+
exports.pad = pad;
|
|
41
|
+
exports.escapeFilterString = escapeFilterString;
|
|
42
|
+
exports.escapeFilePath = escapeFilePath;
|
|
43
|
+
exports.percentageToDecimal = percentageToDecimal;
|
|
44
|
+
exports.getFileExtension = getFileExtension;
|
|
45
|
+
exports.validateFFmpegAvailable = validateFFmpegAvailable;
|
|
46
|
+
/**
|
|
47
|
+
* Format seconds to HH:MM:SS format
|
|
48
|
+
*/
|
|
49
|
+
function formatTime(seconds) {
|
|
50
|
+
const hours = Math.floor(seconds / 3600);
|
|
51
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
52
|
+
const secs = Math.floor(seconds % 60);
|
|
53
|
+
return `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(secs, 2)}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Pad number with zeros
|
|
57
|
+
*/
|
|
58
|
+
function pad(num, length) {
|
|
59
|
+
return num.toString().padStart(length, '0');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Escape special characters for FFmpeg filter syntax
|
|
63
|
+
*/
|
|
64
|
+
function escapeFilterString(str) {
|
|
65
|
+
return str
|
|
66
|
+
.replace(/\\/g, '\\\\')
|
|
67
|
+
.replace(/:/g, '\\:')
|
|
68
|
+
.replace(/'/g, "\\'")
|
|
69
|
+
.replace(/\[/g, '\\[')
|
|
70
|
+
.replace(/]/g, '\\]')
|
|
71
|
+
.replace(/,/g, '\\,')
|
|
72
|
+
.replace(/;/g, '\\;');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Escape file path for FFmpeg
|
|
76
|
+
*/
|
|
77
|
+
function escapeFilePath(path) {
|
|
78
|
+
return path
|
|
79
|
+
.replace(/\\/g, '/')
|
|
80
|
+
.replace(/:/g, '\\:');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Convert percentage to decimal
|
|
84
|
+
*/
|
|
85
|
+
function percentageToDecimal(percentage) {
|
|
86
|
+
return percentage / 100;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get file extension from path
|
|
90
|
+
*/
|
|
91
|
+
function getFileExtension(path) {
|
|
92
|
+
const parts = path.split('.');
|
|
93
|
+
return parts.length > 1 ? `.${parts[parts.length - 1]}` : '';
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validate FFmpeg is available
|
|
97
|
+
*/
|
|
98
|
+
async function validateFFmpegAvailable() {
|
|
99
|
+
try {
|
|
100
|
+
const ffmpegInstaller = await Promise.resolve().then(() => __importStar(require('@ffmpeg-installer/ffmpeg')));
|
|
101
|
+
return !!ffmpegInstaller.path;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=ffmpeg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../../../nodes/SbRender/utils/ffmpeg.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKH,gCAMC;AAKD,kBAEC;AAKD,gDASC;AAKD,wCAIC;AAKD,kDAEC;AAKD,4CAGC;AAKD,0DAOC;AAlED;;GAEG;AACH,SAAgB,UAAU,CAAC,OAAe;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IAEtC,OAAO,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,SAAgB,GAAG,CAAC,GAAW,EAAE,MAAc;IAC7C,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAAC,GAAW;IAC5C,OAAO,GAAG;SACP,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI;SACR,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,UAAkB;IACpD,OAAO,UAAU,GAAG,GAAG,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,uBAAuB;IAC3C,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,wDAAa,0BAA0B,GAAC,CAAC;QACjE,OAAO,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ISbRenderNodeParams, ISubtitleConfig } from '../interfaces';
|
|
2
|
+
/**
|
|
3
|
+
* Validation utilities for sb-render node
|
|
4
|
+
*/
|
|
5
|
+
export declare class ValidationError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Validate video source configuration
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateVideoSource(params: ISbRenderNodeParams): void;
|
|
12
|
+
/**
|
|
13
|
+
* Validate BGM configuration
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateBGMConfig(params: ISbRenderNodeParams): void;
|
|
16
|
+
/**
|
|
17
|
+
* Validate narration configuration
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateNarrationConfig(params: ISbRenderNodeParams): void;
|
|
20
|
+
/**
|
|
21
|
+
* Validate subtitle configuration
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateSubtitles(subtitles: ISubtitleConfig[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Validate output configuration
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateOutputConfig(params: ISbRenderNodeParams): void;
|
|
28
|
+
/**
|
|
29
|
+
* Validate all parameters
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateParams(params: ISbRenderNodeParams): void;
|
|
32
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../nodes/SbRender/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE1E;;GAEG;AAEH,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAoBrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAqCnE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAgCzE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,IAAI,CAgDpE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CA6BtE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAUhE"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidationError = void 0;
|
|
4
|
+
exports.validateVideoSource = validateVideoSource;
|
|
5
|
+
exports.validateBGMConfig = validateBGMConfig;
|
|
6
|
+
exports.validateNarrationConfig = validateNarrationConfig;
|
|
7
|
+
exports.validateSubtitles = validateSubtitles;
|
|
8
|
+
exports.validateOutputConfig = validateOutputConfig;
|
|
9
|
+
exports.validateParams = validateParams;
|
|
10
|
+
/**
|
|
11
|
+
* Validation utilities for sb-render node
|
|
12
|
+
*/
|
|
13
|
+
class ValidationError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'ValidationError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ValidationError = ValidationError;
|
|
20
|
+
/**
|
|
21
|
+
* Validate video source configuration
|
|
22
|
+
*/
|
|
23
|
+
function validateVideoSource(params) {
|
|
24
|
+
if (!params.videoSource) {
|
|
25
|
+
throw new ValidationError('Video source must be specified (url or binary)');
|
|
26
|
+
}
|
|
27
|
+
if (params.videoSource === 'url') {
|
|
28
|
+
if (!params.videoUrl || params.videoUrl.trim() === '') {
|
|
29
|
+
throw new ValidationError('Video URL is required when video source is URL');
|
|
30
|
+
}
|
|
31
|
+
if (!isValidUrl(params.videoUrl)) {
|
|
32
|
+
throw new ValidationError('Invalid video URL format');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (params.videoSource === 'binary') {
|
|
36
|
+
if (!params.videoBinaryProperty || params.videoBinaryProperty.trim() === '') {
|
|
37
|
+
throw new ValidationError('Video binary property name is required when video source is binary');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate BGM configuration
|
|
43
|
+
*/
|
|
44
|
+
function validateBGMConfig(params) {
|
|
45
|
+
var _a, _b, _c;
|
|
46
|
+
if (!params.enableBGM)
|
|
47
|
+
return;
|
|
48
|
+
if (!params.bgmSource) {
|
|
49
|
+
throw new ValidationError('BGM source must be specified when BGM is enabled');
|
|
50
|
+
}
|
|
51
|
+
if (params.bgmSource === 'url') {
|
|
52
|
+
if (!params.bgmUrl || params.bgmUrl.trim() === '') {
|
|
53
|
+
throw new ValidationError('BGM URL is required when BGM source is URL');
|
|
54
|
+
}
|
|
55
|
+
if (!isValidUrl(params.bgmUrl)) {
|
|
56
|
+
throw new ValidationError('Invalid BGM URL format');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (params.bgmSource === 'binary') {
|
|
60
|
+
if (!params.bgmBinaryProperty || params.bgmBinaryProperty.trim() === '') {
|
|
61
|
+
throw new ValidationError('BGM binary property name is required when BGM source is binary');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const volume = (_a = params.bgmVolume) !== null && _a !== void 0 ? _a : 30;
|
|
65
|
+
if (volume < 0 || volume > 100) {
|
|
66
|
+
throw new ValidationError('BGM volume must be between 0 and 100');
|
|
67
|
+
}
|
|
68
|
+
const fadeIn = (_b = params.bgmFadeIn) !== null && _b !== void 0 ? _b : 0;
|
|
69
|
+
if (fadeIn < 0) {
|
|
70
|
+
throw new ValidationError('BGM fade-in duration must be non-negative');
|
|
71
|
+
}
|
|
72
|
+
const fadeOut = (_c = params.bgmFadeOut) !== null && _c !== void 0 ? _c : 0;
|
|
73
|
+
if (fadeOut < 0) {
|
|
74
|
+
throw new ValidationError('BGM fade-out duration must be non-negative');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate narration configuration
|
|
79
|
+
*/
|
|
80
|
+
function validateNarrationConfig(params) {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
if (!params.enableNarration)
|
|
83
|
+
return;
|
|
84
|
+
if (!params.narrationSource) {
|
|
85
|
+
throw new ValidationError('Narration source must be specified when narration is enabled');
|
|
86
|
+
}
|
|
87
|
+
if (params.narrationSource === 'url') {
|
|
88
|
+
if (!params.narrationUrl || params.narrationUrl.trim() === '') {
|
|
89
|
+
throw new ValidationError('Narration URL is required when narration source is URL');
|
|
90
|
+
}
|
|
91
|
+
if (!isValidUrl(params.narrationUrl)) {
|
|
92
|
+
throw new ValidationError('Invalid narration URL format');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (params.narrationSource === 'binary') {
|
|
96
|
+
if (!params.narrationBinaryProperty || params.narrationBinaryProperty.trim() === '') {
|
|
97
|
+
throw new ValidationError('Narration binary property name is required when narration source is binary');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const volume = (_a = params.narrationVolume) !== null && _a !== void 0 ? _a : 80;
|
|
101
|
+
if (volume < 0 || volume > 100) {
|
|
102
|
+
throw new ValidationError('Narration volume must be between 0 and 100');
|
|
103
|
+
}
|
|
104
|
+
const delay = (_b = params.narrationDelay) !== null && _b !== void 0 ? _b : 0;
|
|
105
|
+
if (delay < 0) {
|
|
106
|
+
throw new ValidationError('Narration delay must be non-negative');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Validate subtitle configuration
|
|
111
|
+
*/
|
|
112
|
+
function validateSubtitles(subtitles) {
|
|
113
|
+
if (!subtitles || subtitles.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
subtitles.forEach((subtitle, index) => {
|
|
116
|
+
if (!subtitle.text || subtitle.text.trim() === '') {
|
|
117
|
+
throw new ValidationError(`Subtitle ${index + 1}: Text cannot be empty`);
|
|
118
|
+
}
|
|
119
|
+
if (subtitle.startTime < 0) {
|
|
120
|
+
throw new ValidationError(`Subtitle ${index + 1}: Start time cannot be negative`);
|
|
121
|
+
}
|
|
122
|
+
if (subtitle.endTime <= subtitle.startTime) {
|
|
123
|
+
throw new ValidationError(`Subtitle ${index + 1}: End time must be greater than start time`);
|
|
124
|
+
}
|
|
125
|
+
if (subtitle.fontSize <= 0) {
|
|
126
|
+
throw new ValidationError(`Subtitle ${index + 1}: Font size must be positive`);
|
|
127
|
+
}
|
|
128
|
+
if (!isValidColor(subtitle.fontColor)) {
|
|
129
|
+
throw new ValidationError(`Subtitle ${index + 1}: Invalid font color format (use #RRGGBB)`);
|
|
130
|
+
}
|
|
131
|
+
if (subtitle.backgroundColor && !isValidColor(subtitle.backgroundColor)) {
|
|
132
|
+
throw new ValidationError(`Subtitle ${index + 1}: Invalid background color format (use #RRGGBB)`);
|
|
133
|
+
}
|
|
134
|
+
if (subtitle.borderColor && !isValidColor(subtitle.borderColor)) {
|
|
135
|
+
throw new ValidationError(`Subtitle ${index + 1}: Invalid border color format (use #RRGGBB)`);
|
|
136
|
+
}
|
|
137
|
+
if (subtitle.backgroundOpacity !== undefined) {
|
|
138
|
+
if (subtitle.backgroundOpacity < 0 || subtitle.backgroundOpacity > 100) {
|
|
139
|
+
throw new ValidationError(`Subtitle ${index + 1}: Background opacity must be between 0 and 100`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (subtitle.position === 'custom') {
|
|
143
|
+
if (subtitle.customX === undefined || subtitle.customY === undefined) {
|
|
144
|
+
throw new ValidationError(`Subtitle ${index + 1}: Custom position requires customX and customY`);
|
|
145
|
+
}
|
|
146
|
+
if (subtitle.customX < 0 || subtitle.customY < 0) {
|
|
147
|
+
throw new ValidationError(`Subtitle ${index + 1}: Custom position coordinates must be non-negative`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Validate output configuration
|
|
154
|
+
*/
|
|
155
|
+
function validateOutputConfig(params) {
|
|
156
|
+
const validFormats = ['mp4', 'mov', 'webm'];
|
|
157
|
+
if (!validFormats.includes(params.outputFormat)) {
|
|
158
|
+
throw new ValidationError(`Invalid output format: ${params.outputFormat}. Must be one of: ${validFormats.join(', ')}`);
|
|
159
|
+
}
|
|
160
|
+
const validCodecs = ['libx264', 'libx265', 'vp9'];
|
|
161
|
+
if (!validCodecs.includes(params.videoCodec)) {
|
|
162
|
+
throw new ValidationError(`Invalid video codec: ${params.videoCodec}. Must be one of: ${validCodecs.join(', ')}`);
|
|
163
|
+
}
|
|
164
|
+
const validQualities = ['low', 'medium', 'high', 'custom'];
|
|
165
|
+
if (!validQualities.includes(params.quality)) {
|
|
166
|
+
throw new ValidationError(`Invalid quality setting: ${params.quality}. Must be one of: ${validQualities.join(', ')}`);
|
|
167
|
+
}
|
|
168
|
+
if (params.quality === 'custom') {
|
|
169
|
+
if (params.customCRF === undefined) {
|
|
170
|
+
throw new ValidationError('Custom CRF value is required when quality is set to custom');
|
|
171
|
+
}
|
|
172
|
+
if (params.customCRF < 0 || params.customCRF > 51) {
|
|
173
|
+
throw new ValidationError('Custom CRF must be between 0 and 51');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!params.outputBinaryProperty || params.outputBinaryProperty.trim() === '') {
|
|
177
|
+
throw new ValidationError('Output binary property name is required');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Validate all parameters
|
|
182
|
+
*/
|
|
183
|
+
function validateParams(params) {
|
|
184
|
+
validateVideoSource(params);
|
|
185
|
+
validateBGMConfig(params);
|
|
186
|
+
validateNarrationConfig(params);
|
|
187
|
+
if (params.enableSubtitles && params.subtitles) {
|
|
188
|
+
validateSubtitles(params.subtitles);
|
|
189
|
+
}
|
|
190
|
+
validateOutputConfig(params);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if string is a valid URL
|
|
194
|
+
*/
|
|
195
|
+
function isValidUrl(url) {
|
|
196
|
+
try {
|
|
197
|
+
new URL(url);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Check if string is a valid hex color
|
|
206
|
+
*/
|
|
207
|
+
function isValidColor(color) {
|
|
208
|
+
return /^#[0-9A-Fa-f]{6}$/.test(color);
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../../nodes/SbRender/utils/validation.ts"],"names":[],"mappings":";;;AAgBA,kDAoBC;AAKD,8CAqCC;AAKD,0DAgCC;AAKD,8CAgDC;AAKD,oDA6BC;AAKD,wCAUC;AAvND;;GAEG;AAEH,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AALD,0CAKC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,MAA2B;IAC7D,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,eAAe,CAAC,gDAAgD,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,eAAe,CAAC,gDAAgD,CAAC,CAAC;QAC9E,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,eAAe,CAAC,0BAA0B,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC5E,MAAM,IAAI,eAAe,CAAC,oEAAoE,CAAC,CAAC;QAClG,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,MAA2B;;IAC3D,IAAI,CAAC,MAAM,CAAC,SAAS;QAAE,OAAO;IAE9B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,eAAe,CAAC,kDAAkD,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAClD,MAAM,IAAI,eAAe,CAAC,4CAA4C,CAAC,CAAC;QAC1E,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,eAAe,CAAC,wBAAwB,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxE,MAAM,IAAI,eAAe,CAAC,gEAAgE,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAA,MAAM,CAAC,SAAS,mCAAI,EAAE,CAAC;IACtC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QAC/B,MAAM,IAAI,eAAe,CAAC,sCAAsC,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,MAAM,GAAG,MAAA,MAAM,CAAC,SAAS,mCAAI,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,2CAA2C,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,OAAO,GAAG,MAAA,MAAM,CAAC,UAAU,mCAAI,CAAC,CAAC;IACvC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,eAAe,CAAC,4CAA4C,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,uBAAuB,CAAC,MAA2B;;IACjE,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,OAAO;IAEpC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QAC5B,MAAM,IAAI,eAAe,CAAC,8DAA8D,CAAC,CAAC;IAC5F,CAAC;IAED,IAAI,MAAM,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC9D,MAAM,IAAI,eAAe,CAAC,wDAAwD,CAAC,CAAC;QACtF,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,eAAe,CAAC,8BAA8B,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,uBAAuB,IAAI,MAAM,CAAC,uBAAuB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACpF,MAAM,IAAI,eAAe,CAAC,4EAA4E,CAAC,CAAC;QAC1G,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAA,MAAM,CAAC,eAAe,mCAAI,EAAE,CAAC;IAC5C,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QAC/B,MAAM,IAAI,eAAe,CAAC,4CAA4C,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,KAAK,GAAG,MAAA,MAAM,CAAC,cAAc,mCAAI,CAAC,CAAC;IACzC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,eAAe,CAAC,sCAAsC,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,SAA4B;IAC5D,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEjD,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;QACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAClD,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,wBAAwB,CAAC,CAAC;QAC3E,CAAC;QAED,IAAI,QAAQ,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,iCAAiC,CAAC,CAAC;QACpF,CAAC;QAED,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC3C,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC/F,CAAC;QAED,IAAI,QAAQ,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACjF,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,2CAA2C,CAAC,CAAC;QAC9F,CAAC;QAED,IAAI,QAAQ,CAAC,eAAe,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,iDAAiD,CAAC,CAAC;QACpG,CAAC;QAED,IAAI,QAAQ,CAAC,WAAW,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAChG,CAAC;QAED,IAAI,QAAQ,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YAC7C,IAAI,QAAQ,CAAC,iBAAiB,GAAG,CAAC,IAAI,QAAQ,CAAC,iBAAiB,GAAG,GAAG,EAAE,CAAC;gBACvE,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,gDAAgD,CAAC,CAAC;YACnG,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACnC,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACrE,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,gDAAgD,CAAC,CAAC;YACnG,CAAC;YAED,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;gBACjD,MAAM,IAAI,eAAe,CAAC,YAAY,KAAK,GAAG,CAAC,oDAAoD,CAAC,CAAC;YACvG,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAAC,MAA2B;IAC9D,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,eAAe,CAAC,0BAA0B,MAAM,CAAC,YAAY,qBAAqB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzH,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,eAAe,CAAC,wBAAwB,MAAM,CAAC,UAAU,qBAAqB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpH,CAAC;IAED,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3D,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,eAAe,CAAC,4BAA4B,MAAM,CAAC,OAAO,qBAAqB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxH,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,eAAe,CAAC,4DAA4D,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,IAAI,MAAM,CAAC,SAAS,GAAG,EAAE,EAAE,CAAC;YAClD,MAAM,IAAI,eAAe,CAAC,qCAAqC,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9E,MAAM,IAAI,eAAe,CAAC,yCAAyC,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,MAA2B;IACxD,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAEhC,IAAI,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QAC/C,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-sb-render",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n community node for video rendering with customizable subtitles, BGM, and narration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"video",
|
|
9
|
+
"ffmpeg",
|
|
10
|
+
"subtitle",
|
|
11
|
+
"rendering",
|
|
12
|
+
"video-composition"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"homepage": "https://github.com/choisb87/sb-render",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "choisb87",
|
|
18
|
+
"email": "choisb87@gmail.com"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/choisb87/sb-render.git"
|
|
23
|
+
},
|
|
24
|
+
"main": "index.js",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc && gulp build:icons",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"format": "prettier nodes --write",
|
|
29
|
+
"lint": "eslint nodes --ext .ts",
|
|
30
|
+
"lintfix": "eslint nodes --ext .ts --fix",
|
|
31
|
+
"prepublishOnly": "npm run build && npm run lint"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"fonts"
|
|
36
|
+
],
|
|
37
|
+
"n8n": {
|
|
38
|
+
"n8nNodesApiVersion": 1,
|
|
39
|
+
"credentials": [],
|
|
40
|
+
"nodes": [
|
|
41
|
+
"dist/nodes/SbRender/SbRender.node.js"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/fluent-ffmpeg": "^2.1.21",
|
|
46
|
+
"@types/node": "^18.16.0",
|
|
47
|
+
"@types/node-fetch": "^2.6.13",
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
|
49
|
+
"@typescript-eslint/parser": "^5.59.0",
|
|
50
|
+
"eslint": "^8.40.0",
|
|
51
|
+
"eslint-plugin-n8n-nodes-base": "^1.11.0",
|
|
52
|
+
"gulp": "^4.0.2",
|
|
53
|
+
"n8n-workflow": "^1.0.0",
|
|
54
|
+
"prettier": "^2.8.8",
|
|
55
|
+
"typescript": "^5.0.4"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
59
|
+
"fluent-ffmpeg": "^2.1.2",
|
|
60
|
+
"node-fetch": "^2.6.12",
|
|
61
|
+
"tmp-promise": "^3.0.3"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"n8n-workflow": "*"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=16.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|