@lee-jisoo/n8n-nodes-mediafx 1.6.0 → 1.6.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.
Files changed (55) hide show
  1. package/dist/fonts/DejaVuSans.ttf +0 -0
  2. package/dist/fonts/Inter-Regular.ttf +0 -0
  3. package/dist/fonts/NanumGothic-Regular.ttf +0 -0
  4. package/dist/fonts/NotoSansKR-Regular.ttf +0 -0
  5. package/dist/fonts/Pretendard-Regular.otf +0 -0
  6. package/dist/fonts/Roboto-Regular.ttf +0 -0
  7. package/dist/nodes/MediaFX/MediaFX.node.d.ts +12 -0
  8. package/dist/nodes/MediaFX/MediaFX.node.js +559 -0
  9. package/dist/nodes/MediaFX/mediafx.png +0 -0
  10. package/dist/nodes/MediaFX/operations/addSubtitle.d.ts +2 -0
  11. package/dist/nodes/MediaFX/operations/addSubtitle.js +146 -0
  12. package/dist/nodes/MediaFX/operations/addText.d.ts +2 -0
  13. package/dist/nodes/MediaFX/operations/addText.js +108 -0
  14. package/dist/nodes/MediaFX/operations/extractAudio.d.ts +2 -0
  15. package/dist/nodes/MediaFX/operations/extractAudio.js +57 -0
  16. package/dist/nodes/MediaFX/operations/imageToVideo.d.ts +5 -0
  17. package/dist/nodes/MediaFX/operations/imageToVideo.js +65 -0
  18. package/dist/nodes/MediaFX/operations/index.d.ts +13 -0
  19. package/dist/nodes/MediaFX/operations/index.js +29 -0
  20. package/dist/nodes/MediaFX/operations/merge.d.ts +2 -0
  21. package/dist/nodes/MediaFX/operations/merge.js +121 -0
  22. package/dist/nodes/MediaFX/operations/mixAudio.d.ts +2 -0
  23. package/dist/nodes/MediaFX/operations/mixAudio.js +141 -0
  24. package/dist/nodes/MediaFX/operations/multiVideoTransition.d.ts +2 -0
  25. package/dist/nodes/MediaFX/operations/multiVideoTransition.js +245 -0
  26. package/dist/nodes/MediaFX/operations/overlayVideo.d.ts +16 -0
  27. package/dist/nodes/MediaFX/operations/overlayVideo.js +240 -0
  28. package/dist/nodes/MediaFX/operations/separateAudio.d.ts +17 -0
  29. package/dist/nodes/MediaFX/operations/separateAudio.js +78 -0
  30. package/dist/nodes/MediaFX/operations/singleVideoFade.d.ts +2 -0
  31. package/dist/nodes/MediaFX/operations/singleVideoFade.js +60 -0
  32. package/dist/nodes/MediaFX/operations/speed.d.ts +12 -0
  33. package/dist/nodes/MediaFX/operations/speed.js +110 -0
  34. package/dist/nodes/MediaFX/operations/stampImage.d.ts +2 -0
  35. package/dist/nodes/MediaFX/operations/stampImage.js +146 -0
  36. package/dist/nodes/MediaFX/operations/trim.d.ts +2 -0
  37. package/dist/nodes/MediaFX/operations/trim.js +49 -0
  38. package/dist/nodes/MediaFX/properties/audio.properties.d.ts +2 -0
  39. package/dist/nodes/MediaFX/properties/audio.properties.js +394 -0
  40. package/dist/nodes/MediaFX/properties/font.properties.d.ts +2 -0
  41. package/dist/nodes/MediaFX/properties/font.properties.js +186 -0
  42. package/dist/nodes/MediaFX/properties/image.properties.d.ts +2 -0
  43. package/dist/nodes/MediaFX/properties/image.properties.js +333 -0
  44. package/dist/nodes/MediaFX/properties/resources.properties.d.ts +2 -0
  45. package/dist/nodes/MediaFX/properties/resources.properties.js +34 -0
  46. package/dist/nodes/MediaFX/properties/subtitle.properties.d.ts +2 -0
  47. package/dist/nodes/MediaFX/properties/subtitle.properties.js +306 -0
  48. package/dist/nodes/MediaFX/properties/video.properties.d.ts +2 -0
  49. package/dist/nodes/MediaFX/properties/video.properties.js +1135 -0
  50. package/dist/nodes/MediaFX/utils/ffmpegVersion.d.ts +14 -0
  51. package/dist/nodes/MediaFX/utils/ffmpegVersion.js +97 -0
  52. package/dist/nodes/MediaFX/utils.d.ts +43 -0
  53. package/dist/nodes/MediaFX/utils.js +410 -0
  54. package/package.json +1 -1
  55. package/CHANGELOG.md +0 -65
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.executeSeparateAudio = void 0;
27
+ const n8n_workflow_1 = require("n8n-workflow");
28
+ const ffmpeg = require("fluent-ffmpeg");
29
+ const utils_1 = require("../utils");
30
+ const fs = __importStar(require("fs-extra"));
31
+ /**
32
+ * Separates audio from video, returning both a muted video and the extracted audio track.
33
+ *
34
+ * @param input - Path to the input video file
35
+ * @param videoFormat - Output format for the muted video (e.g., 'mp4', 'mov')
36
+ * @param audioFormat - Output format for the extracted audio (e.g., 'mp3', 'aac', 'wav')
37
+ * @param audioCodec - Audio codec to use (e.g., 'copy', 'libmp3lame', 'aac')
38
+ * @param audioBitrate - Audio bitrate (e.g., '192k', '320k')
39
+ * @param itemIndex - Current item index for error handling
40
+ * @returns Object containing paths to both the muted video and extracted audio
41
+ */
42
+ async function executeSeparateAudio(input, videoFormat, audioFormat, audioCodec, audioBitrate, itemIndex) {
43
+ const mutedVideoPath = (0, utils_1.getTempFile)(`.${videoFormat}`);
44
+ const audioOutputPath = (0, utils_1.getTempFile)(`.${audioFormat}`);
45
+ let finalAudioCodec = audioCodec;
46
+ // If stream copy ('copy') is selected for a format that requires a specific
47
+ // codec (like mp3), we must override it to prevent an FFmpeg error.
48
+ if (finalAudioCodec === 'copy' && audioFormat === 'mp3') {
49
+ finalAudioCodec = 'libmp3lame';
50
+ }
51
+ try {
52
+ // Step 1: Create muted video (remove audio track)
53
+ const mutedVideoCommand = ffmpeg(input)
54
+ .output(mutedVideoPath)
55
+ .noAudio()
56
+ .videoCodec('copy'); // Copy video stream without re-encoding
57
+ await (0, utils_1.runFfmpeg)(mutedVideoCommand);
58
+ // Step 2: Extract audio track
59
+ const audioCommand = ffmpeg(input)
60
+ .output(audioOutputPath)
61
+ .noVideo()
62
+ .audioCodec(finalAudioCodec)
63
+ .audioBitrate(audioBitrate)
64
+ .outputOptions('-map', '0:a:0'); // Select first audio stream
65
+ await (0, utils_1.runFfmpeg)(audioCommand);
66
+ return {
67
+ videoPath: mutedVideoPath,
68
+ audioPath: audioOutputPath,
69
+ };
70
+ }
71
+ catch (error) {
72
+ // Clean up any created files on error
73
+ await fs.remove(mutedVideoPath).catch(() => { });
74
+ await fs.remove(audioOutputPath).catch(() => { });
75
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Error separating audio from video. Please ensure the source video contains both video and audio tracks. FFmpeg error: ${error.message}`, { itemIndex });
76
+ }
77
+ }
78
+ exports.executeSeparateAudio = executeSeparateAudio;
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ export declare function executeSingleVideoFade(this: IExecuteFunctions, input: string, effect: 'in' | 'out', startTime: number, duration: number, outputFormat: string, itemIndex: number): Promise<string>;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.executeSingleVideoFade = void 0;
27
+ const n8n_workflow_1 = require("n8n-workflow");
28
+ const ffmpeg = require("fluent-ffmpeg");
29
+ const utils_1 = require("../utils");
30
+ const fs = __importStar(require("fs-extra"));
31
+ async function executeSingleVideoFade(input,
32
+ // effect is 'in' or 'out' from the UI options
33
+ effect, startTime, duration, outputFormat, itemIndex) {
34
+ const outputPath = (0, utils_1.getTempFile)(`.${outputFormat}`);
35
+ const command = ffmpeg(input);
36
+ // Apply both video and audio fades for a consistent effect
37
+ const videoFade = `fade=type=${effect}:st=${startTime}:d=${duration}`;
38
+ const audioFade = `afade=type=${effect}:st=${startTime}:d=${duration}`;
39
+ command.videoFilters(videoFade).audioFilters(audioFade);
40
+ command.save(outputPath);
41
+ try {
42
+ await (0, utils_1.runFfmpeg)(command);
43
+ return outputPath;
44
+ }
45
+ catch (error) {
46
+ // Clean up output file if creation failed
47
+ await fs.remove(outputPath).catch(() => { });
48
+ // If the video has no audio, ffmpeg might throw an error for afade.
49
+ // We provide a more descriptive error message in that case.
50
+ const errorMessage = error.message;
51
+ let displayMessage = `Error applying fade effect. Please check the effect parameters (start time, duration).`;
52
+ if (errorMessage.includes('Cannot find a matching stream for unlabeled')) {
53
+ displayMessage = `Error applying audio fade: The source video may not have an audio track.`;
54
+ }
55
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `${displayMessage} FFmpeg error: ${errorMessage}`, {
56
+ itemIndex,
57
+ });
58
+ }
59
+ }
60
+ exports.executeSingleVideoFade = executeSingleVideoFade;
@@ -0,0 +1,12 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ /**
3
+ * Execute speed adjustment on a video.
4
+ *
5
+ * @param input - Path to the input video file
6
+ * @param speed - Speed multiplier (0.25 = 4x slower, 2.0 = 2x faster, etc.)
7
+ * @param adjustAudio - Whether to adjust audio speed as well (pitch will change)
8
+ * @param maintainPitch - Whether to maintain audio pitch when adjusting speed (requires rubberband filter)
9
+ * @param outputFormat - Output file format
10
+ * @param itemIndex - Index of the current item being processed
11
+ */
12
+ export declare function executeSpeed(this: IExecuteFunctions, input: string, speed: number, adjustAudio: boolean, maintainPitch: boolean, outputFormat: string, itemIndex: number): Promise<string>;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.executeSpeed = void 0;
27
+ const n8n_workflow_1 = require("n8n-workflow");
28
+ const ffmpeg = require("fluent-ffmpeg");
29
+ const utils_1 = require("../utils");
30
+ const fs = __importStar(require("fs-extra"));
31
+ /**
32
+ * Execute speed adjustment on a video.
33
+ *
34
+ * @param input - Path to the input video file
35
+ * @param speed - Speed multiplier (0.25 = 4x slower, 2.0 = 2x faster, etc.)
36
+ * @param adjustAudio - Whether to adjust audio speed as well (pitch will change)
37
+ * @param maintainPitch - Whether to maintain audio pitch when adjusting speed (requires rubberband filter)
38
+ * @param outputFormat - Output file format
39
+ * @param itemIndex - Index of the current item being processed
40
+ */
41
+ async function executeSpeed(input, speed, adjustAudio, maintainPitch, outputFormat, itemIndex) {
42
+ const outputPath = (0, utils_1.getTempFile)(`.${outputFormat}`);
43
+ // Validate speed value
44
+ if (speed <= 0) {
45
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Speed must be greater than 0', { itemIndex });
46
+ }
47
+ // FFmpeg uses PTS (Presentation Time Stamp) for video speed
48
+ // setpts=0.5*PTS means 2x faster (less time per frame)
49
+ // setpts=2*PTS means 2x slower (more time per frame)
50
+ const videoPtsFactor = 1 / speed;
51
+ const videoFilter = `setpts=${videoPtsFactor}*PTS`;
52
+ // For audio, atempo filter accepts values between 0.5 and 2.0
53
+ // For values outside this range, we need to chain multiple atempo filters
54
+ const buildAtempoFilter = (targetSpeed) => {
55
+ const filters = [];
56
+ let remaining = targetSpeed;
57
+ // atempo only accepts 0.5 to 2.0, so we chain multiple filters
58
+ while (remaining > 2.0) {
59
+ filters.push('atempo=2.0');
60
+ remaining /= 2.0;
61
+ }
62
+ while (remaining < 0.5) {
63
+ filters.push('atempo=0.5');
64
+ remaining /= 0.5;
65
+ }
66
+ filters.push(`atempo=${remaining}`);
67
+ return filters;
68
+ };
69
+ try {
70
+ let command = ffmpeg(input);
71
+ // Apply video speed filter
72
+ command = command.videoFilters([videoFilter]);
73
+ if (adjustAudio) {
74
+ if (maintainPitch) {
75
+ // Use rubberband filter to maintain pitch (requires libavfilter compiled with rubberband)
76
+ // Fallback to atempo if rubberband is not available
77
+ try {
78
+ const audioFilter = `rubberband=tempo=${speed}`;
79
+ command = command.audioFilters([audioFilter]);
80
+ }
81
+ catch {
82
+ // Fallback to atempo (pitch will change slightly)
83
+ const atempoFilters = buildAtempoFilter(speed);
84
+ command = command.audioFilters(atempoFilters);
85
+ }
86
+ }
87
+ else {
88
+ // Use atempo filter (pitch will change proportionally)
89
+ const atempoFilters = buildAtempoFilter(speed);
90
+ command = command.audioFilters(atempoFilters);
91
+ }
92
+ }
93
+ else {
94
+ // Remove audio entirely when not adjusting
95
+ command = command.noAudio();
96
+ }
97
+ command = command
98
+ .videoCodec('libx264')
99
+ .audioCodec('aac')
100
+ .output(outputPath);
101
+ await (0, utils_1.runFfmpeg)(command);
102
+ return outputPath;
103
+ }
104
+ catch (error) {
105
+ // Clean up output file if creation failed
106
+ await fs.remove(outputPath).catch(() => { });
107
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Error adjusting video speed. FFmpeg error: ${error.message}`, { itemIndex });
108
+ }
109
+ }
110
+ exports.executeSpeed = executeSpeed;
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions, IDataObject } from 'n8n-workflow';
2
+ export declare function executeStampImage(this: IExecuteFunctions, videoPath: string, imagePath: string, options: IDataObject, itemIndex: number): Promise<string>;
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.executeStampImage = void 0;
27
+ const n8n_workflow_1 = require("n8n-workflow");
28
+ const path = __importStar(require("path"));
29
+ const ffmpeg = require("fluent-ffmpeg");
30
+ const utils_1 = require("../utils");
31
+ const fs = __importStar(require("fs-extra"));
32
+ async function executeStampImage(videoPath, imagePath, options, itemIndex) {
33
+ var _a;
34
+ const outputPath = (0, utils_1.getTempFile)(path.extname(videoPath));
35
+ // Basic stamp options
36
+ const width = options.width || 150;
37
+ const height = options.height || -1;
38
+ const x = options.x || '10';
39
+ const y = options.y || '10';
40
+ const rotationDegrees = options.rotation || 0;
41
+ const opacity = (_a = options.opacity) !== null && _a !== void 0 ? _a : 1.0;
42
+ // Time control options
43
+ const enableTimeControl = options.enableTimeControl;
44
+ const startTime = options.startTime || 0;
45
+ const endTime = options.endTime || 5;
46
+ try {
47
+ // Get video duration for calculations
48
+ // const videoDuration = await getDuration(videoPath);
49
+ // console.log('=== STAMP IMAGE DEBUG ===');
50
+ // console.log('Video path:', videoPath);
51
+ // console.log('Image path:', imagePath);
52
+ // console.log('Video duration:', videoDuration);
53
+ // console.log('Stamp options:', {
54
+ // width, height, x, y, rotationDegrees, opacity,
55
+ // enableTimeControl, startTime, endTime
56
+ // });
57
+ // Start with the simplest possible filter
58
+ let complexFilter = '';
59
+ // Check if we need any processing
60
+ const needsScaling = width !== -1 || height !== -1;
61
+ const needsRotation = rotationDegrees !== 0;
62
+ const needsOpacity = opacity < 1.0;
63
+ const needsProcessing = needsScaling || needsRotation || needsOpacity;
64
+ if (!needsProcessing && !enableTimeControl) {
65
+ // Simplest case: direct overlay
66
+ complexFilter = '[0:v][1:v]overlay=x=' + x + ':y=' + y;
67
+ }
68
+ else if (!enableTimeControl) {
69
+ // Process image but no time control
70
+ let imageFilter = '[1:v]';
71
+ if (needsScaling) {
72
+ imageFilter += 'scale=' + width + ':' + height;
73
+ }
74
+ if (needsRotation) {
75
+ if (!needsScaling) {
76
+ imageFilter += 'rotate=' + (rotationDegrees * Math.PI / 180) + ':fillcolor=none';
77
+ }
78
+ else {
79
+ imageFilter += ',rotate=' + (rotationDegrees * Math.PI / 180) + ':fillcolor=none';
80
+ }
81
+ }
82
+ if (needsOpacity) {
83
+ if (!needsScaling && !needsRotation) {
84
+ imageFilter += 'colorchannelmixer=aa=' + opacity;
85
+ }
86
+ else {
87
+ imageFilter += ',colorchannelmixer=aa=' + opacity;
88
+ }
89
+ }
90
+ imageFilter += '[processed]';
91
+ complexFilter = imageFilter + ';[0:v][processed]overlay=x=' + x + ':y=' + y;
92
+ }
93
+ else {
94
+ // With time control
95
+ let imageFilter = '[1:v]';
96
+ if (needsScaling) {
97
+ imageFilter += 'scale=' + width + ':' + height;
98
+ }
99
+ if (needsRotation) {
100
+ if (!needsScaling) {
101
+ imageFilter += 'rotate=' + (rotationDegrees * Math.PI / 180) + ':fillcolor=none';
102
+ }
103
+ else {
104
+ imageFilter += ',rotate=' + (rotationDegrees * Math.PI / 180) + ':fillcolor=none';
105
+ }
106
+ }
107
+ if (needsOpacity) {
108
+ if (!needsScaling && !needsRotation) {
109
+ imageFilter += 'colorchannelmixer=aa=' + opacity;
110
+ }
111
+ else {
112
+ imageFilter += ',colorchannelmixer=aa=' + opacity;
113
+ }
114
+ }
115
+ if (needsProcessing) {
116
+ imageFilter += '[processed]';
117
+ complexFilter = imageFilter + ';[0:v][processed]overlay=x=' + x + ':y=' + y;
118
+ }
119
+ else {
120
+ complexFilter = '[0:v][1:v]overlay=x=' + x + ':y=' + y;
121
+ }
122
+ // Add time control
123
+ if (enableTimeControl) {
124
+ complexFilter += ':enable=\'between(t,' + startTime + ',' + endTime + ')\'';
125
+ }
126
+ }
127
+ console.log('Generated FFmpeg filter:', complexFilter);
128
+ console.log('========================');
129
+ const command = ffmpeg()
130
+ .input(videoPath)
131
+ .input(imagePath)
132
+ .complexFilter(complexFilter)
133
+ .output(outputPath);
134
+ await (0, utils_1.runFfmpeg)(command);
135
+ return outputPath;
136
+ }
137
+ catch (error) {
138
+ // Clean up output file if creation failed
139
+ await fs.remove(outputPath).catch(() => { });
140
+ console.error('=== STAMP IMAGE ERROR ===');
141
+ console.error('Error details:', error);
142
+ console.error('========================');
143
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to stamp image: ${error instanceof Error ? error.message : 'Unknown error'}`, { itemIndex });
144
+ }
145
+ }
146
+ exports.executeStampImage = executeStampImage;
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ export declare function executeTrim(this: IExecuteFunctions, input: string, from: number, to: number, outputFormat: string, itemIndex: number): Promise<string>;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.executeTrim = void 0;
27
+ const n8n_workflow_1 = require("n8n-workflow");
28
+ const ffmpeg = require("fluent-ffmpeg");
29
+ const utils_1 = require("../utils");
30
+ const fs = __importStar(require("fs-extra"));
31
+ async function executeTrim(input, from, to, outputFormat, itemIndex) {
32
+ const outputPath = (0, utils_1.getTempFile)(`.${outputFormat}`);
33
+ const command = ffmpeg(input)
34
+ .setStartTime(from)
35
+ .setDuration(to - from)
36
+ .output(outputPath)
37
+ .videoCodec('libx264')
38
+ .audioCodec('aac');
39
+ try {
40
+ await (0, utils_1.runFfmpeg)(command);
41
+ return outputPath;
42
+ }
43
+ catch (error) {
44
+ // Clean up output file if creation failed
45
+ await fs.remove(outputPath).catch(() => { });
46
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Error trimming video. Please check that start and end times are valid and within the video's duration. FFmpeg error: ${error.message}`, { itemIndex });
47
+ }
48
+ }
49
+ exports.executeTrim = executeTrim;
@@ -0,0 +1,2 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const audioProperties: INodeProperties[];