@bambuser/n8n-nodes-livecommerce 0.1.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 +188 -0
- package/dist/credentials/BambuserApi.credentials.js +55 -0
- package/dist/credentials/bambuser.svg +13 -0
- package/dist/lib/resolveOrigin.js +14 -0
- package/dist/nodes/BambuserCalls/BambuserCalls.node.js +295 -0
- package/dist/nodes/BambuserCalls/bambuser-live.svg +3 -0
- package/dist/nodes/BambuserProductCatalog/BambuserProductCatalog.node.js +236 -0
- package/dist/nodes/BambuserProductCatalog/bambuser-vod.svg +12 -0
- package/dist/nodes/BambuserShopperData/BambuserShopperData.node.js +170 -0
- package/dist/nodes/BambuserShopperData/bambuser-vod.svg +12 -0
- package/dist/nodes/BambuserShows/BambuserShows.node.js +1432 -0
- package/dist/nodes/BambuserShows/bambuser-live.svg +3 -0
- package/dist/nodes/BambuserVod/BambuserVod.node.js +704 -0
- package/dist/nodes/BambuserVod/bambuser-vod.svg +12 -0
- package/dist/nodes/BambuserWebhookTrigger/BambuserWebhookTrigger.node.js +114 -0
- package/dist/nodes/BambuserWebhookTrigger/bambuser-webhook.svg +8 -0
- package/package.json +77 -0
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BambuserVod = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const resolveOrigin_1 = require("../../lib/resolveOrigin");
|
|
6
|
+
const buildVideoListQs = (ctx, i) => {
|
|
7
|
+
const qs = {
|
|
8
|
+
pageSize: ctx.getNodeParameter('pageSize', i, 50),
|
|
9
|
+
sortBy: ctx.getNodeParameter('sortBy', i, 'createdAt'),
|
|
10
|
+
sortOrder: ctx.getNodeParameter('sortOrder', i, 'DESC'),
|
|
11
|
+
};
|
|
12
|
+
const cursor = ctx.getNodeParameter('cursor', i, '');
|
|
13
|
+
const search = ctx.getNodeParameter('search', i, '');
|
|
14
|
+
if (cursor)
|
|
15
|
+
qs.cursor = cursor;
|
|
16
|
+
if (search)
|
|
17
|
+
qs.search = search;
|
|
18
|
+
return qs;
|
|
19
|
+
};
|
|
20
|
+
const buildVideoDetails = (ctx, i) => {
|
|
21
|
+
const details = {
|
|
22
|
+
title: ctx.getNodeParameter('title', i),
|
|
23
|
+
description: ctx.getNodeParameter('description', i),
|
|
24
|
+
};
|
|
25
|
+
const locale = ctx.getNodeParameter('locale', i, '');
|
|
26
|
+
if (locale)
|
|
27
|
+
details.locale = locale;
|
|
28
|
+
return details;
|
|
29
|
+
};
|
|
30
|
+
const buildListQs = (ctx, i) => {
|
|
31
|
+
const qs = {
|
|
32
|
+
pageSize: ctx.getNodeParameter('pageSize', i, 50),
|
|
33
|
+
};
|
|
34
|
+
const cursor = ctx.getNodeParameter('cursor', i, '');
|
|
35
|
+
if (cursor)
|
|
36
|
+
qs.cursor = cursor;
|
|
37
|
+
return qs;
|
|
38
|
+
};
|
|
39
|
+
const buildVideoPlaylistBody = (ctx, i) => {
|
|
40
|
+
const body = {};
|
|
41
|
+
const title = ctx.getNodeParameter('playlistTitle', i, '');
|
|
42
|
+
const description = ctx.getNodeParameter('playlistDescription', i, '');
|
|
43
|
+
const published = ctx.getNodeParameter('published', i, false);
|
|
44
|
+
const videoOrderRaw = ctx.getNodeParameter('videoOrder', i, '[]');
|
|
45
|
+
const videoOrder = typeof videoOrderRaw === 'string' ? JSON.parse(videoOrderRaw) : videoOrderRaw;
|
|
46
|
+
if (title)
|
|
47
|
+
body.title = title;
|
|
48
|
+
if (description)
|
|
49
|
+
body.description = description;
|
|
50
|
+
body.published = published;
|
|
51
|
+
if (videoOrder.length > 0)
|
|
52
|
+
body.videoOrder = videoOrder;
|
|
53
|
+
return body;
|
|
54
|
+
};
|
|
55
|
+
const buildOperationHandlers = (ctx, baseUrl) => ({
|
|
56
|
+
// ── Video ──────────────────────────────────────────────────────────────────
|
|
57
|
+
'video:getMany': async (i) => ({
|
|
58
|
+
method: 'GET',
|
|
59
|
+
url: `${baseUrl}/videos`,
|
|
60
|
+
qs: buildVideoListQs(ctx, i),
|
|
61
|
+
}),
|
|
62
|
+
'video:get': async (i) => ({
|
|
63
|
+
method: 'GET',
|
|
64
|
+
url: `${baseUrl}/videos/${ctx.getNodeParameter('videoId', i)}`,
|
|
65
|
+
}),
|
|
66
|
+
'video:create': async (i) => {
|
|
67
|
+
const sourceUrl = ctx.getNodeParameter('sourceUrl', i, '');
|
|
68
|
+
const inputJson = ctx.getInputData()[i]?.json ?? {};
|
|
69
|
+
const broadcastLength = typeof inputJson.broadcastLength === 'number' ? inputJson.broadcastLength : undefined;
|
|
70
|
+
return {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
url: `${baseUrl}/videos`,
|
|
73
|
+
headers: { 'Content-Type': 'application/json' },
|
|
74
|
+
body: {
|
|
75
|
+
data: {
|
|
76
|
+
filename: ctx.getNodeParameter('filename', i),
|
|
77
|
+
...(sourceUrl ? { sourceUrl } : {}),
|
|
78
|
+
...(broadcastLength !== undefined ? { broadcastLength } : {}),
|
|
79
|
+
videoDetails: buildVideoDetails(ctx, i),
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
'video:update': async (i) => ({
|
|
85
|
+
method: 'PATCH',
|
|
86
|
+
url: `${baseUrl}/videos/${ctx.getNodeParameter('videoId', i)}`,
|
|
87
|
+
headers: { 'Content-Type': 'application/json' },
|
|
88
|
+
body: {
|
|
89
|
+
data: {
|
|
90
|
+
videoDetails: buildVideoDetails(ctx, i),
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
'video:delete': async (i) => ({
|
|
95
|
+
method: 'DELETE',
|
|
96
|
+
url: `${baseUrl}/videos/${ctx.getNodeParameter('videoId', i)}`,
|
|
97
|
+
}),
|
|
98
|
+
'video:query': async (i) => {
|
|
99
|
+
const queryBodyRaw = ctx.getNodeParameter('queryBody', i, '{}');
|
|
100
|
+
const queryBody = typeof queryBodyRaw === 'string' ? JSON.parse(queryBodyRaw) : queryBodyRaw;
|
|
101
|
+
const qs = buildListQs(ctx, i);
|
|
102
|
+
return {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
url: `${baseUrl}/videos/query`,
|
|
105
|
+
headers: { 'Content-Type': 'application/json' },
|
|
106
|
+
qs,
|
|
107
|
+
body: queryBody,
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
'video:getCount': async (i) => ({
|
|
111
|
+
method: 'GET',
|
|
112
|
+
url: `${baseUrl}/videos/count`,
|
|
113
|
+
qs: {
|
|
114
|
+
includeExampleVideos: ctx.getNodeParameter('includeExampleVideos', i, false),
|
|
115
|
+
},
|
|
116
|
+
}),
|
|
117
|
+
'video:getViewsCount': async () => ({
|
|
118
|
+
method: 'GET',
|
|
119
|
+
url: `${baseUrl}/videos/views-count`,
|
|
120
|
+
}),
|
|
121
|
+
'video:clip': async (i) => ({
|
|
122
|
+
method: 'POST',
|
|
123
|
+
url: `${baseUrl}/videos/${ctx.getNodeParameter('videoId', i)}/clip`,
|
|
124
|
+
headers: { 'Content-Type': 'application/json' },
|
|
125
|
+
body: {
|
|
126
|
+
data: {
|
|
127
|
+
broadcastId: ctx.getNodeParameter('broadcastId', i),
|
|
128
|
+
start: ctx.getNodeParameter('clipStart', i),
|
|
129
|
+
end: ctx.getNodeParameter('clipEnd', i),
|
|
130
|
+
importCaptions: ctx.getNodeParameter('importCaptions', i, false),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
'video:updatePreview': async (i) => ({
|
|
135
|
+
method: 'PUT',
|
|
136
|
+
url: `${baseUrl}/videos/${ctx.getNodeParameter('videoId', i)}/preview`,
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: {
|
|
139
|
+
data: {
|
|
140
|
+
fileId: ctx.getNodeParameter('fileId', i),
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
// ── Media Asset ────────────────────────────────────────────────────────────
|
|
145
|
+
'mediaAsset:getMany': async (i) => ({
|
|
146
|
+
method: 'GET',
|
|
147
|
+
url: `${baseUrl}/media-assets`,
|
|
148
|
+
qs: buildListQs(ctx, i),
|
|
149
|
+
}),
|
|
150
|
+
'mediaAsset:get': async (i) => ({
|
|
151
|
+
method: 'GET',
|
|
152
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}`,
|
|
153
|
+
}),
|
|
154
|
+
'mediaAsset:create': async (i) => {
|
|
155
|
+
const sourceUrl = ctx.getNodeParameter('sourceUrl', i, '');
|
|
156
|
+
return {
|
|
157
|
+
method: 'POST',
|
|
158
|
+
url: `${baseUrl}/media-assets`,
|
|
159
|
+
headers: { 'Content-Type': 'application/json' },
|
|
160
|
+
body: {
|
|
161
|
+
ref: {
|
|
162
|
+
videoId: ctx.getNodeParameter('refVideoId', i),
|
|
163
|
+
},
|
|
164
|
+
data: {
|
|
165
|
+
type: ctx.getNodeParameter('mediaType', i, 'image'),
|
|
166
|
+
data: {
|
|
167
|
+
filename: ctx.getNodeParameter('filename', i),
|
|
168
|
+
...(sourceUrl ? { sourceUrl } : {}),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
'mediaAsset:update': async (i) => {
|
|
175
|
+
const vendorUploadId = ctx.getNodeParameter('vendorUploadId', i, '');
|
|
176
|
+
return {
|
|
177
|
+
method: 'PATCH',
|
|
178
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}`,
|
|
179
|
+
headers: { 'Content-Type': 'application/json' },
|
|
180
|
+
body: {
|
|
181
|
+
data: {
|
|
182
|
+
...(vendorUploadId ? { vendorUploadId } : {}),
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
'mediaAsset:delete': async (i) => ({
|
|
188
|
+
method: 'DELETE',
|
|
189
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}`,
|
|
190
|
+
}),
|
|
191
|
+
'mediaAsset:createUploadTicket': async () => ({
|
|
192
|
+
method: 'POST',
|
|
193
|
+
url: `${baseUrl}/image-upload-ticket`,
|
|
194
|
+
headers: { 'Content-Type': 'application/json' },
|
|
195
|
+
body: {},
|
|
196
|
+
}),
|
|
197
|
+
'mediaAsset:updateUploadStatus': async (i) => {
|
|
198
|
+
const vendorUploadId = ctx.getNodeParameter('vendorUploadId', i, '');
|
|
199
|
+
const uploadState = ctx.getNodeParameter('uploadState', i, 'completed');
|
|
200
|
+
return {
|
|
201
|
+
method: 'POST',
|
|
202
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}/upload-status`,
|
|
203
|
+
headers: { 'Content-Type': 'application/json' },
|
|
204
|
+
body: {
|
|
205
|
+
state: uploadState,
|
|
206
|
+
...(vendorUploadId ? { vendorUploadId } : {}),
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
'mediaAsset:getCaptions': async (i) => ({
|
|
211
|
+
method: 'GET',
|
|
212
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}/captions`,
|
|
213
|
+
}),
|
|
214
|
+
'mediaAsset:createCaption': async (i) => {
|
|
215
|
+
const sourceLanguageCode = ctx.getNodeParameter('sourceLanguageCode', i, '');
|
|
216
|
+
return {
|
|
217
|
+
method: 'POST',
|
|
218
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}/captions`,
|
|
219
|
+
headers: { 'Content-Type': 'application/json' },
|
|
220
|
+
body: {
|
|
221
|
+
data: {
|
|
222
|
+
languageCode: ctx.getNodeParameter('captionLanguageCode', i),
|
|
223
|
+
...(sourceLanguageCode ? { sourceLanguageCode } : {}),
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
},
|
|
228
|
+
'mediaAsset:updateCaption': async (i) => {
|
|
229
|
+
const captionBodyRaw = ctx.getNodeParameter('captionBody', i, '{}');
|
|
230
|
+
const captionBody = typeof captionBodyRaw === 'string' ? JSON.parse(captionBodyRaw) : captionBodyRaw;
|
|
231
|
+
return {
|
|
232
|
+
method: 'PUT',
|
|
233
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}/captions/${ctx.getNodeParameter('languageCode', i)}`,
|
|
234
|
+
headers: { 'Content-Type': 'application/json' },
|
|
235
|
+
body: { data: captionBody },
|
|
236
|
+
};
|
|
237
|
+
},
|
|
238
|
+
'mediaAsset:deleteCaption': async (i) => ({
|
|
239
|
+
method: 'DELETE',
|
|
240
|
+
url: `${baseUrl}/media-assets/${ctx.getNodeParameter('mediaAssetId', i)}/captions/${ctx.getNodeParameter('languageCode', i)}`,
|
|
241
|
+
}),
|
|
242
|
+
// ── Video Playlist ─────────────────────────────────────────────────────────
|
|
243
|
+
'videoPlaylist:getMany': async (i) => ({
|
|
244
|
+
method: 'GET',
|
|
245
|
+
url: `${baseUrl}/video-playlists`,
|
|
246
|
+
qs: buildListQs(ctx, i),
|
|
247
|
+
}),
|
|
248
|
+
'videoPlaylist:get': async (i) => ({
|
|
249
|
+
method: 'GET',
|
|
250
|
+
url: `${baseUrl}/video-playlists/${ctx.getNodeParameter('playlistId', i)}`,
|
|
251
|
+
}),
|
|
252
|
+
'videoPlaylist:create': async (i) => ({
|
|
253
|
+
method: 'POST',
|
|
254
|
+
url: `${baseUrl}/video-playlists`,
|
|
255
|
+
headers: { 'Content-Type': 'application/json' },
|
|
256
|
+
body: buildVideoPlaylistBody(ctx, i),
|
|
257
|
+
}),
|
|
258
|
+
'videoPlaylist:update': async (i) => ({
|
|
259
|
+
method: 'PATCH',
|
|
260
|
+
url: `${baseUrl}/video-playlists/${ctx.getNodeParameter('playlistId', i)}`,
|
|
261
|
+
headers: { 'Content-Type': 'application/json' },
|
|
262
|
+
body: buildVideoPlaylistBody(ctx, i),
|
|
263
|
+
}),
|
|
264
|
+
'videoPlaylist:delete': async (i) => ({
|
|
265
|
+
method: 'DELETE',
|
|
266
|
+
url: `${baseUrl}/video-playlists/${ctx.getNodeParameter('playlistId', i)}`,
|
|
267
|
+
}),
|
|
268
|
+
});
|
|
269
|
+
class BambuserVod {
|
|
270
|
+
description = {
|
|
271
|
+
// `displayName` is the UI label and may follow public product branding freely.
|
|
272
|
+
// `name` is the persisted node type (`<package>.<name>`) baked into every saved
|
|
273
|
+
// workflow — changing it breaks existing flows, so it is frozen to the internal
|
|
274
|
+
// concept (vod) and must NOT track marketing renames.
|
|
275
|
+
displayName: 'Bambuser Shoppable Videos',
|
|
276
|
+
name: 'bambuserVod',
|
|
277
|
+
icon: 'file:bambuser-vod.svg',
|
|
278
|
+
group: ['transform'],
|
|
279
|
+
version: 1,
|
|
280
|
+
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
|
|
281
|
+
description: 'Manage VOD videos, media assets, and playlists via the Bambuser public API. Requires VOD_MANAGE scope.',
|
|
282
|
+
defaults: { name: 'Bambuser Shoppable Videos' },
|
|
283
|
+
inputs: ['main'],
|
|
284
|
+
outputs: ['main'],
|
|
285
|
+
credentials: [{ name: 'bambuserApi', required: true }],
|
|
286
|
+
properties: [
|
|
287
|
+
// ── Resource ──────────────────────────────────────────────────────────
|
|
288
|
+
{
|
|
289
|
+
displayName: 'Resource',
|
|
290
|
+
name: 'resource',
|
|
291
|
+
type: 'options',
|
|
292
|
+
noDataExpression: true,
|
|
293
|
+
options: [
|
|
294
|
+
{ name: 'Video', value: 'video' },
|
|
295
|
+
{ name: 'Media Asset', value: 'mediaAsset' },
|
|
296
|
+
{ name: 'Video Playlist', value: 'videoPlaylist' },
|
|
297
|
+
],
|
|
298
|
+
default: 'video',
|
|
299
|
+
},
|
|
300
|
+
// ── Operations ────────────────────────────────────────────────────────
|
|
301
|
+
{
|
|
302
|
+
displayName: 'Operation',
|
|
303
|
+
name: 'operation',
|
|
304
|
+
type: 'options',
|
|
305
|
+
noDataExpression: true,
|
|
306
|
+
displayOptions: { show: { resource: ['video'] } },
|
|
307
|
+
options: [
|
|
308
|
+
{ name: 'Clip', value: 'clip', action: 'Create a clip from a broadcast' },
|
|
309
|
+
{ name: 'Create', value: 'create', action: 'Create a video' },
|
|
310
|
+
{ name: 'Delete', value: 'delete', action: 'Delete a video' },
|
|
311
|
+
{ name: 'Get', value: 'get', action: 'Get a video by ID' },
|
|
312
|
+
{ name: 'Get Count', value: 'getCount', action: 'Get total video count' },
|
|
313
|
+
{ name: 'Get Many', value: 'getMany', action: 'List videos' },
|
|
314
|
+
{ name: 'Get Views Count', value: 'getViewsCount', action: 'Get total views count for the org' },
|
|
315
|
+
{ name: 'Query', value: 'query', action: 'Query videos with filters' },
|
|
316
|
+
{ name: 'Update', value: 'update', action: 'Update a video' },
|
|
317
|
+
{ name: 'Update Preview', value: 'updatePreview', action: 'Update the preview image of a video' },
|
|
318
|
+
],
|
|
319
|
+
default: 'getMany',
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
displayName: 'Operation',
|
|
323
|
+
name: 'operation',
|
|
324
|
+
type: 'options',
|
|
325
|
+
noDataExpression: true,
|
|
326
|
+
displayOptions: { show: { resource: ['mediaAsset'] } },
|
|
327
|
+
options: [
|
|
328
|
+
{ name: 'Create', value: 'create', action: 'Create a media asset' },
|
|
329
|
+
{ name: 'Create Caption', value: 'createCaption', action: 'Trigger transcription for a language' },
|
|
330
|
+
{ name: 'Create Upload Ticket', value: 'createUploadTicket', action: 'Get a ticket to upload an image' },
|
|
331
|
+
{ name: 'Delete', value: 'delete', action: 'Delete a media asset' },
|
|
332
|
+
{ name: 'Delete Caption', value: 'deleteCaption', action: 'Delete a caption track' },
|
|
333
|
+
{ name: 'Get', value: 'get', action: 'Get a media asset by ID' },
|
|
334
|
+
{ name: 'Get Captions', value: 'getCaptions', action: 'List captions for a media asset' },
|
|
335
|
+
{ name: 'Get Many', value: 'getMany', action: 'List media assets' },
|
|
336
|
+
{ name: 'Update', value: 'update', action: 'Update a media asset' },
|
|
337
|
+
{ name: 'Update Caption', value: 'updateCaption', action: 'Update caption content' },
|
|
338
|
+
{ name: 'Update Upload Status', value: 'updateUploadStatus', action: 'Report upload progress or completion' },
|
|
339
|
+
],
|
|
340
|
+
default: 'getMany',
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
displayName: 'Operation',
|
|
344
|
+
name: 'operation',
|
|
345
|
+
type: 'options',
|
|
346
|
+
noDataExpression: true,
|
|
347
|
+
displayOptions: { show: { resource: ['videoPlaylist'] } },
|
|
348
|
+
options: [
|
|
349
|
+
{ name: 'Create', value: 'create', action: 'Create a playlist' },
|
|
350
|
+
{ name: 'Delete', value: 'delete', action: 'Delete a playlist' },
|
|
351
|
+
{ name: 'Get', value: 'get', action: 'Get a playlist by ID' },
|
|
352
|
+
{ name: 'Get Many', value: 'getMany', action: 'List playlists' },
|
|
353
|
+
{ name: 'Update', value: 'update', action: 'Update a playlist' },
|
|
354
|
+
],
|
|
355
|
+
default: 'getMany',
|
|
356
|
+
},
|
|
357
|
+
// ── Video ID ──────────────────────────────────────────────────────────
|
|
358
|
+
{
|
|
359
|
+
displayName: 'Video ID',
|
|
360
|
+
name: 'videoId',
|
|
361
|
+
type: 'string',
|
|
362
|
+
required: true,
|
|
363
|
+
default: '',
|
|
364
|
+
displayOptions: { show: { resource: ['video'], operation: ['get', 'update', 'delete', 'clip', 'updatePreview'] } },
|
|
365
|
+
},
|
|
366
|
+
// ── Media Asset ID ────────────────────────────────────────────────────
|
|
367
|
+
{
|
|
368
|
+
displayName: 'Media Asset ID',
|
|
369
|
+
name: 'mediaAssetId',
|
|
370
|
+
type: 'string',
|
|
371
|
+
required: true,
|
|
372
|
+
default: '',
|
|
373
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['get', 'update', 'delete', 'updateUploadStatus', 'getCaptions', 'createCaption', 'updateCaption', 'deleteCaption'] } },
|
|
374
|
+
},
|
|
375
|
+
// ── Playlist ID ───────────────────────────────────────────────────────
|
|
376
|
+
{
|
|
377
|
+
displayName: 'Playlist ID',
|
|
378
|
+
name: 'playlistId',
|
|
379
|
+
type: 'string',
|
|
380
|
+
required: true,
|
|
381
|
+
default: '',
|
|
382
|
+
displayOptions: { show: { resource: ['videoPlaylist'], operation: ['get', 'update', 'delete'] } },
|
|
383
|
+
},
|
|
384
|
+
// ── Video create fields ───────────────────────────────────────────────
|
|
385
|
+
{
|
|
386
|
+
displayName: 'Filename',
|
|
387
|
+
name: 'filename',
|
|
388
|
+
type: 'string',
|
|
389
|
+
required: true,
|
|
390
|
+
default: '',
|
|
391
|
+
description: 'File label (e.g. my-show.mp4)',
|
|
392
|
+
displayOptions: { show: { resource: ['video', 'mediaAsset'], operation: ['create'] } },
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
displayName: 'Source URL',
|
|
396
|
+
name: 'sourceUrl',
|
|
397
|
+
type: 'string',
|
|
398
|
+
default: '',
|
|
399
|
+
placeholder: 'https://cdn.bambuser.net/broadcasts/…',
|
|
400
|
+
description: 'Import from URL instead of uploading a file',
|
|
401
|
+
displayOptions: { show: { resource: ['video', 'mediaAsset'], operation: ['create'] } },
|
|
402
|
+
},
|
|
403
|
+
// ── Video create / update ─────────────────────────────────────────────
|
|
404
|
+
{
|
|
405
|
+
displayName: 'Title',
|
|
406
|
+
name: 'title',
|
|
407
|
+
type: 'string',
|
|
408
|
+
required: true,
|
|
409
|
+
default: '',
|
|
410
|
+
displayOptions: { show: { resource: ['video'], operation: ['create', 'update'] } },
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
displayName: 'Description',
|
|
414
|
+
name: 'description',
|
|
415
|
+
type: 'string',
|
|
416
|
+
required: true,
|
|
417
|
+
default: '',
|
|
418
|
+
displayOptions: { show: { resource: ['video'], operation: ['create', 'update'] } },
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
displayName: 'Locale',
|
|
422
|
+
name: 'locale',
|
|
423
|
+
type: 'string',
|
|
424
|
+
default: '',
|
|
425
|
+
placeholder: 'en-US',
|
|
426
|
+
description: 'BCP-47 locale tag (e.g. en-US, sv-SE)',
|
|
427
|
+
displayOptions: { show: { resource: ['video'], operation: ['create', 'update'] } },
|
|
428
|
+
},
|
|
429
|
+
// ── Video list / pagination ───────────────────────────────────────────
|
|
430
|
+
{
|
|
431
|
+
displayName: 'Page Size',
|
|
432
|
+
name: 'pageSize',
|
|
433
|
+
type: 'number',
|
|
434
|
+
typeOptions: { minValue: 1, maxValue: 100 },
|
|
435
|
+
default: 50,
|
|
436
|
+
displayOptions: { show: { resource: ['video'], operation: ['getMany'] } },
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
displayName: 'Cursor',
|
|
440
|
+
name: 'cursor',
|
|
441
|
+
type: 'string',
|
|
442
|
+
default: '',
|
|
443
|
+
description: 'Pagination cursor from a previous response',
|
|
444
|
+
displayOptions: { show: { resource: ['video'], operation: ['getMany'] } },
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
displayName: 'Sort By',
|
|
448
|
+
name: 'sortBy',
|
|
449
|
+
type: 'options',
|
|
450
|
+
options: [
|
|
451
|
+
{ name: 'Created At', value: 'createdAt' },
|
|
452
|
+
{ name: 'Updated At', value: 'updatedAt' },
|
|
453
|
+
{ name: 'Title', value: 'title' },
|
|
454
|
+
{ name: 'Duration', value: 'duration' },
|
|
455
|
+
],
|
|
456
|
+
default: 'createdAt',
|
|
457
|
+
displayOptions: { show: { resource: ['video'], operation: ['getMany'] } },
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
displayName: 'Sort Order',
|
|
461
|
+
name: 'sortOrder',
|
|
462
|
+
type: 'options',
|
|
463
|
+
options: [
|
|
464
|
+
{ name: 'Descending', value: 'DESC' },
|
|
465
|
+
{ name: 'Ascending', value: 'ASC' },
|
|
466
|
+
],
|
|
467
|
+
default: 'DESC',
|
|
468
|
+
displayOptions: { show: { resource: ['video'], operation: ['getMany'] } },
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
displayName: 'Search',
|
|
472
|
+
name: 'search',
|
|
473
|
+
type: 'string',
|
|
474
|
+
default: '',
|
|
475
|
+
displayOptions: { show: { resource: ['video'], operation: ['getMany'] } },
|
|
476
|
+
},
|
|
477
|
+
// ── Video query ───────────────────────────────────────────────────────
|
|
478
|
+
{
|
|
479
|
+
displayName: 'Query Body',
|
|
480
|
+
name: 'queryBody',
|
|
481
|
+
type: 'json',
|
|
482
|
+
default: '{}',
|
|
483
|
+
description: 'JSON filter expression for the query endpoint',
|
|
484
|
+
displayOptions: { show: { resource: ['video'], operation: ['query'] } },
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
displayName: 'Page Size',
|
|
488
|
+
name: 'pageSize',
|
|
489
|
+
type: 'number',
|
|
490
|
+
typeOptions: { minValue: 1, maxValue: 500 },
|
|
491
|
+
default: 25,
|
|
492
|
+
displayOptions: { show: { resource: ['video'], operation: ['query'] } },
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
displayName: 'Cursor',
|
|
496
|
+
name: 'cursor',
|
|
497
|
+
type: 'string',
|
|
498
|
+
default: '',
|
|
499
|
+
description: 'Pagination cursor from a previous response',
|
|
500
|
+
displayOptions: { show: { resource: ['video'], operation: ['query'] } },
|
|
501
|
+
},
|
|
502
|
+
// ── Video getCount ────────────────────────────────────────────────────
|
|
503
|
+
{
|
|
504
|
+
displayName: 'Include Example Videos',
|
|
505
|
+
name: 'includeExampleVideos',
|
|
506
|
+
type: 'boolean',
|
|
507
|
+
default: false,
|
|
508
|
+
displayOptions: { show: { resource: ['video'], operation: ['getCount'] } },
|
|
509
|
+
},
|
|
510
|
+
// ── Video clip ────────────────────────────────────────────────────────
|
|
511
|
+
{
|
|
512
|
+
displayName: 'Broadcast ID',
|
|
513
|
+
name: 'broadcastId',
|
|
514
|
+
type: 'string',
|
|
515
|
+
required: true,
|
|
516
|
+
default: '',
|
|
517
|
+
displayOptions: { show: { resource: ['video'], operation: ['clip'] } },
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
displayName: 'Start (Seconds)',
|
|
521
|
+
name: 'clipStart',
|
|
522
|
+
type: 'number',
|
|
523
|
+
required: true,
|
|
524
|
+
default: 0,
|
|
525
|
+
displayOptions: { show: { resource: ['video'], operation: ['clip'] } },
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
displayName: 'End (Seconds)',
|
|
529
|
+
name: 'clipEnd',
|
|
530
|
+
type: 'number',
|
|
531
|
+
required: true,
|
|
532
|
+
default: 60,
|
|
533
|
+
displayOptions: { show: { resource: ['video'], operation: ['clip'] } },
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
displayName: 'Import Captions',
|
|
537
|
+
name: 'importCaptions',
|
|
538
|
+
type: 'boolean',
|
|
539
|
+
default: false,
|
|
540
|
+
displayOptions: { show: { resource: ['video'], operation: ['clip'] } },
|
|
541
|
+
},
|
|
542
|
+
// ── Video updatePreview ───────────────────────────────────────────────
|
|
543
|
+
{
|
|
544
|
+
displayName: 'File ID',
|
|
545
|
+
name: 'fileId',
|
|
546
|
+
type: 'string',
|
|
547
|
+
required: true,
|
|
548
|
+
default: '',
|
|
549
|
+
description: 'ID of an uploaded image to use as the video preview',
|
|
550
|
+
displayOptions: { show: { resource: ['video'], operation: ['updatePreview'] } },
|
|
551
|
+
},
|
|
552
|
+
// ── MediaAsset create ─────────────────────────────────────────────────
|
|
553
|
+
{
|
|
554
|
+
displayName: 'Video ID (Reference)',
|
|
555
|
+
name: 'refVideoId',
|
|
556
|
+
type: 'string',
|
|
557
|
+
required: true,
|
|
558
|
+
default: '',
|
|
559
|
+
description: 'The video this media asset belongs to',
|
|
560
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['create'] } },
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
displayName: 'Asset Type',
|
|
564
|
+
name: 'mediaType',
|
|
565
|
+
type: 'options',
|
|
566
|
+
options: [
|
|
567
|
+
{ name: 'Image', value: 'image' },
|
|
568
|
+
{ name: 'Video', value: 'video' },
|
|
569
|
+
],
|
|
570
|
+
default: 'image',
|
|
571
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['create'] } },
|
|
572
|
+
},
|
|
573
|
+
// ── MediaAsset update / uploadStatus ──────────────────────────────────
|
|
574
|
+
{
|
|
575
|
+
displayName: 'Vendor Upload ID',
|
|
576
|
+
name: 'vendorUploadId',
|
|
577
|
+
type: 'string',
|
|
578
|
+
default: '',
|
|
579
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['update', 'updateUploadStatus'] } },
|
|
580
|
+
},
|
|
581
|
+
// ── MediaAsset updateUploadStatus ─────────────────────────────────────
|
|
582
|
+
{
|
|
583
|
+
displayName: 'Upload State',
|
|
584
|
+
name: 'uploadState',
|
|
585
|
+
type: 'options',
|
|
586
|
+
options: [
|
|
587
|
+
{ name: 'Completed', value: 'completed' },
|
|
588
|
+
{ name: 'Created', value: 'created' },
|
|
589
|
+
{ name: 'Processing', value: 'processing' },
|
|
590
|
+
{ name: 'Uploading', value: 'uploading' },
|
|
591
|
+
{ name: 'Waiting', value: 'waiting' },
|
|
592
|
+
],
|
|
593
|
+
default: 'completed',
|
|
594
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['updateUploadStatus'] } },
|
|
595
|
+
},
|
|
596
|
+
// ── MediaAsset / VideoPlaylist pagination ─────────────────────────────
|
|
597
|
+
{
|
|
598
|
+
displayName: 'Page Size',
|
|
599
|
+
name: 'pageSize',
|
|
600
|
+
type: 'number',
|
|
601
|
+
typeOptions: { minValue: 1, maxValue: 100 },
|
|
602
|
+
default: 50,
|
|
603
|
+
displayOptions: { show: { resource: ['mediaAsset', 'videoPlaylist'], operation: ['getMany'] } },
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
displayName: 'Cursor',
|
|
607
|
+
name: 'cursor',
|
|
608
|
+
type: 'string',
|
|
609
|
+
default: '',
|
|
610
|
+
description: 'Pagination cursor from a previous response',
|
|
611
|
+
displayOptions: { show: { resource: ['mediaAsset', 'videoPlaylist'], operation: ['getMany'] } },
|
|
612
|
+
},
|
|
613
|
+
// ── MediaAsset createCaption ──────────────────────────────────────────
|
|
614
|
+
{
|
|
615
|
+
displayName: 'Language Code',
|
|
616
|
+
name: 'captionLanguageCode',
|
|
617
|
+
type: 'string',
|
|
618
|
+
required: true,
|
|
619
|
+
default: '',
|
|
620
|
+
placeholder: 'en',
|
|
621
|
+
description: 'BCP-47 language code. Triggers AI transcription for this language.',
|
|
622
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['createCaption'] } },
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
displayName: 'Source Language Code',
|
|
626
|
+
name: 'sourceLanguageCode',
|
|
627
|
+
type: 'string',
|
|
628
|
+
default: '',
|
|
629
|
+
placeholder: 'sv',
|
|
630
|
+
description: 'When set, translates from this language instead of transcribing from audio',
|
|
631
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['createCaption'] } },
|
|
632
|
+
},
|
|
633
|
+
// ── MediaAsset updateCaption / deleteCaption ──────────────────────────
|
|
634
|
+
{
|
|
635
|
+
displayName: 'Language Code',
|
|
636
|
+
name: 'languageCode',
|
|
637
|
+
type: 'string',
|
|
638
|
+
required: true,
|
|
639
|
+
default: '',
|
|
640
|
+
placeholder: 'en',
|
|
641
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['updateCaption', 'deleteCaption'] } },
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
displayName: 'Caption Body',
|
|
645
|
+
name: 'captionBody',
|
|
646
|
+
type: 'json',
|
|
647
|
+
default: '{"title":"","editAccessibility":[]}',
|
|
648
|
+
description: 'Caption data with optional title and array of {startTime, endTime, content} segments',
|
|
649
|
+
displayOptions: { show: { resource: ['mediaAsset'], operation: ['updateCaption'] } },
|
|
650
|
+
},
|
|
651
|
+
// ── VideoPlaylist create / update ─────────────────────────────────────
|
|
652
|
+
{
|
|
653
|
+
displayName: 'Title',
|
|
654
|
+
name: 'playlistTitle',
|
|
655
|
+
type: 'string',
|
|
656
|
+
default: '',
|
|
657
|
+
displayOptions: { show: { resource: ['videoPlaylist'], operation: ['create', 'update'] } },
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
displayName: 'Description',
|
|
661
|
+
name: 'playlistDescription',
|
|
662
|
+
type: 'string',
|
|
663
|
+
default: '',
|
|
664
|
+
displayOptions: { show: { resource: ['videoPlaylist'], operation: ['create', 'update'] } },
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
displayName: 'Published',
|
|
668
|
+
name: 'published',
|
|
669
|
+
type: 'boolean',
|
|
670
|
+
default: false,
|
|
671
|
+
displayOptions: { show: { resource: ['videoPlaylist'], operation: ['create', 'update'] } },
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
displayName: 'Video Order',
|
|
675
|
+
name: 'videoOrder',
|
|
676
|
+
type: 'json',
|
|
677
|
+
default: '[]',
|
|
678
|
+
description: 'Ordered array of video IDs',
|
|
679
|
+
displayOptions: { show: { resource: ['videoPlaylist'], operation: ['create', 'update'] } },
|
|
680
|
+
},
|
|
681
|
+
],
|
|
682
|
+
usableAsTool: true,
|
|
683
|
+
};
|
|
684
|
+
async execute() {
|
|
685
|
+
const items = this.getInputData();
|
|
686
|
+
const credentials = await this.getCredentials('bambuserApi');
|
|
687
|
+
const origin = (0, resolveOrigin_1.resolveOrigin)(credentials.baseUrl, credentials.region);
|
|
688
|
+
const handlers = buildOperationHandlers(this, `${origin}/v1/vod`);
|
|
689
|
+
const results = await Promise.all(items.map(async (_, i) => {
|
|
690
|
+
const resource = this.getNodeParameter('resource', i);
|
|
691
|
+
const operation = this.getNodeParameter('operation', i);
|
|
692
|
+
const key = `${resource}:${operation}`;
|
|
693
|
+
const handler = handlers[key];
|
|
694
|
+
if (!handler) {
|
|
695
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation "${operation}" for resource "${resource}"`, { itemIndex: i });
|
|
696
|
+
}
|
|
697
|
+
const requestOptions = await handler(i);
|
|
698
|
+
const responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'bambuserApi', requestOptions);
|
|
699
|
+
return { json: responseData };
|
|
700
|
+
}));
|
|
701
|
+
return [results];
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
exports.BambuserVod = BambuserVod;
|