ugcinc 4.5.19 → 4.5.21
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.
|
@@ -45,11 +45,15 @@ interface VideoModelOption {
|
|
|
45
45
|
/** Reference-to-video variant, if one exists */
|
|
46
46
|
refId?: VideoGenerationReferenceModel;
|
|
47
47
|
}
|
|
48
|
+
/** A single media item in a selection pool */
|
|
49
|
+
interface VideoMediaItem {
|
|
50
|
+
id: string;
|
|
51
|
+
url: string;
|
|
52
|
+
}
|
|
48
53
|
/** Static or variable reference image input */
|
|
49
54
|
interface ReferenceImageInput {
|
|
50
55
|
isVariable: boolean;
|
|
51
|
-
|
|
52
|
-
mediaUrl: string | null;
|
|
56
|
+
mediaItems: VideoMediaItem[];
|
|
53
57
|
}
|
|
54
58
|
declare const ALL_VIDEO_MODELS: VideoModelOption[];
|
|
55
59
|
/** @deprecated Use getImageToVideoModelId instead — I2V mode is auto-detected from image input */
|
|
@@ -76,16 +80,13 @@ declare const definition: import("./types").NodeDefinition<"generate-video", "ge
|
|
|
76
80
|
duration: number;
|
|
77
81
|
prompt: string;
|
|
78
82
|
promptIsVariable: boolean;
|
|
79
|
-
imageIsVariable: boolean;
|
|
80
|
-
imageMediaId: string | null;
|
|
81
|
-
imageMediaUrl: string | null;
|
|
82
83
|
inputMode: VideoInputMode;
|
|
84
|
+
imageIsVariable: boolean;
|
|
85
|
+
imageMediaItems: VideoMediaItem[];
|
|
83
86
|
firstFrameIsVariable: boolean;
|
|
84
|
-
|
|
85
|
-
firstFrameMediaUrl: string | null;
|
|
87
|
+
firstFrameMediaItems: VideoMediaItem[];
|
|
86
88
|
lastFrameIsVariable: boolean;
|
|
87
|
-
|
|
88
|
-
lastFrameMediaUrl: string | null;
|
|
89
|
+
lastFrameMediaItems: VideoMediaItem[];
|
|
89
90
|
referenceImages: ReferenceImageInput[];
|
|
90
91
|
outputMode: OutputMode;
|
|
91
92
|
selectionMode: SelectionMode | null;
|
|
@@ -96,5 +97,5 @@ declare const _default: typeof definition & {
|
|
|
96
97
|
};
|
|
97
98
|
export default _default;
|
|
98
99
|
export { isImageToVideoModel, getImageToVideoModelId, hasImageToVideoVariant, getFirstLastFrameModelId, hasFirstLastFrameVariant, getReferenceModelId, hasReferenceVariant, getAvailableInputModes, ALL_VIDEO_MODELS, getModelAspectRatios, getModelDurations, };
|
|
99
|
-
export type { VideoGenerationTextToVideoModel, VideoGenerationImageToVideoModel, VideoGenerationFirstLastFrameModel, VideoGenerationReferenceModel, VideoGenerationModel, VideoInputMode, VideoModelProvider, VideoModelTier, VideoAspectRatioOption, VideoDurationOption, VideoModelOption, ReferenceImageInput, };
|
|
100
|
+
export type { VideoGenerationTextToVideoModel, VideoGenerationImageToVideoModel, VideoGenerationFirstLastFrameModel, VideoGenerationReferenceModel, VideoGenerationModel, VideoInputMode, VideoMediaItem, VideoModelProvider, VideoModelTier, VideoAspectRatioOption, VideoDurationOption, VideoModelOption, ReferenceImageInput, };
|
|
100
101
|
export type GenerateVideoNodeConfig = typeof definition.defaults;
|
|
@@ -127,17 +127,15 @@ const definition = (0, types_1.defineNode)({
|
|
|
127
127
|
duration: 5,
|
|
128
128
|
prompt: '',
|
|
129
129
|
promptIsVariable: false,
|
|
130
|
-
imageIsVariable: false,
|
|
131
|
-
imageMediaId: null,
|
|
132
|
-
imageMediaUrl: null,
|
|
133
130
|
inputMode: 'none',
|
|
131
|
+
// Image-to-video
|
|
132
|
+
imageIsVariable: false,
|
|
133
|
+
imageMediaItems: [],
|
|
134
134
|
// First-last-frame
|
|
135
135
|
firstFrameIsVariable: false,
|
|
136
|
-
|
|
137
|
-
firstFrameMediaUrl: null,
|
|
136
|
+
firstFrameMediaItems: [],
|
|
138
137
|
lastFrameIsVariable: false,
|
|
139
|
-
|
|
140
|
-
lastFrameMediaUrl: null,
|
|
138
|
+
lastFrameMediaItems: [],
|
|
141
139
|
// Reference
|
|
142
140
|
referenceImages: [],
|
|
143
141
|
outputMode: 'per-input',
|
|
@@ -175,16 +175,13 @@ export declare const nodeDefinitions: {
|
|
|
175
175
|
duration: number;
|
|
176
176
|
prompt: string;
|
|
177
177
|
promptIsVariable: boolean;
|
|
178
|
-
imageIsVariable: boolean;
|
|
179
|
-
imageMediaId: string | null;
|
|
180
|
-
imageMediaUrl: string | null;
|
|
181
178
|
inputMode: import("./generate-video").VideoInputMode;
|
|
179
|
+
imageIsVariable: boolean;
|
|
180
|
+
imageMediaItems: import("./generate-video").VideoMediaItem[];
|
|
182
181
|
firstFrameIsVariable: boolean;
|
|
183
|
-
|
|
184
|
-
firstFrameMediaUrl: string | null;
|
|
182
|
+
firstFrameMediaItems: import("./generate-video").VideoMediaItem[];
|
|
185
183
|
lastFrameIsVariable: boolean;
|
|
186
|
-
|
|
187
|
-
lastFrameMediaUrl: string | null;
|
|
184
|
+
lastFrameMediaItems: import("./generate-video").VideoMediaItem[];
|
|
188
185
|
referenceImages: import("./generate-video").ReferenceImageInput[];
|
|
189
186
|
outputMode: import("./types").OutputMode;
|
|
190
187
|
selectionMode: import("./types").SelectionMode | null;
|
|
@@ -37,7 +37,8 @@ const definition = (0, types_1.defineNode)({
|
|
|
37
37
|
channel.segments.forEach(segment => {
|
|
38
38
|
// inputRef exists on all segments except 'text'
|
|
39
39
|
if (segment.type !== 'text') {
|
|
40
|
-
|
|
40
|
+
const isVar = !('isVariable' in segment) || segment.isVariable !== false;
|
|
41
|
+
if (segment.inputRef && !addedIds.has(segment.inputRef) && isVar) {
|
|
41
42
|
addedIds.add(segment.inputRef);
|
|
42
43
|
const inputType = segment.type === 'video' || segment.type === 'video-sequence' ? 'video'
|
|
43
44
|
: segment.type === 'audio' ? 'audio'
|
|
@@ -52,7 +53,7 @@ const definition = (0, types_1.defineNode)({
|
|
|
52
53
|
}
|
|
53
54
|
// textInputRef only exists on 'text' segments
|
|
54
55
|
if (segment.type === 'text') {
|
|
55
|
-
if (segment.textInputRef && !addedIds.has(segment.textInputRef)) {
|
|
56
|
+
if (segment.textInputRef && !addedIds.has(segment.textInputRef) && segment.textIsVariable !== false) {
|
|
56
57
|
addedIds.add(segment.textInputRef);
|
|
57
58
|
inputs.push({
|
|
58
59
|
id: segment.textInputRef,
|
|
@@ -87,8 +88,13 @@ const definition = (0, types_1.defineNode)({
|
|
|
87
88
|
for (const channel of editorConfig.channels) {
|
|
88
89
|
for (const segment of channel.segments) {
|
|
89
90
|
if (segment.type !== 'text') {
|
|
90
|
-
// Media segments
|
|
91
|
-
if (segment.
|
|
91
|
+
// Media segments - static or variable
|
|
92
|
+
if ('isVariable' in segment && segment.isVariable === false) {
|
|
93
|
+
const url = segment.staticMedia?.[0]?.url;
|
|
94
|
+
if (url)
|
|
95
|
+
sources[segment.id] = url;
|
|
96
|
+
}
|
|
97
|
+
else if (segment.inputRef) {
|
|
92
98
|
const url = editorConfig.previewUrls?.[segment.inputRef];
|
|
93
99
|
if (url) {
|
|
94
100
|
sources[segment.id] = url;
|
|
@@ -96,8 +102,12 @@ const definition = (0, types_1.defineNode)({
|
|
|
96
102
|
}
|
|
97
103
|
}
|
|
98
104
|
else {
|
|
99
|
-
// Text segments
|
|
100
|
-
if (segment.
|
|
105
|
+
// Text segments - static or variable
|
|
106
|
+
if (segment.textIsVariable === false) {
|
|
107
|
+
if (segment.text)
|
|
108
|
+
textContent[segment.id] = segment.text;
|
|
109
|
+
}
|
|
110
|
+
else if (segment.textInputRef) {
|
|
101
111
|
const text = editorConfig.previewTextValues?.[segment.textInputRef];
|
|
102
112
|
if (text) {
|
|
103
113
|
textContent[segment.id] = text;
|
|
@@ -173,82 +183,109 @@ function transformSegment(segment, inputs) {
|
|
|
173
183
|
let result = { ...segment };
|
|
174
184
|
// Handle inputRef for media segments
|
|
175
185
|
if ('inputRef' in segment && segment.inputRef) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const keysToOmit = ['inputRef', 'timeMode', 'itemCountMode', 'staticItemCount'];
|
|
194
|
-
const transformed = {
|
|
195
|
-
...omit(segment, [...keysToOmit]),
|
|
196
|
-
type: 'image-sequence',
|
|
197
|
-
source: '',
|
|
198
|
-
items,
|
|
199
|
-
};
|
|
200
|
-
result = transformed;
|
|
201
|
-
}
|
|
202
|
-
else if (segment.type === 'video-sequence') {
|
|
203
|
-
if (!Array.isArray(value)) {
|
|
204
|
-
throw new Error(`Video sequence expects VideoValue[] for "${inputKey}", got ${typeof value}`);
|
|
205
|
-
}
|
|
206
|
-
let items = value.map(v => v.url);
|
|
207
|
-
if (segment.itemCountMode === 'static' && segment.staticItemCount !== undefined) {
|
|
208
|
-
items = items.slice(0, segment.staticItemCount);
|
|
186
|
+
if ('isVariable' in segment && segment.isVariable === false) {
|
|
187
|
+
// Static: pick random from staticMedia
|
|
188
|
+
const items = segment.staticMedia;
|
|
189
|
+
if (items?.length) {
|
|
190
|
+
const pick = items[Math.floor(Math.random() * items.length)];
|
|
191
|
+
if (pick?.url) {
|
|
192
|
+
const keysToOmit = ['inputRef', 'timeMode', 'isVariable', 'staticMedia'];
|
|
193
|
+
if (segment.type === 'video') {
|
|
194
|
+
result = { ...omit(segment, [...keysToOmit]), type: 'video', source: pick.url };
|
|
195
|
+
}
|
|
196
|
+
else if (segment.type === 'audio') {
|
|
197
|
+
result = { ...omit(segment, [...keysToOmit]), type: 'audio', source: pick.url };
|
|
198
|
+
}
|
|
199
|
+
else if (segment.type === 'image') {
|
|
200
|
+
result = { ...omit(segment, [...keysToOmit]), type: 'image', source: pick.url };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
209
203
|
}
|
|
210
|
-
const keysToOmit = ['inputRef', 'timeMode', 'itemCountMode', 'staticItemCount'];
|
|
211
|
-
const transformed = {
|
|
212
|
-
...omit(segment, [...keysToOmit]),
|
|
213
|
-
type: 'video-sequence',
|
|
214
|
-
source: '',
|
|
215
|
-
items,
|
|
216
|
-
};
|
|
217
|
-
result = transformed;
|
|
218
204
|
}
|
|
219
205
|
else {
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
|
|
206
|
+
const inputKey = segment.inputRef;
|
|
207
|
+
const value = inputs[inputKey];
|
|
208
|
+
if (value === undefined || value === null) {
|
|
209
|
+
if (segment.required === false) {
|
|
210
|
+
return null; // Optional segment with missing input
|
|
211
|
+
}
|
|
212
|
+
throw new Error(`Required segment input "${inputKey}" was not provided`);
|
|
224
213
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
214
|
+
// Image sequence segments expect array of media values
|
|
215
|
+
if (segment.type === 'image-sequence') {
|
|
216
|
+
if (!Array.isArray(value)) {
|
|
217
|
+
throw new Error(`Image sequence expects ImageValue[] for "${inputKey}", got ${typeof value}`);
|
|
218
|
+
}
|
|
219
|
+
let items = value.map(v => v.url);
|
|
220
|
+
if (segment.itemCountMode === 'static' && segment.staticItemCount !== undefined) {
|
|
221
|
+
items = items.slice(0, segment.staticItemCount);
|
|
222
|
+
}
|
|
223
|
+
const keysToOmit = ['inputRef', 'timeMode', 'itemCountMode', 'staticItemCount'];
|
|
224
|
+
const transformed = {
|
|
225
|
+
...omit(segment, [...keysToOmit]),
|
|
226
|
+
type: 'image-sequence',
|
|
227
|
+
source: '',
|
|
228
|
+
items,
|
|
229
|
+
};
|
|
230
|
+
result = transformed;
|
|
229
231
|
}
|
|
230
|
-
else if (segment.type === '
|
|
231
|
-
|
|
232
|
+
else if (segment.type === 'video-sequence') {
|
|
233
|
+
if (!Array.isArray(value)) {
|
|
234
|
+
throw new Error(`Video sequence expects VideoValue[] for "${inputKey}", got ${typeof value}`);
|
|
235
|
+
}
|
|
236
|
+
let items = value.map(v => v.url);
|
|
237
|
+
if (segment.itemCountMode === 'static' && segment.staticItemCount !== undefined) {
|
|
238
|
+
items = items.slice(0, segment.staticItemCount);
|
|
239
|
+
}
|
|
240
|
+
const keysToOmit = ['inputRef', 'timeMode', 'itemCountMode', 'staticItemCount'];
|
|
241
|
+
const transformed = {
|
|
242
|
+
...omit(segment, [...keysToOmit]),
|
|
243
|
+
type: 'video-sequence',
|
|
244
|
+
source: '',
|
|
245
|
+
items,
|
|
246
|
+
};
|
|
247
|
+
result = transformed;
|
|
232
248
|
}
|
|
233
|
-
else
|
|
234
|
-
|
|
249
|
+
else {
|
|
250
|
+
// Single media segment (image/video/audio) - extract .url from value object
|
|
251
|
+
const mediaValue = value;
|
|
252
|
+
if (!mediaValue || typeof mediaValue !== 'object' || typeof mediaValue.url !== 'string') {
|
|
253
|
+
throw new Error(`Segment expects media value with url for "${inputKey}", got ${typeof value}`);
|
|
254
|
+
}
|
|
255
|
+
const source = mediaValue.url;
|
|
256
|
+
const keysToOmit = ['inputRef', 'timeMode'];
|
|
257
|
+
if (segment.type === 'video') {
|
|
258
|
+
result = { ...omit(segment, [...keysToOmit]), type: 'video', source };
|
|
259
|
+
}
|
|
260
|
+
else if (segment.type === 'audio') {
|
|
261
|
+
result = { ...omit(segment, [...keysToOmit]), type: 'audio', source };
|
|
262
|
+
}
|
|
263
|
+
else if (segment.type === 'image') {
|
|
264
|
+
result = { ...omit(segment, [...keysToOmit]), type: 'image', source };
|
|
265
|
+
}
|
|
235
266
|
}
|
|
236
267
|
}
|
|
237
268
|
}
|
|
238
269
|
// Handle textInputRef for text segments
|
|
239
|
-
if (segment.type === 'text'
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (segment.required === false) {
|
|
244
|
-
return null;
|
|
245
|
-
}
|
|
246
|
-
throw new Error(`Required text segment input "${inputKey}" was not provided`);
|
|
270
|
+
if (segment.type === 'text') {
|
|
271
|
+
if (segment.textIsVariable === false) {
|
|
272
|
+
// Static text: use segment.text directly
|
|
273
|
+
result = { ...omit(segment, ['textInputRef', 'timeMode', 'textIsVariable']), type: 'text', source: '', text: segment.text ?? '' };
|
|
247
274
|
}
|
|
248
|
-
if (
|
|
249
|
-
|
|
275
|
+
else if (segment.textInputRef) {
|
|
276
|
+
const inputKey = segment.textInputRef;
|
|
277
|
+
const value = inputs[inputKey];
|
|
278
|
+
if (value === undefined || value === null) {
|
|
279
|
+
if (segment.required === false) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
throw new Error(`Required text segment input "${inputKey}" was not provided`);
|
|
283
|
+
}
|
|
284
|
+
if (typeof value !== 'string') {
|
|
285
|
+
throw new Error(`Text segment expects string for "${inputKey}", got ${typeof value}`);
|
|
286
|
+
}
|
|
287
|
+
result = { ...omit(segment, ['textInputRef', 'timeMode']), type: 'text', source: '', text: value };
|
|
250
288
|
}
|
|
251
|
-
result = { ...omit(segment, ['textInputRef', 'timeMode']), type: 'text', source: '', text: value };
|
|
252
289
|
}
|
|
253
290
|
// Handle trim inputRefs
|
|
254
291
|
if (segment.startTrimInputRef) {
|
|
@@ -274,7 +311,7 @@ function transformSegment(segment, inputs) {
|
|
|
274
311
|
}
|
|
275
312
|
}
|
|
276
313
|
// Remove UI-only fields
|
|
277
|
-
const uiOnlyKeys = ['timeMode', 'startTrimInputRef', 'endTrimInputRef'];
|
|
314
|
+
const uiOnlyKeys = ['timeMode', 'startTrimInputRef', 'endTrimInputRef', 'isVariable', 'staticMedia', 'textIsVariable'];
|
|
278
315
|
const resultWithUiFields = result;
|
|
279
316
|
for (const key of uiOnlyKeys) {
|
|
280
317
|
if (key in resultWithUiFields) {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - previewUrls/previewTextValues: Only for UI preview
|
|
12
12
|
*/
|
|
13
13
|
import type { FitMode, BorderRadiusConfig, TimeValue, TextStyleProperties } from './base';
|
|
14
|
-
import type { DimensionPresetKey } from './element';
|
|
14
|
+
import type { DimensionPresetKey, StaticMediaItem } from './element';
|
|
15
15
|
/**
|
|
16
16
|
* UI helper for timing mode - not sent to renderer
|
|
17
17
|
*/
|
|
@@ -71,6 +71,10 @@ export interface VideoEditorVideoSegment extends VideoEditorVisualSegment {
|
|
|
71
71
|
inputRef?: string;
|
|
72
72
|
/** Actual source URL (set after inputRef is resolved) */
|
|
73
73
|
source?: string;
|
|
74
|
+
/** UI-only: whether this segment uses a variable input (default: true for backwards compat) */
|
|
75
|
+
isVariable?: boolean;
|
|
76
|
+
/** UI-only: static media items when isVariable is false */
|
|
77
|
+
staticMedia?: StaticMediaItem[];
|
|
74
78
|
fit?: FitMode;
|
|
75
79
|
speed?: number;
|
|
76
80
|
volume?: number;
|
|
@@ -85,6 +89,10 @@ export interface VideoEditorAudioSegment extends VideoEditorBaseSegment {
|
|
|
85
89
|
inputRef?: string;
|
|
86
90
|
/** Actual source URL (set after inputRef is resolved) */
|
|
87
91
|
source?: string;
|
|
92
|
+
/** UI-only: whether this segment uses a variable input (default: true for backwards compat) */
|
|
93
|
+
isVariable?: boolean;
|
|
94
|
+
/** UI-only: static media items when isVariable is false */
|
|
95
|
+
staticMedia?: StaticMediaItem[];
|
|
88
96
|
volume?: number;
|
|
89
97
|
}
|
|
90
98
|
/**
|
|
@@ -96,6 +104,10 @@ export interface VideoEditorImageSegment extends VideoEditorVisualSegment {
|
|
|
96
104
|
inputRef?: string;
|
|
97
105
|
/** Actual source URL (set after inputRef is resolved) */
|
|
98
106
|
source?: string;
|
|
107
|
+
/** UI-only: whether this segment uses a variable input (default: true for backwards compat) */
|
|
108
|
+
isVariable?: boolean;
|
|
109
|
+
/** UI-only: static media items when isVariable is false */
|
|
110
|
+
staticMedia?: StaticMediaItem[];
|
|
99
111
|
fit?: FitMode;
|
|
100
112
|
loop?: boolean;
|
|
101
113
|
borderRadius?: number | BorderRadiusConfig;
|
|
@@ -112,6 +124,8 @@ export interface VideoEditorTextSegment extends VideoEditorVisualSegment, TextSt
|
|
|
112
124
|
textInputRef?: string;
|
|
113
125
|
/** Actual text content (set after textInputRef is resolved) */
|
|
114
126
|
text?: string;
|
|
127
|
+
/** UI-only: whether this segment uses a variable text input (default: true for backwards compat) */
|
|
128
|
+
textIsVariable?: boolean;
|
|
115
129
|
}
|
|
116
130
|
/**
|
|
117
131
|
* Image sequence segment (UI) - plays an array of images sequentially
|