samsar-js 0.48.33 → 0.48.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -7
- package/dist/index.d.ts +73 -0
- package/dist/index.js +87 -126
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,6 +115,20 @@ await samsar.createVideoFromImageList({
|
|
|
115
115
|
],
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
+
// Create a video and generate the outro with a center logo/CTA image instead of a QR code
|
|
119
|
+
await samsar.createVideoFromImageList({
|
|
120
|
+
image_urls: ['https://example.com/a.jpg', 'https://example.com/b.jpg'],
|
|
121
|
+
prompt: 'Product launch teaser with a branded CTA outro',
|
|
122
|
+
video_model: 'RUNWAYML',
|
|
123
|
+
aspect_ratio: '9:16',
|
|
124
|
+
generate_outro_image: true,
|
|
125
|
+
outro_cta_image: {
|
|
126
|
+
top_text: 'Shop the drop',
|
|
127
|
+
middle_image: { url: 'https://cdn.example.com/drop-logo.png' },
|
|
128
|
+
bottom_text: 'Limited availability',
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
118
132
|
// Create the same generated QR outro and per-scene footer CTAs from one CTA link
|
|
119
133
|
await samsar.createVideoFromImageList({
|
|
120
134
|
image_urls: [
|
|
@@ -154,6 +168,20 @@ await samsar.updateVideoOutroImage(
|
|
|
154
168
|
{ webhookUrl: 'https://example.com/webhook' },
|
|
155
169
|
);
|
|
156
170
|
|
|
171
|
+
// Update an existing outro by generating a new CTA outro with a center logo/CTA image
|
|
172
|
+
await samsar.updateVideoOutroImage(
|
|
173
|
+
{
|
|
174
|
+
videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
175
|
+
generate_outro_image: true,
|
|
176
|
+
outro_cta_image: {
|
|
177
|
+
top_text: 'Shop the drop',
|
|
178
|
+
middle_image: { url: 'https://cdn.example.com/drop-logo.png' },
|
|
179
|
+
bottom_text: 'Limited availability',
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{ webhookUrl: 'https://example.com/webhook' },
|
|
183
|
+
);
|
|
184
|
+
|
|
157
185
|
// Update the footer CTA on an existing video session
|
|
158
186
|
await samsar.updateVideoFooterImage(
|
|
159
187
|
{
|
|
@@ -497,13 +525,15 @@ const externalRender = await platform.createExternalVideoFromText(externalUser,
|
|
|
497
525
|
enable_subtitles: true,
|
|
498
526
|
});
|
|
499
527
|
|
|
500
|
-
// Update an external user's existing outro by generating a
|
|
528
|
+
// Update an external user's existing outro by generating a center logo/CTA image outro
|
|
501
529
|
const externalOutroUpdate = await platform.updateExternalVideoOutroImage(externalUser, {
|
|
502
530
|
request_id: externalRender.data.request_id,
|
|
503
531
|
generate_outro_image: true,
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
532
|
+
outro_cta_image: {
|
|
533
|
+
top_text: 'Shop the drop',
|
|
534
|
+
middle_image: { url: 'https://cdn.example.com/drop-logo.png' },
|
|
535
|
+
bottom_text: 'Limited availability',
|
|
536
|
+
},
|
|
507
537
|
add_outro_animation: true,
|
|
508
538
|
});
|
|
509
539
|
console.log(externalOutroUpdate.data.request_id);
|
|
@@ -583,15 +613,16 @@ console.log(externalLibrary.data.requests.map((request) => request.request_id));
|
|
|
583
613
|
Video model support notes:
|
|
584
614
|
- `createVideoFromText` image model keys include: `GPTIMAGE2`, `IMAGEN4`, `SEEDREAM`, `NANOBANANA2`, `NANOBANANAPRO`, `CUSTOM_TEXT_TO_IMAGE`.
|
|
585
615
|
- `createVideoFromText` supports these video models: `RUNWAYML`, `VEO3.1I2V`, `VEO3.1I2VFAST`, `COSMOS3SUPERI2V`, `SEEDANCEI2V` (Seedance 1.5), `KLINGIMGTOVID3PRO`, and `HAPPYHORSEI2V`.
|
|
586
|
-
- `createVideoFromText` accepts either a provided outro (`outro_image_url`) or server-generated
|
|
616
|
+
- `createVideoFromText` accepts either a provided outro (`outro_image_url`) or a server-generated CTA outro (`generate_outro_image: true` with `cta_url` for a QR center image, or `outro_cta_image` for a supplied center logo/CTA image). It can also render bottom CTA footer QR cards with `add_footer_animation` and `footer_metadata`; one footer item applies to every generated scene, while multiple items map by scene index.
|
|
587
617
|
- `createVideoFromImageList` supports `RUNWAYML`, `VEO3.1I2V`, `VEO3.1I2VFAST`, `COSMOS3SUPERI2V`, `SEEDANCEI2V`, `KLINGIMGTOVID3PRO`, and `HAPPYHORSEI2V` via `video_model`; if omitted, it defaults to `RUNWAYML`. It also accepts the same `image_model` keys as text-to-video. Use `aspect_ratio: '16:9'` or `'9:16'`; omitted or invalid values fall back to `16:9`.
|
|
588
618
|
- Text and image-list video creation both accept optional `backingtrack_model` / `backing_track_model` / `backingTrackModel` / `music_provider` / `musicProvider`, `tts_model` / `ttsModel` / `tts_provider` / `ttsProvider`, `speakerOptions` / `speaker_options`, and `inference_model` / `inferenceModel`. The adapter normalizes these to `backingtrack_model`, `tts_model`, `speakerOptions`, and `inference_model` in the request payload. Omit `inference_model` to use the account default; supported request values are `gpt-5.5` and `gemini-3.1-pro`. When `tts_model` is set, Samsar limits assignment to the matching speaker list (`openAISpeakers`, `elevenLabsSpeakers`, or `googleSpeakers`; Google TTS requests should include `googleSpeakerDetails`).
|
|
589
619
|
- `video_model_sub_type` is no longer used by the API and is stripped from text and image-list payloads before sending.
|
|
590
|
-
- `createVideoFromImageList` accepts either a provided outro (`outro_image_url`) or server-generated
|
|
620
|
+
- `createVideoFromImageList` accepts either a provided outro (`outro_image_url`) or a server-generated CTA outro (`generate_outro_image: true` with `cta_url` for a QR center image, or `outro_cta_image` for a supplied center logo/CTA image). Do not combine the two modes in a single request.
|
|
621
|
+
- `outro_cta_image` uses the structured shape `{ top_text, middle_image, bottom_text }`. `middle_image` accepts a public image URL (`{ url }`, `{ image_url }`) or image data (`{ data_url }`, `{ image_data, mime_type }`) and is resized into the same center area used by QR outros without changing aspect ratio.
|
|
591
622
|
- `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
|
|
592
623
|
- `createVideoFromImageList` can also generate QR outro CTA text and each scene footer CTA from a single link by setting `express_cta_generation: true` with `cta_url`. CamelCase `expressCtaGeneration` and compatibility aliases `auto_generate_cta_text` / `generate_cta_texts` are normalized to the same API field.
|
|
593
624
|
- `createVideoFromImageList` accepts `limit_single_narrator: true` to keep all narration under one narrator identity. `add_narrator_avatar: true` automatically enables `limit_single_narrator`, generates an influencer-style human narrator avatar, and overlays it bottom-center or centered in the footer row when footer metadata is present.
|
|
594
|
-
- `updateVideoOutroImage` accepts either a replacement outro image URL (`outro_image_url`, `outroImageUrl`, `new_outro_image_url`) or a generated
|
|
625
|
+
- `updateVideoOutroImage` accepts either a replacement outro image URL (`outro_image_url`, `outroImageUrl`, `new_outro_image_url`) or a generated CTA outro (`generate_outro_image: true` with `cta_url` or `outro_cta_image`, or just `cta_url` / `outro_cta_image` when no outro image URL is supplied). Generated outro updates reuse the existing session image layers for tiling and only queue frame/video regeneration.
|
|
595
626
|
- `updateVideoFooterImage` updates the footer CTA on a cloned session with `cta_text`, `cta_logo`, and/or `cta_url`, or removes all scene footers with `remove_footer: true`. Footer updates queue only frame/video regeneration.
|
|
596
627
|
- `cloneVideo` creates a deep copy of a completed session and queues only the final video render so the clone receives a new rendered video path and URL. It does not charge credits.
|
|
597
628
|
- Main video methods and external-user methods accept the same generated outro and footer parameters. The API can resolve either internal session ids or external `extreq_...` ids on repeated video routes, so client code can keep using `translateVideo`, `joinVideos`, `addSubtitles`, `removeSubtitles`, `addVideoOutroImage`, `updateVideoOutroImage`, and `updateVideoFooterImage`; the explicit external variants are available when you want to call `/external_users/*` directly. Do not strip the `extreq_` prefix.
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,53 @@ export interface TTSSpeakerOptions {
|
|
|
66
66
|
googleSpeakerDetails?: GoogleTTSSpeakerDetail[];
|
|
67
67
|
[key: string]: unknown;
|
|
68
68
|
}
|
|
69
|
+
export type OutroCtaImageSource = string | {
|
|
70
|
+
url?: string;
|
|
71
|
+
image_url?: string;
|
|
72
|
+
imageUrl?: string;
|
|
73
|
+
public_url?: string;
|
|
74
|
+
publicUrl?: string;
|
|
75
|
+
source_url?: string;
|
|
76
|
+
sourceUrl?: string;
|
|
77
|
+
source?: string;
|
|
78
|
+
src?: string;
|
|
79
|
+
image?: string;
|
|
80
|
+
data_url?: string;
|
|
81
|
+
dataUrl?: string;
|
|
82
|
+
image_data?: string;
|
|
83
|
+
imageData?: string;
|
|
84
|
+
data?: string;
|
|
85
|
+
mime_type?: string;
|
|
86
|
+
mimeType?: string;
|
|
87
|
+
content_type?: string;
|
|
88
|
+
contentType?: string;
|
|
89
|
+
[key: string]: unknown;
|
|
90
|
+
};
|
|
91
|
+
export interface OutroCtaImagePayload {
|
|
92
|
+
top_text?: string;
|
|
93
|
+
topText?: string;
|
|
94
|
+
cta_text_top?: string;
|
|
95
|
+
ctaTextTop?: string;
|
|
96
|
+
middle_image?: OutroCtaImageSource;
|
|
97
|
+
middleImage?: OutroCtaImageSource;
|
|
98
|
+
center_image?: OutroCtaImageSource;
|
|
99
|
+
centerImage?: OutroCtaImageSource;
|
|
100
|
+
middle?: OutroCtaImageSource;
|
|
101
|
+
center?: OutroCtaImageSource;
|
|
102
|
+
bottom_text?: string;
|
|
103
|
+
bottomText?: string;
|
|
104
|
+
cta_text_bottom?: string;
|
|
105
|
+
ctaTextBottom?: string;
|
|
106
|
+
url?: string;
|
|
107
|
+
image_url?: string;
|
|
108
|
+
imageUrl?: string;
|
|
109
|
+
src?: string;
|
|
110
|
+
data_url?: string;
|
|
111
|
+
dataUrl?: string;
|
|
112
|
+
image_data?: string;
|
|
113
|
+
imageData?: string;
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
}
|
|
69
116
|
export type V2StepGenerationMode = 'one_step' | 'two_step';
|
|
70
117
|
export interface V2StepGenerationOptions {
|
|
71
118
|
auto_render_full_video?: boolean;
|
|
@@ -127,6 +174,10 @@ export interface CreateVideoFromTextInput extends V2StepGenerationOptions {
|
|
|
127
174
|
ctaTextBottom?: string;
|
|
128
175
|
cta_logo?: string;
|
|
129
176
|
ctaLogo?: string;
|
|
177
|
+
outro_cta_image?: OutroCtaImagePayload | string;
|
|
178
|
+
outroCtaImage?: OutroCtaImagePayload | string;
|
|
179
|
+
cta_image?: OutroCtaImagePayload | string;
|
|
180
|
+
ctaImage?: OutroCtaImagePayload | string;
|
|
130
181
|
add_footer_animation?: boolean;
|
|
131
182
|
addFooterAnimation?: boolean;
|
|
132
183
|
footer_metadata?: FooterMetadataItem[];
|
|
@@ -248,6 +299,10 @@ export interface CreateVideoFromImageListInput extends V2StepGenerationOptions {
|
|
|
248
299
|
ctaTextBottom?: string;
|
|
249
300
|
cta_logo?: string;
|
|
250
301
|
ctaLogo?: string;
|
|
302
|
+
outro_cta_image?: OutroCtaImagePayload | string;
|
|
303
|
+
outroCtaImage?: OutroCtaImagePayload | string;
|
|
304
|
+
cta_image?: OutroCtaImagePayload | string;
|
|
305
|
+
ctaImage?: OutroCtaImagePayload | string;
|
|
251
306
|
add_footer_animation?: boolean;
|
|
252
307
|
addFooterAnimation?: boolean;
|
|
253
308
|
footer_metadata?: FooterMetadataItem[];
|
|
@@ -374,6 +429,10 @@ export interface UpdateVideoOutroImageInput {
|
|
|
374
429
|
ctaTextBottom?: string;
|
|
375
430
|
cta_logo?: string;
|
|
376
431
|
ctaLogo?: string;
|
|
432
|
+
outro_cta_image?: OutroCtaImagePayload | string;
|
|
433
|
+
outroCtaImage?: OutroCtaImagePayload | string;
|
|
434
|
+
cta_image?: OutroCtaImagePayload | string;
|
|
435
|
+
ctaImage?: OutroCtaImagePayload | string;
|
|
377
436
|
[key: string]: unknown;
|
|
378
437
|
}
|
|
379
438
|
export interface UpdateVideoOutroImageResponse {
|
|
@@ -444,6 +503,20 @@ export interface AddVideoOutroImageInput {
|
|
|
444
503
|
outro_focus_area?: OutroFocusArea | null;
|
|
445
504
|
outroFocustArea?: OutroFocusArea | null;
|
|
446
505
|
outroFocusArea?: OutroFocusArea | null;
|
|
506
|
+
generate_outro_image?: boolean;
|
|
507
|
+
generateOutroImage?: boolean;
|
|
508
|
+
cta_url?: string;
|
|
509
|
+
ctaUrl?: string;
|
|
510
|
+
cta_text_top?: string;
|
|
511
|
+
ctaTextTop?: string;
|
|
512
|
+
cta_text_bottom?: string;
|
|
513
|
+
ctaTextBottom?: string;
|
|
514
|
+
cta_logo?: string;
|
|
515
|
+
ctaLogo?: string;
|
|
516
|
+
outro_cta_image?: OutroCtaImagePayload | string;
|
|
517
|
+
outroCtaImage?: OutroCtaImagePayload | string;
|
|
518
|
+
cta_image?: OutroCtaImagePayload | string;
|
|
519
|
+
ctaImage?: OutroCtaImagePayload | string;
|
|
447
520
|
[key: string]: unknown;
|
|
448
521
|
}
|
|
449
522
|
export interface AddVideoOutroImageResponse {
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,58 @@ function assertOptionalBoolean(value, fieldName, context = 'createVideoFromImage
|
|
|
41
41
|
throw new Error(`${fieldName} must be a boolean for ${context}`);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
function hasOutroCtaImageSource(value) {
|
|
45
|
+
if (typeof value === 'string') {
|
|
46
|
+
return Boolean(value.trim());
|
|
47
|
+
}
|
|
48
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const record = value;
|
|
52
|
+
const middleImage = getFirstDefinedInputValue(record, [
|
|
53
|
+
'middle_image',
|
|
54
|
+
'middleImage',
|
|
55
|
+
'center_image',
|
|
56
|
+
'centerImage',
|
|
57
|
+
'middle',
|
|
58
|
+
'center',
|
|
59
|
+
]);
|
|
60
|
+
if (middleImage !== undefined) {
|
|
61
|
+
return hasOutroCtaImageSource(middleImage);
|
|
62
|
+
}
|
|
63
|
+
return Boolean(getTrimmedString(record.url) ??
|
|
64
|
+
getTrimmedString(record.image_url) ??
|
|
65
|
+
getTrimmedString(record.imageUrl) ??
|
|
66
|
+
getTrimmedString(record.public_url) ??
|
|
67
|
+
getTrimmedString(record.publicUrl) ??
|
|
68
|
+
getTrimmedString(record.source_url) ??
|
|
69
|
+
getTrimmedString(record.sourceUrl) ??
|
|
70
|
+
getTrimmedString(record.source) ??
|
|
71
|
+
getTrimmedString(record.src) ??
|
|
72
|
+
getTrimmedString(record.image) ??
|
|
73
|
+
getTrimmedString(record.middle_image_url) ??
|
|
74
|
+
getTrimmedString(record.middleImageUrl) ??
|
|
75
|
+
getTrimmedString(record.center_image_url) ??
|
|
76
|
+
getTrimmedString(record.centerImageUrl) ??
|
|
77
|
+
getTrimmedString(record.data_url) ??
|
|
78
|
+
getTrimmedString(record.dataUrl) ??
|
|
79
|
+
getTrimmedString(record.image_data) ??
|
|
80
|
+
getTrimmedString(record.imageData) ??
|
|
81
|
+
getTrimmedString(record.data));
|
|
82
|
+
}
|
|
83
|
+
function normalizeOutroCtaImageInput(raw, context) {
|
|
84
|
+
const value = resolveAliasedInputValue(raw, ['outro_cta_image', 'outroCtaImage', 'cta_image', 'ctaImage'], 'outro_cta_image');
|
|
85
|
+
if (value === undefined || value === null) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
if (typeof value !== 'string' && (typeof value !== 'object' || Array.isArray(value))) {
|
|
89
|
+
throw new Error(`outro_cta_image must be a string or object for ${context}`);
|
|
90
|
+
}
|
|
91
|
+
if (!hasOutroCtaImageSource(value)) {
|
|
92
|
+
throw new Error(`outro_cta_image.middle_image is required for ${context}`);
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
44
96
|
function getFirstDefinedInputValue(raw, aliases) {
|
|
45
97
|
for (const alias of aliases) {
|
|
46
98
|
if (Object.prototype.hasOwnProperty.call(raw, alias)) {
|
|
@@ -135,6 +187,7 @@ function normalizeCreateVideoFromTextInput(input) {
|
|
|
135
187
|
['cta_text_top', ['cta_text_top', 'ctaTextTop']],
|
|
136
188
|
['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
|
|
137
189
|
['cta_logo', ['cta_logo', 'ctaLogo']],
|
|
190
|
+
['outro_cta_image', ['outro_cta_image', 'outroCtaImage', 'cta_image', 'ctaImage']],
|
|
138
191
|
['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
|
|
139
192
|
['footer_metadata', ['footer_metadata', 'footerMetadata']],
|
|
140
193
|
['backingtrack_model', ['backingtrack_model', 'backing_track_model', 'backingTrackModel', 'music_provider', 'musicProvider']],
|
|
@@ -159,11 +212,21 @@ function normalizeCreateVideoFromTextInput(input) {
|
|
|
159
212
|
assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation', 'createVideoFromText');
|
|
160
213
|
if (normalized.generate_outro_image === true) {
|
|
161
214
|
const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
|
|
162
|
-
|
|
163
|
-
|
|
215
|
+
const outroCtaImage = normalizeOutroCtaImageInput(normalized, 'createVideoFromText');
|
|
216
|
+
if (outroCtaImage !== undefined) {
|
|
217
|
+
normalized.outro_cta_image = outroCtaImage;
|
|
218
|
+
}
|
|
219
|
+
if (!ctaUrl && !outroCtaImage) {
|
|
220
|
+
throw new Error('cta_url or outro_cta_image is required when generate_outro_image is true for createVideoFromText');
|
|
164
221
|
}
|
|
165
222
|
}
|
|
166
|
-
else
|
|
223
|
+
else {
|
|
224
|
+
const outroCtaImage = normalizeOutroCtaImageInput(normalized, 'createVideoFromText');
|
|
225
|
+
if (outroCtaImage !== undefined) {
|
|
226
|
+
normalized.outro_cta_image = outroCtaImage;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (normalized.generate_outro_image !== true && normalized.add_outro_focus_area === true && normalized.add_outro_animation !== true) {
|
|
167
230
|
throw new Error('add_outro_focus_area requires add_outro_animation to be true for createVideoFromText');
|
|
168
231
|
}
|
|
169
232
|
return normalized;
|
|
@@ -197,6 +260,7 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
197
260
|
['cta_text_top', ['cta_text_top', 'ctaTextTop']],
|
|
198
261
|
['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
|
|
199
262
|
['cta_logo', ['cta_logo', 'ctaLogo']],
|
|
263
|
+
['outro_cta_image', ['outro_cta_image', 'outroCtaImage', 'cta_image', 'ctaImage']],
|
|
200
264
|
['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
|
|
201
265
|
['footer_metadata', ['footer_metadata', 'footerMetadata']],
|
|
202
266
|
['backingtrack_model', ['backingtrack_model', 'backing_track_model', 'backingTrackModel', 'music_provider', 'musicProvider']],
|
|
@@ -224,6 +288,10 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
224
288
|
assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation');
|
|
225
289
|
assertOptionalBoolean(normalized.limit_single_narrator, 'limit_single_narrator');
|
|
226
290
|
assertOptionalBoolean(normalized.add_narrator_avatar, 'add_narrator_avatar');
|
|
291
|
+
const outroCtaImage = normalizeOutroCtaImageInput(normalized, 'createVideoFromImageList');
|
|
292
|
+
if (outroCtaImage !== undefined) {
|
|
293
|
+
normalized.outro_cta_image = outroCtaImage;
|
|
294
|
+
}
|
|
227
295
|
if (normalized.add_narrator_avatar === true) {
|
|
228
296
|
normalized.limit_single_narrator = true;
|
|
229
297
|
}
|
|
@@ -240,8 +308,8 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
240
308
|
}
|
|
241
309
|
if (normalized.generate_outro_image === true) {
|
|
242
310
|
const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
|
|
243
|
-
if (!ctaUrl) {
|
|
244
|
-
throw new Error('cta_url is required when generate_outro_image is true for createVideoFromImageList');
|
|
311
|
+
if (!ctaUrl && !outroCtaImage) {
|
|
312
|
+
throw new Error('cta_url or outro_cta_image is required when generate_outro_image is true for createVideoFromImageList');
|
|
245
313
|
}
|
|
246
314
|
}
|
|
247
315
|
else if (normalized.add_outro_focus_area === true && normalized.add_outro_animation !== true) {
|
|
@@ -370,8 +438,9 @@ function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroI
|
|
|
370
438
|
raw.ctaTextBottom;
|
|
371
439
|
const ctaLogo = raw.cta_logo ??
|
|
372
440
|
raw.ctaLogo;
|
|
441
|
+
const outroCtaImage = normalizeOutroCtaImageInput(raw, context);
|
|
373
442
|
const generateOutroImage = rawGenerateOutroImage === true ||
|
|
374
|
-
(rawGenerateOutroImage === undefined && !outroImageUrl && Boolean(ctaUrl));
|
|
443
|
+
(rawGenerateOutroImage === undefined && !outroImageUrl && (Boolean(ctaUrl) || Boolean(outroCtaImage)));
|
|
375
444
|
if (!videoSessionId) {
|
|
376
445
|
throw new Error(`videoSessionId is required for ${context}`);
|
|
377
446
|
}
|
|
@@ -384,15 +453,15 @@ function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroI
|
|
|
384
453
|
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
385
454
|
throw new Error(`add_outro_focus_area must be a boolean for ${context}`);
|
|
386
455
|
}
|
|
387
|
-
if (generateOutroImage && outroImageUrl) {
|
|
388
|
-
throw new Error(`Use either generate_outro_image with cta_url or outro_image_url for ${context}`);
|
|
456
|
+
if ((generateOutroImage || outroCtaImage) && outroImageUrl) {
|
|
457
|
+
throw new Error(`Use either generate_outro_image with cta_url/outro_cta_image or outro_image_url for ${context}`);
|
|
389
458
|
}
|
|
390
459
|
if (!generateOutroImage && !outroImageUrl) {
|
|
391
460
|
throw new Error(`outro_image_url is required for ${context} unless generate_outro_image is true`);
|
|
392
461
|
}
|
|
393
462
|
if (generateOutroImage) {
|
|
394
|
-
if (!ctaUrl || !String(ctaUrl).trim()) {
|
|
395
|
-
throw new Error(`cta_url is required when generate_outro_image is true for ${context}`);
|
|
463
|
+
if ((!ctaUrl || !String(ctaUrl).trim()) && !outroCtaImage) {
|
|
464
|
+
throw new Error(`cta_url or outro_cta_image is required when generate_outro_image is true for ${context}`);
|
|
396
465
|
}
|
|
397
466
|
}
|
|
398
467
|
else if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
@@ -413,7 +482,8 @@ function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroI
|
|
|
413
482
|
videoSessionId: String(videoSessionId),
|
|
414
483
|
...(outroImageUrl ? { outro_image_url: String(outroImageUrl) } : {}),
|
|
415
484
|
generate_outro_image: generateOutroImage,
|
|
416
|
-
...(generateOutroImage ? { cta_url: String(ctaUrl).trim() } : {}),
|
|
485
|
+
...(generateOutroImage && ctaUrl ? { cta_url: String(ctaUrl).trim() } : {}),
|
|
486
|
+
...(generateOutroImage && outroCtaImage ? { outro_cta_image: outroCtaImage } : {}),
|
|
417
487
|
...(ctaTextTop ? { cta_text_top: String(ctaTextTop) } : {}),
|
|
418
488
|
...(ctaTextBottom ? { cta_text_bottom: String(ctaTextBottom) } : {}),
|
|
419
489
|
...(ctaLogo ? { cta_logo: String(ctaLogo) } : {}),
|
|
@@ -879,8 +949,9 @@ export class SamsarClient {
|
|
|
879
949
|
}, options);
|
|
880
950
|
}
|
|
881
951
|
async addV2VideoOutroImage(input, options) {
|
|
952
|
+
const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'addV2VideoOutroImage');
|
|
882
953
|
return this.postV2('add_outro_image', {
|
|
883
|
-
input,
|
|
954
|
+
input: normalizedInput,
|
|
884
955
|
webhookUrl: options?.webhookUrl,
|
|
885
956
|
}, options);
|
|
886
957
|
}
|
|
@@ -1484,61 +1555,9 @@ export class SamsarClient {
|
|
|
1484
1555
|
* re-running frame/video generation.
|
|
1485
1556
|
*/
|
|
1486
1557
|
async addVideoOutroImage(input, options) {
|
|
1487
|
-
const
|
|
1488
|
-
const videoSessionId = raw.videoSessionId ??
|
|
1489
|
-
raw.video_session_id ??
|
|
1490
|
-
raw.videoSessionID ??
|
|
1491
|
-
raw.session_id ??
|
|
1492
|
-
raw.sessionId ??
|
|
1493
|
-
raw.sessionID ??
|
|
1494
|
-
raw.request_id ??
|
|
1495
|
-
raw.requestId;
|
|
1496
|
-
const outroImageUrl = raw.outro_image_url ??
|
|
1497
|
-
raw.outroImageUrl ??
|
|
1498
|
-
raw.new_outro_image_url ??
|
|
1499
|
-
raw.newOutroImageUrl;
|
|
1500
|
-
const rawAddOutroAnimation = raw.add_outro_animation ??
|
|
1501
|
-
raw.addOutroAnimation;
|
|
1502
|
-
const rawAddOutroFocusArea = raw.add_outro_focus_area ??
|
|
1503
|
-
raw.addOutroFocusArea;
|
|
1504
|
-
const rawOutroFocusArea = raw.outro_focust_area ??
|
|
1505
|
-
raw.outro_focus_area ??
|
|
1506
|
-
raw.outroFocustArea ??
|
|
1507
|
-
raw.outroFocusArea;
|
|
1508
|
-
if (!videoSessionId) {
|
|
1509
|
-
throw new Error('videoSessionId is required for addVideoOutroImage');
|
|
1510
|
-
}
|
|
1511
|
-
if (!outroImageUrl) {
|
|
1512
|
-
throw new Error('outro_image_url is required for addVideoOutroImage');
|
|
1513
|
-
}
|
|
1514
|
-
if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
|
|
1515
|
-
throw new Error('add_outro_animation must be a boolean for addVideoOutroImage');
|
|
1516
|
-
}
|
|
1517
|
-
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
1518
|
-
throw new Error('add_outro_focus_area must be a boolean for addVideoOutroImage');
|
|
1519
|
-
}
|
|
1520
|
-
if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
1521
|
-
throw new Error('add_outro_focus_area requires add_outro_animation to be true for addVideoOutroImage');
|
|
1522
|
-
}
|
|
1523
|
-
if (rawAddOutroFocusArea === true) {
|
|
1524
|
-
if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
|
|
1525
|
-
throw new Error('outro_focust_area must be an object with x, y, width, height for addVideoOutroImage');
|
|
1526
|
-
}
|
|
1527
|
-
const { x, y, width, height } = rawOutroFocusArea;
|
|
1528
|
-
const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
|
|
1529
|
-
if (isInvalid) {
|
|
1530
|
-
throw new Error('outro_focust_area x, y, width, height must be valid numbers for addVideoOutroImage');
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1558
|
+
const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'addVideoOutroImage');
|
|
1533
1559
|
const body = {
|
|
1534
|
-
input:
|
|
1535
|
-
...input,
|
|
1536
|
-
videoSessionId: String(videoSessionId),
|
|
1537
|
-
outro_image_url: String(outroImageUrl),
|
|
1538
|
-
...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
|
|
1539
|
-
...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
|
|
1540
|
-
...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
|
|
1541
|
-
},
|
|
1560
|
+
input: normalizedInput,
|
|
1542
1561
|
webhookUrl: options?.webhookUrl,
|
|
1543
1562
|
};
|
|
1544
1563
|
const response = await this.post('video/add_outro_image', body, options);
|
|
@@ -1566,68 +1585,10 @@ export class SamsarClient {
|
|
|
1566
1585
|
* Add or replace an outro image for an external-user video request by resolving the external request id.
|
|
1567
1586
|
*/
|
|
1568
1587
|
async addExternalVideoOutroImage(externalUser, input, options) {
|
|
1569
|
-
const
|
|
1570
|
-
const videoSessionId = raw.videoSessionId ??
|
|
1571
|
-
raw.video_session_id ??
|
|
1572
|
-
raw.videoSessionID ??
|
|
1573
|
-
raw.session_id ??
|
|
1574
|
-
raw.sessionId ??
|
|
1575
|
-
raw.sessionID ??
|
|
1576
|
-
raw.request_id ??
|
|
1577
|
-
raw.requestId ??
|
|
1578
|
-
raw.source_request_id ??
|
|
1579
|
-
raw.sourceRequestId ??
|
|
1580
|
-
raw.external_request_id ??
|
|
1581
|
-
raw.externalRequestId ??
|
|
1582
|
-
raw.external_session_id ??
|
|
1583
|
-
raw.externalSessionId;
|
|
1584
|
-
const outroImageUrl = raw.outro_image_url ??
|
|
1585
|
-
raw.outroImageUrl ??
|
|
1586
|
-
raw.new_outro_image_url ??
|
|
1587
|
-
raw.newOutroImageUrl;
|
|
1588
|
-
const rawAddOutroAnimation = raw.add_outro_animation ??
|
|
1589
|
-
raw.addOutroAnimation;
|
|
1590
|
-
const rawAddOutroFocusArea = raw.add_outro_focus_area ??
|
|
1591
|
-
raw.addOutroFocusArea;
|
|
1592
|
-
const rawOutroFocusArea = raw.outro_focust_area ??
|
|
1593
|
-
raw.outro_focus_area ??
|
|
1594
|
-
raw.outroFocustArea ??
|
|
1595
|
-
raw.outroFocusArea;
|
|
1596
|
-
if (!videoSessionId) {
|
|
1597
|
-
throw new Error('videoSessionId is required for addExternalVideoOutroImage');
|
|
1598
|
-
}
|
|
1599
|
-
if (!outroImageUrl) {
|
|
1600
|
-
throw new Error('outro_image_url is required for addExternalVideoOutroImage');
|
|
1601
|
-
}
|
|
1602
|
-
if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
|
|
1603
|
-
throw new Error('add_outro_animation must be a boolean for addExternalVideoOutroImage');
|
|
1604
|
-
}
|
|
1605
|
-
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
1606
|
-
throw new Error('add_outro_focus_area must be a boolean for addExternalVideoOutroImage');
|
|
1607
|
-
}
|
|
1608
|
-
if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
1609
|
-
throw new Error('add_outro_focus_area requires add_outro_animation to be true for addExternalVideoOutroImage');
|
|
1610
|
-
}
|
|
1611
|
-
if (rawAddOutroFocusArea === true) {
|
|
1612
|
-
if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
|
|
1613
|
-
throw new Error('outro_focust_area must be an object with x, y, width, height for addExternalVideoOutroImage');
|
|
1614
|
-
}
|
|
1615
|
-
const { x, y, width, height } = rawOutroFocusArea;
|
|
1616
|
-
const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
|
|
1617
|
-
if (isInvalid) {
|
|
1618
|
-
throw new Error('outro_focust_area x, y, width, height must be valid numbers for addExternalVideoOutroImage');
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1588
|
+
const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'addExternalVideoOutroImage');
|
|
1621
1589
|
const body = {
|
|
1622
1590
|
external_user: normalizeExternalUserIdentity(externalUser),
|
|
1623
|
-
input:
|
|
1624
|
-
...input,
|
|
1625
|
-
videoSessionId: String(videoSessionId),
|
|
1626
|
-
outro_image_url: String(outroImageUrl),
|
|
1627
|
-
...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
|
|
1628
|
-
...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
|
|
1629
|
-
...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
|
|
1630
|
-
},
|
|
1591
|
+
input: normalizedInput,
|
|
1631
1592
|
webhookUrl: options?.webhookUrl,
|
|
1632
1593
|
};
|
|
1633
1594
|
return this.post('external_users/add_outro_image', body, options);
|