n8n-nodes-upload-post 0.1.21 → 0.1.30
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.
|
@@ -6,6 +6,829 @@ const MANUAL_USER_VALUE = '__manual_user__';
|
|
|
6
6
|
const MANUAL_FACEBOOK_VALUE = '__manual_facebook__';
|
|
7
7
|
const MANUAL_LINKEDIN_VALUE = '__manual_linkedin__';
|
|
8
8
|
const MANUAL_PINTEREST_VALUE = '__manual_pinterest__';
|
|
9
|
+
const isBinaryFormField = (value) => {
|
|
10
|
+
return typeof value === 'object' && value !== null && 'value' in value;
|
|
11
|
+
};
|
|
12
|
+
const normalizeFormField = (value) => {
|
|
13
|
+
if (value === undefined || value === null) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
if (isBinaryFormField(value)) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
return String(value);
|
|
20
|
+
};
|
|
21
|
+
const buildMultipartPayload = (rawFormData) => {
|
|
22
|
+
const payload = {};
|
|
23
|
+
for (const [key, rawValue] of Object.entries(rawFormData)) {
|
|
24
|
+
if (rawValue === undefined || rawValue === null)
|
|
25
|
+
continue;
|
|
26
|
+
if (Array.isArray(rawValue)) {
|
|
27
|
+
const normalizedItems = rawValue
|
|
28
|
+
.map(item => normalizeFormField(item))
|
|
29
|
+
.filter((item) => item !== undefined);
|
|
30
|
+
if (normalizedItems.length > 0) {
|
|
31
|
+
payload[key] = normalizedItems;
|
|
32
|
+
}
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const normalizedValue = normalizeFormField(rawValue);
|
|
36
|
+
if (normalizedValue !== undefined) {
|
|
37
|
+
payload[key] = normalizedValue;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return payload;
|
|
41
|
+
};
|
|
42
|
+
const parseJsonIfNeeded = (data) => {
|
|
43
|
+
if (typeof data === 'string') {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(data);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return data;
|
|
52
|
+
};
|
|
53
|
+
const API_BASE_URL = 'https://api.upload-post.com/api';
|
|
54
|
+
const normalizeDateInput = (value) => {
|
|
55
|
+
if (!value)
|
|
56
|
+
return undefined;
|
|
57
|
+
const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(value);
|
|
58
|
+
return hasTimezone ? value : `${value}Z`;
|
|
59
|
+
};
|
|
60
|
+
const ensureArrayFromCommaSeparated = (value) => {
|
|
61
|
+
return value
|
|
62
|
+
.split(',')
|
|
63
|
+
.map(item => item.trim())
|
|
64
|
+
.filter(item => item.length > 0);
|
|
65
|
+
};
|
|
66
|
+
const getBinaryFieldFromItem = async (ctx, propertyName, errorLabel) => {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
const { node, itemIndex, items } = ctx;
|
|
69
|
+
try {
|
|
70
|
+
const binaryBuffer = await node.helpers.getBinaryDataBuffer(itemIndex, propertyName);
|
|
71
|
+
const binaryDetails = (_a = items[itemIndex].binary) === null || _a === void 0 ? void 0 : _a[propertyName];
|
|
72
|
+
return {
|
|
73
|
+
value: binaryBuffer,
|
|
74
|
+
options: {
|
|
75
|
+
filename: (_b = binaryDetails === null || binaryDetails === void 0 ? void 0 : binaryDetails.fileName) !== null && _b !== void 0 ? _b : propertyName,
|
|
76
|
+
contentType: binaryDetails === null || binaryDetails === void 0 ? void 0 : binaryDetails.mimeType,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const message = error instanceof Error ? error.message : '';
|
|
82
|
+
const details = message ? ` (${message})` : '';
|
|
83
|
+
throw new n8n_workflow_1.NodeOperationError(node.getNode(), `${errorLabel} '${propertyName}' was not found in item ${itemIndex}.${details}`, {
|
|
84
|
+
itemIndex,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const PLATFORM_SUPPORT = {
|
|
89
|
+
uploadPhotos: ['facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x'],
|
|
90
|
+
uploadVideo: ['facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x', 'youtube'],
|
|
91
|
+
uploadText: ['facebook', 'linkedin', 'reddit', 'threads', 'x'],
|
|
92
|
+
};
|
|
93
|
+
const DESCRIPTION_ENABLED_PLATFORMS = new Set(['linkedin', 'facebook', 'youtube', 'pinterest', 'tiktok']);
|
|
94
|
+
const TITLE_OVERRIDES = [
|
|
95
|
+
{ platform: 'instagram', param: 'instagramTitle', field: 'instagram_title' },
|
|
96
|
+
{ platform: 'facebook', param: 'facebookTitle', field: 'facebook_title' },
|
|
97
|
+
{ platform: 'tiktok', param: 'tiktokTitle', field: 'tiktok_title' },
|
|
98
|
+
{ platform: 'linkedin', param: 'linkedinTitle', field: 'linkedin_title' },
|
|
99
|
+
{ platform: 'x', param: 'xTitle', field: 'x_title' },
|
|
100
|
+
{ platform: 'youtube', param: 'youtubeTitle', field: 'youtube_title', operations: ['uploadVideo'] },
|
|
101
|
+
{ platform: 'pinterest', param: 'pinterestTitle', field: 'pinterest_title' },
|
|
102
|
+
{ platform: 'threads', param: 'threadsTitle', field: 'threads_title', operations: ['uploadText'] },
|
|
103
|
+
];
|
|
104
|
+
const DESCRIPTION_OVERRIDES = [
|
|
105
|
+
{ platform: 'linkedin', param: 'linkedinDescription', field: 'linkedin_description', operations: ['uploadPhotos', 'uploadVideo'] },
|
|
106
|
+
{ platform: 'youtube', param: 'youtubeDescription', field: 'youtube_description', operations: ['uploadVideo'] },
|
|
107
|
+
{ platform: 'facebook', param: 'facebookDescription', field: 'facebook_description', operations: ['uploadPhotos', 'uploadVideo'] },
|
|
108
|
+
{ platform: 'tiktok', param: 'tiktokDescription', field: 'tiktok_description', operations: ['uploadPhotos'] },
|
|
109
|
+
{ platform: 'pinterest', param: 'pinterestDescription', field: 'pinterest_description', operations: ['uploadPhotos', 'uploadVideo'] },
|
|
110
|
+
];
|
|
111
|
+
const getFilteredPlatforms = (operation, platforms) => {
|
|
112
|
+
var _a;
|
|
113
|
+
const allowed = (_a = PLATFORM_SUPPORT[operation]) !== null && _a !== void 0 ? _a : [];
|
|
114
|
+
return platforms.filter(platform => allowed.includes(platform));
|
|
115
|
+
};
|
|
116
|
+
const applyTitleOverrides = (ctx, operation, platforms, formData) => {
|
|
117
|
+
for (const override of TITLE_OVERRIDES) {
|
|
118
|
+
if (!platforms.includes(override.platform))
|
|
119
|
+
continue;
|
|
120
|
+
if (override.operations && !override.operations.includes(operation))
|
|
121
|
+
continue;
|
|
122
|
+
const value = ctx.node.getNodeParameter(override.param, ctx.itemIndex, '');
|
|
123
|
+
if (value) {
|
|
124
|
+
formData[override.field] = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const applyDescriptionOverrides = (ctx, operation, platforms, formData) => {
|
|
129
|
+
const genericDescription = ctx.node.getNodeParameter('description', ctx.itemIndex, '');
|
|
130
|
+
if (genericDescription &&
|
|
131
|
+
(operation === 'uploadPhotos' || operation === 'uploadVideo') &&
|
|
132
|
+
platforms.some(platform => DESCRIPTION_ENABLED_PLATFORMS.has(platform))) {
|
|
133
|
+
formData.description = genericDescription;
|
|
134
|
+
}
|
|
135
|
+
for (const override of DESCRIPTION_OVERRIDES) {
|
|
136
|
+
if (!platforms.includes(override.platform))
|
|
137
|
+
continue;
|
|
138
|
+
if (override.operations && !override.operations.includes(operation))
|
|
139
|
+
continue;
|
|
140
|
+
const value = ctx.node.getNodeParameter(override.param, ctx.itemIndex, '');
|
|
141
|
+
if (value) {
|
|
142
|
+
formData[override.field] = value;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const getUserForOperation = (ctx, needsUser) => {
|
|
147
|
+
if (!needsUser) {
|
|
148
|
+
return '';
|
|
149
|
+
}
|
|
150
|
+
const selection = ctx.node.getNodeParameter('user', ctx.itemIndex);
|
|
151
|
+
if (selection === MANUAL_USER_VALUE) {
|
|
152
|
+
return ctx.node.getNodeParameter('userManual', ctx.itemIndex);
|
|
153
|
+
}
|
|
154
|
+
return selection;
|
|
155
|
+
};
|
|
156
|
+
const prepareUploadBase = (ctx, operation) => {
|
|
157
|
+
const formData = {};
|
|
158
|
+
const user = getUserForOperation(ctx, true);
|
|
159
|
+
const title = ctx.node.getNodeParameter('title', ctx.itemIndex);
|
|
160
|
+
formData.user = user;
|
|
161
|
+
formData.title = title;
|
|
162
|
+
const scheduledDate = normalizeDateInput(ctx.node.getNodeParameter('scheduledDate', ctx.itemIndex, ''));
|
|
163
|
+
if (scheduledDate) {
|
|
164
|
+
formData.scheduled_date = scheduledDate;
|
|
165
|
+
}
|
|
166
|
+
const uploadAsync = ctx.node.getNodeParameter('uploadAsync', ctx.itemIndex);
|
|
167
|
+
if (uploadAsync !== undefined) {
|
|
168
|
+
formData.async_upload = String(uploadAsync);
|
|
169
|
+
}
|
|
170
|
+
const rawPlatforms = ctx.node.getNodeParameter('platform', ctx.itemIndex);
|
|
171
|
+
const platforms = getFilteredPlatforms(operation, Array.isArray(rawPlatforms) ? rawPlatforms : []);
|
|
172
|
+
formData['platform[]'] = platforms;
|
|
173
|
+
applyTitleOverrides(ctx, operation, platforms, formData);
|
|
174
|
+
applyDescriptionOverrides(ctx, operation, platforms, formData);
|
|
175
|
+
const waitForCompletion = ctx.node.getNodeParameter('waitForCompletion', ctx.itemIndex, false);
|
|
176
|
+
const pollInterval = ctx.node.getNodeParameter('pollInterval', ctx.itemIndex, 10);
|
|
177
|
+
const pollTimeout = ctx.node.getNodeParameter('pollTimeout', ctx.itemIndex, 600);
|
|
178
|
+
return {
|
|
179
|
+
formData,
|
|
180
|
+
platforms,
|
|
181
|
+
waitForCompletion,
|
|
182
|
+
pollInterval,
|
|
183
|
+
pollTimeout,
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
const applyPinterestOptions = (ctx, operation, formData) => {
|
|
187
|
+
const selection = ctx.node.getNodeParameter('pinterestBoardId', ctx.itemIndex, '');
|
|
188
|
+
const pinterestBoardId = selection === MANUAL_PINTEREST_VALUE
|
|
189
|
+
? ctx.node.getNodeParameter('pinterestBoardIdManual', ctx.itemIndex)
|
|
190
|
+
: selection;
|
|
191
|
+
if (pinterestBoardId) {
|
|
192
|
+
formData.pinterest_board_id = pinterestBoardId;
|
|
193
|
+
}
|
|
194
|
+
const pinterestLink = ctx.node.getNodeParameter('pinterestLink', ctx.itemIndex, '');
|
|
195
|
+
if (pinterestLink) {
|
|
196
|
+
formData.pinterest_link = pinterestLink;
|
|
197
|
+
}
|
|
198
|
+
if (operation === 'uploadVideo') {
|
|
199
|
+
const pinterestCoverImageUrl = ctx.node.getNodeParameter('pinterestCoverImageUrl', ctx.itemIndex, '');
|
|
200
|
+
const pinterestCoverImageContentType = ctx.node.getNodeParameter('pinterestCoverImageContentType', ctx.itemIndex, '');
|
|
201
|
+
const pinterestCoverImageData = ctx.node.getNodeParameter('pinterestCoverImageData', ctx.itemIndex, '');
|
|
202
|
+
const pinterestCoverImageKeyFrameTime = ctx.node.getNodeParameter('pinterestCoverImageKeyFrameTime', ctx.itemIndex, 0);
|
|
203
|
+
if (pinterestCoverImageUrl) {
|
|
204
|
+
formData.pinterest_cover_image_url = pinterestCoverImageUrl;
|
|
205
|
+
}
|
|
206
|
+
else if (pinterestCoverImageContentType && pinterestCoverImageData) {
|
|
207
|
+
formData.pinterest_cover_image_content_type = pinterestCoverImageContentType;
|
|
208
|
+
formData.pinterest_cover_image_data = pinterestCoverImageData;
|
|
209
|
+
}
|
|
210
|
+
else if (pinterestCoverImageKeyFrameTime !== undefined) {
|
|
211
|
+
formData.pinterest_cover_image_key_frame_time = pinterestCoverImageKeyFrameTime;
|
|
212
|
+
}
|
|
213
|
+
if (pinterestLink) {
|
|
214
|
+
formData.pinterest_link = pinterestLink;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const applyLinkedinOptions = (ctx, operation, formData) => {
|
|
219
|
+
const selection = ctx.node.getNodeParameter('targetLinkedinPageId', ctx.itemIndex, '');
|
|
220
|
+
const resolvedValue = selection === MANUAL_LINKEDIN_VALUE
|
|
221
|
+
? ctx.node.getNodeParameter('targetLinkedinPageIdManual', ctx.itemIndex)
|
|
222
|
+
: selection;
|
|
223
|
+
if (resolvedValue && resolvedValue !== 'me') {
|
|
224
|
+
const match = resolvedValue.match(/(\d+)$/);
|
|
225
|
+
formData.target_linkedin_page_id = match ? match[1] : resolvedValue;
|
|
226
|
+
}
|
|
227
|
+
if (operation === 'uploadPhotos') {
|
|
228
|
+
const linkedinVisibility = ctx.node.getNodeParameter('linkedinVisibility', ctx.itemIndex, 'PUBLIC');
|
|
229
|
+
if (linkedinVisibility === 'PUBLIC') {
|
|
230
|
+
formData.visibility = 'PUBLIC';
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else if (operation === 'uploadVideo') {
|
|
234
|
+
const linkedinVisibility = ctx.node.getNodeParameter('linkedinVisibility', ctx.itemIndex, 'PUBLIC');
|
|
235
|
+
formData.visibility = linkedinVisibility;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const applyFacebookOptions = (ctx, operation, formData) => {
|
|
239
|
+
const selection = ctx.node.getNodeParameter('facebookPageId', ctx.itemIndex);
|
|
240
|
+
const resolvedValue = selection === MANUAL_FACEBOOK_VALUE
|
|
241
|
+
? ctx.node.getNodeParameter('facebookPageIdManual', ctx.itemIndex)
|
|
242
|
+
: selection;
|
|
243
|
+
formData.facebook_page_id = resolvedValue;
|
|
244
|
+
if (operation === 'uploadVideo') {
|
|
245
|
+
const facebookVideoState = ctx.node.getNodeParameter('facebookVideoState', ctx.itemIndex, '');
|
|
246
|
+
const facebookMediaType = ctx.node.getNodeParameter('facebookMediaType', ctx.itemIndex, '');
|
|
247
|
+
if (facebookVideoState) {
|
|
248
|
+
formData.video_state = facebookVideoState;
|
|
249
|
+
}
|
|
250
|
+
if (facebookMediaType) {
|
|
251
|
+
formData.facebook_media_type = facebookMediaType;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else if (operation === 'uploadText') {
|
|
255
|
+
const facebookLink = ctx.node.getNodeParameter('facebookLink', ctx.itemIndex, '');
|
|
256
|
+
if (facebookLink) {
|
|
257
|
+
formData.facebook_link_url = facebookLink;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
const applyTiktokOptions = (ctx, operation, formData) => {
|
|
262
|
+
if (operation === 'uploadPhotos') {
|
|
263
|
+
const autoAddMusic = ctx.node.getNodeParameter('tiktokAutoAddMusic', ctx.itemIndex, false);
|
|
264
|
+
const disableComment = ctx.node.getNodeParameter('tiktokDisableComment', ctx.itemIndex, false);
|
|
265
|
+
const brandContentToggle = ctx.node.getNodeParameter('brand_content_toggle', ctx.itemIndex, false);
|
|
266
|
+
const brandOrganicToggle = ctx.node.getNodeParameter('brand_organic_toggle', ctx.itemIndex, false);
|
|
267
|
+
const photoCoverIndex = ctx.node.getNodeParameter('tiktokPhotoCoverIndex', ctx.itemIndex, 0);
|
|
268
|
+
const photoDescription = ctx.node.getNodeParameter('tiktokPhotoDescription', ctx.itemIndex, '');
|
|
269
|
+
formData.auto_add_music = String(autoAddMusic);
|
|
270
|
+
formData.disable_comment = String(disableComment);
|
|
271
|
+
formData.brand_content_toggle = String(brandContentToggle);
|
|
272
|
+
formData.brand_organic_toggle = String(brandOrganicToggle);
|
|
273
|
+
formData.photo_cover_index = photoCoverIndex;
|
|
274
|
+
if (photoDescription && formData.description === undefined) {
|
|
275
|
+
formData.description = photoDescription;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else if (operation === 'uploadVideo') {
|
|
279
|
+
const privacyLevel = ctx.node.getNodeParameter('tiktokPrivacyLevel', ctx.itemIndex, '');
|
|
280
|
+
const disableDuet = ctx.node.getNodeParameter('tiktokDisableDuet', ctx.itemIndex, false);
|
|
281
|
+
const disableComment = ctx.node.getNodeParameter('tiktokDisableComment', ctx.itemIndex, false);
|
|
282
|
+
const disableStitch = ctx.node.getNodeParameter('tiktokDisableStitch', ctx.itemIndex, false);
|
|
283
|
+
const coverTimestamp = ctx.node.getNodeParameter('tiktokCoverTimestamp', ctx.itemIndex, 1000);
|
|
284
|
+
const brandContentToggle = ctx.node.getNodeParameter('brand_content_toggle', ctx.itemIndex, false);
|
|
285
|
+
const brandOrganicToggle = ctx.node.getNodeParameter('brand_organic_toggle', ctx.itemIndex, false);
|
|
286
|
+
const isAigc = ctx.node.getNodeParameter('tiktokIsAigc', ctx.itemIndex, false);
|
|
287
|
+
const postMode = ctx.node.getNodeParameter('tiktokPostMode', ctx.itemIndex, '');
|
|
288
|
+
if (privacyLevel)
|
|
289
|
+
formData.privacy_level = privacyLevel;
|
|
290
|
+
formData.disable_duet = String(disableDuet);
|
|
291
|
+
formData.disable_comment = String(disableComment);
|
|
292
|
+
formData.disable_stitch = String(disableStitch);
|
|
293
|
+
formData.cover_timestamp = coverTimestamp;
|
|
294
|
+
formData.brand_content_toggle = String(brandContentToggle);
|
|
295
|
+
formData.brand_organic_toggle = String(brandOrganicToggle);
|
|
296
|
+
formData.is_aigc = String(isAigc);
|
|
297
|
+
if (postMode)
|
|
298
|
+
formData.post_mode = postMode;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
const applyInstagramOptions = (ctx, operation, formData) => {
|
|
302
|
+
const providedMediaType = ctx.node.getNodeParameter('instagramMediaType', ctx.itemIndex, '');
|
|
303
|
+
let finalMediaType = providedMediaType;
|
|
304
|
+
if (operation === 'uploadPhotos') {
|
|
305
|
+
if (!['IMAGE', 'STORIES'].includes(providedMediaType)) {
|
|
306
|
+
finalMediaType = 'IMAGE';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
else if (operation === 'uploadVideo') {
|
|
310
|
+
if (!['REELS', 'STORIES'].includes(providedMediaType)) {
|
|
311
|
+
finalMediaType = 'REELS';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (finalMediaType) {
|
|
315
|
+
formData.media_type = finalMediaType;
|
|
316
|
+
}
|
|
317
|
+
if (operation === 'uploadVideo') {
|
|
318
|
+
const shareToFeed = ctx.node.getNodeParameter('instagramShareToFeed', ctx.itemIndex, true);
|
|
319
|
+
const collaborators = ctx.node.getNodeParameter('instagramCollaborators', ctx.itemIndex, '');
|
|
320
|
+
const coverUrl = ctx.node.getNodeParameter('instagramCoverUrl', ctx.itemIndex, '');
|
|
321
|
+
const audioName = ctx.node.getNodeParameter('instagramAudioName', ctx.itemIndex, '');
|
|
322
|
+
const userTags = ctx.node.getNodeParameter('instagramUserTags', ctx.itemIndex, '');
|
|
323
|
+
const locationId = ctx.node.getNodeParameter('instagramLocationId', ctx.itemIndex, '');
|
|
324
|
+
const thumbOffset = ctx.node.getNodeParameter('instagramThumbOffset', ctx.itemIndex, '');
|
|
325
|
+
formData.share_to_feed = String(shareToFeed);
|
|
326
|
+
if (collaborators)
|
|
327
|
+
formData.collaborators = collaborators;
|
|
328
|
+
if (coverUrl)
|
|
329
|
+
formData.cover_url = coverUrl;
|
|
330
|
+
if (audioName)
|
|
331
|
+
formData.audio_name = audioName;
|
|
332
|
+
if (userTags)
|
|
333
|
+
formData.user_tags = userTags;
|
|
334
|
+
if (locationId)
|
|
335
|
+
formData.location_id = locationId;
|
|
336
|
+
if (thumbOffset)
|
|
337
|
+
formData.thumb_offset = thumbOffset;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const applyYoutubeOptions = async (ctx, formData) => {
|
|
341
|
+
const tagsRaw = ctx.node.getNodeParameter('youtubeTags', ctx.itemIndex, '');
|
|
342
|
+
const categoryId = ctx.node.getNodeParameter('youtubeCategoryId', ctx.itemIndex, '');
|
|
343
|
+
const privacyStatus = ctx.node.getNodeParameter('youtubePrivacyStatus', ctx.itemIndex, '');
|
|
344
|
+
const embeddable = ctx.node.getNodeParameter('youtubeEmbeddable', ctx.itemIndex, true);
|
|
345
|
+
const license = ctx.node.getNodeParameter('youtubeLicense', ctx.itemIndex, '');
|
|
346
|
+
const publicStatsViewable = ctx.node.getNodeParameter('youtubePublicStatsViewable', ctx.itemIndex, true);
|
|
347
|
+
const madeForKids = ctx.node.getNodeParameter('youtubeMadeForKids', ctx.itemIndex, false);
|
|
348
|
+
const thumbnailInput = ctx.node.getNodeParameter('youtubeThumbnail', ctx.itemIndex, '');
|
|
349
|
+
if (tagsRaw)
|
|
350
|
+
formData['tags[]'] = ensureArrayFromCommaSeparated(tagsRaw);
|
|
351
|
+
if (categoryId)
|
|
352
|
+
formData.categoryId = categoryId;
|
|
353
|
+
if (privacyStatus)
|
|
354
|
+
formData.privacyStatus = privacyStatus;
|
|
355
|
+
formData.embeddable = String(embeddable);
|
|
356
|
+
if (license)
|
|
357
|
+
formData.license = license;
|
|
358
|
+
formData.publicStatsViewable = String(publicStatsViewable);
|
|
359
|
+
formData.madeForKids = String(madeForKids);
|
|
360
|
+
if (thumbnailInput) {
|
|
361
|
+
if (thumbnailInput.toLowerCase().startsWith('http://') || thumbnailInput.toLowerCase().startsWith('https://')) {
|
|
362
|
+
formData.thumbnail_url = thumbnailInput;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
const thumbnailBinary = await getBinaryFieldFromItem(ctx, thumbnailInput, 'Binary data for YouTube thumbnail property');
|
|
366
|
+
formData.thumbnail = thumbnailBinary;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const selfDeclaredMadeForKids = ctx.node.getNodeParameter('youtubeSelfDeclaredMadeForKids', ctx.itemIndex, false);
|
|
370
|
+
const containsSyntheticMedia = ctx.node.getNodeParameter('youtubeContainsSyntheticMedia', ctx.itemIndex, false);
|
|
371
|
+
const defaultLanguage = ctx.node.getNodeParameter('youtubeDefaultLanguage', ctx.itemIndex, '');
|
|
372
|
+
const defaultAudioLanguage = ctx.node.getNodeParameter('youtubeDefaultAudioLanguage', ctx.itemIndex, '');
|
|
373
|
+
const allowedCountries = ctx.node.getNodeParameter('youtubeAllowedCountries', ctx.itemIndex, '');
|
|
374
|
+
const blockedCountries = ctx.node.getNodeParameter('youtubeBlockedCountries', ctx.itemIndex, '');
|
|
375
|
+
const hasPaidProductPlacement = ctx.node.getNodeParameter('youtubeHasPaidProductPlacement', ctx.itemIndex, false);
|
|
376
|
+
const recordingDate = ctx.node.getNodeParameter('youtubeRecordingDate', ctx.itemIndex, '');
|
|
377
|
+
formData.selfDeclaredMadeForKids = String(selfDeclaredMadeForKids);
|
|
378
|
+
formData.containsSyntheticMedia = String(containsSyntheticMedia);
|
|
379
|
+
if (defaultLanguage)
|
|
380
|
+
formData.defaultLanguage = defaultLanguage;
|
|
381
|
+
if (defaultAudioLanguage)
|
|
382
|
+
formData.defaultAudioLanguage = defaultAudioLanguage;
|
|
383
|
+
if (allowedCountries)
|
|
384
|
+
formData.allowedCountries = allowedCountries;
|
|
385
|
+
if (blockedCountries)
|
|
386
|
+
formData.blockedCountries = blockedCountries;
|
|
387
|
+
formData.hasPaidProductPlacement = String(hasPaidProductPlacement);
|
|
388
|
+
if (recordingDate)
|
|
389
|
+
formData.recordingDate = recordingDate;
|
|
390
|
+
};
|
|
391
|
+
const validateXPollConfiguration = (ctx, operation, formData) => {
|
|
392
|
+
if (operation !== 'uploadText') {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const pollOptionsRaw = ctx.node.getNodeParameter('xPollOptions', ctx.itemIndex, '');
|
|
396
|
+
const hasPollOptions = pollOptionsRaw.trim().length > 0;
|
|
397
|
+
if (!hasPollOptions) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const conflictingFields = [];
|
|
401
|
+
const cardUri = ctx.node.getNodeParameter('xCardUri', ctx.itemIndex, '');
|
|
402
|
+
const quoteTweetId = ctx.node.getNodeParameter('xQuoteTweetId', ctx.itemIndex, '');
|
|
403
|
+
const directMessageDeepLink = ctx.node.getNodeParameter('xDirectMessageDeepLink', ctx.itemIndex, '');
|
|
404
|
+
if (cardUri.trim().length > 0)
|
|
405
|
+
conflictingFields.push('X Card URI');
|
|
406
|
+
if (quoteTweetId.trim().length > 0)
|
|
407
|
+
conflictingFields.push('X Quote Tweet ID');
|
|
408
|
+
if (directMessageDeepLink.trim().length > 0)
|
|
409
|
+
conflictingFields.push('X Direct Message Deep Link');
|
|
410
|
+
if (conflictingFields.length > 0) {
|
|
411
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options cannot be used with: ${conflictingFields.join(', ')}. These fields are mutually exclusive.`);
|
|
412
|
+
}
|
|
413
|
+
const pollOptions = ensureArrayFromCommaSeparated(pollOptionsRaw);
|
|
414
|
+
if (pollOptions.length < 2 || pollOptions.length > 4) {
|
|
415
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options must contain between 2 and 4 non-empty options. Found: ${pollOptions.length}`);
|
|
416
|
+
}
|
|
417
|
+
const invalidOptions = pollOptions.filter(option => option.length > 25);
|
|
418
|
+
if (invalidOptions.length > 0) {
|
|
419
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options cannot exceed 25 characters each. Invalid options: ${invalidOptions.join(', ')}`);
|
|
420
|
+
}
|
|
421
|
+
const pollDuration = ctx.node.getNodeParameter('xPollDuration', ctx.itemIndex, 1440);
|
|
422
|
+
if (pollDuration < 5 || pollDuration > 10080) {
|
|
423
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Duration must be between 5 and 10080 minutes (5 minutes to 7 days). Provided: ${pollDuration}`);
|
|
424
|
+
}
|
|
425
|
+
formData['poll_options[]'] = pollOptions;
|
|
426
|
+
formData.poll_duration = pollDuration;
|
|
427
|
+
const pollReplySettings = ctx.node.getNodeParameter('xPollReplySettings', ctx.itemIndex, 'following');
|
|
428
|
+
formData.poll_reply_settings = pollReplySettings;
|
|
429
|
+
};
|
|
430
|
+
const applyXOptions = (ctx, operation, formData) => {
|
|
431
|
+
const quoteTweetId = ctx.node.getNodeParameter('xQuoteTweetId', ctx.itemIndex, '');
|
|
432
|
+
const geoPlaceId = ctx.node.getNodeParameter('xGeoPlaceId', ctx.itemIndex, '');
|
|
433
|
+
const forSuperFollowersOnly = ctx.node.getNodeParameter('xForSuperFollowersOnly', ctx.itemIndex, false);
|
|
434
|
+
const communityId = ctx.node.getNodeParameter('xCommunityId', ctx.itemIndex, '');
|
|
435
|
+
const shareWithFollowers = ctx.node.getNodeParameter('xShareWithFollowers', ctx.itemIndex, false);
|
|
436
|
+
const directMessageDeepLink = ctx.node.getNodeParameter('xDirectMessageDeepLink', ctx.itemIndex, '');
|
|
437
|
+
const cardUri = ctx.node.getNodeParameter('xCardUri', ctx.itemIndex, '');
|
|
438
|
+
if (quoteTweetId)
|
|
439
|
+
formData.quote_tweet_id = quoteTweetId;
|
|
440
|
+
if (geoPlaceId)
|
|
441
|
+
formData.geo_place_id = geoPlaceId;
|
|
442
|
+
if (forSuperFollowersOnly)
|
|
443
|
+
formData.for_super_followers_only = String(forSuperFollowersOnly);
|
|
444
|
+
if (communityId)
|
|
445
|
+
formData.community_id = communityId;
|
|
446
|
+
if (shareWithFollowers)
|
|
447
|
+
formData.share_with_followers = String(shareWithFollowers);
|
|
448
|
+
if (directMessageDeepLink)
|
|
449
|
+
formData.direct_message_deep_link = directMessageDeepLink;
|
|
450
|
+
if (cardUri)
|
|
451
|
+
formData.card_uri = cardUri;
|
|
452
|
+
if (operation === 'uploadText') {
|
|
453
|
+
const postUrl = ctx.node.getNodeParameter('xPostUrlText', ctx.itemIndex, '');
|
|
454
|
+
const replySettings = ctx.node.getNodeParameter('xReplySettings', ctx.itemIndex, 'everyone');
|
|
455
|
+
if (postUrl)
|
|
456
|
+
formData.post_url = postUrl;
|
|
457
|
+
if (replySettings && replySettings !== 'everyone')
|
|
458
|
+
formData.reply_settings = replySettings;
|
|
459
|
+
validateXPollConfiguration(ctx, operation, formData);
|
|
460
|
+
const xLongTextAsPost = ctx.node.getNodeParameter('xLongTextAsPost', ctx.itemIndex, false);
|
|
461
|
+
if (xLongTextAsPost) {
|
|
462
|
+
formData.x_long_text_as_post = String(xLongTextAsPost);
|
|
463
|
+
}
|
|
464
|
+
delete formData.nullcast;
|
|
465
|
+
delete formData.place_id;
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
const taggedUserIds = ctx.node.getNodeParameter('xTaggedUserIds', ctx.itemIndex, '');
|
|
469
|
+
const replySettings = ctx.node.getNodeParameter('xReplySettings', ctx.itemIndex, 'everyone');
|
|
470
|
+
const nullcast = ctx.node.getNodeParameter('xNullcastVideo', ctx.itemIndex, false);
|
|
471
|
+
if (taggedUserIds) {
|
|
472
|
+
formData['tagged_user_ids[]'] = ensureArrayFromCommaSeparated(taggedUserIds);
|
|
473
|
+
}
|
|
474
|
+
if (replySettings && replySettings !== 'everyone')
|
|
475
|
+
formData.reply_settings = replySettings;
|
|
476
|
+
formData.nullcast = String(nullcast);
|
|
477
|
+
if (operation === 'uploadVideo') {
|
|
478
|
+
const xLongTextAsPost = ctx.node.getNodeParameter('xLongTextAsPost', ctx.itemIndex, false);
|
|
479
|
+
if (xLongTextAsPost) {
|
|
480
|
+
formData.x_long_text_as_post = String(xLongTextAsPost);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const xPlaceIdVideo = ctx.node.getNodeParameter('xPlaceIdVideo', ctx.itemIndex, '');
|
|
484
|
+
if (operation === 'uploadVideo' && xPlaceIdVideo) {
|
|
485
|
+
formData.place_id = xPlaceIdVideo;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
const applyThreadsOptions = (ctx, formData) => {
|
|
490
|
+
const threadsLongTextAsPost = ctx.node.getNodeParameter('threadsLongTextAsPost', ctx.itemIndex, false);
|
|
491
|
+
if (threadsLongTextAsPost) {
|
|
492
|
+
formData.threads_long_text_as_post = String(threadsLongTextAsPost);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const applyRedditOptions = (ctx, formData) => {
|
|
496
|
+
const subreddit = ctx.node.getNodeParameter('redditSubreddit', ctx.itemIndex);
|
|
497
|
+
const flairId = ctx.node.getNodeParameter('redditFlairId', ctx.itemIndex, '');
|
|
498
|
+
formData.subreddit = subreddit;
|
|
499
|
+
if (flairId) {
|
|
500
|
+
formData.flair_id = flairId;
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
const applyUploadPlatformOptions = async (ctx, operation, prep) => {
|
|
504
|
+
const { formData, platforms } = prep;
|
|
505
|
+
if (platforms.includes('pinterest')) {
|
|
506
|
+
applyPinterestOptions(ctx, operation, formData);
|
|
507
|
+
}
|
|
508
|
+
if (platforms.includes('linkedin')) {
|
|
509
|
+
applyLinkedinOptions(ctx, operation, formData);
|
|
510
|
+
}
|
|
511
|
+
if (platforms.includes('facebook')) {
|
|
512
|
+
applyFacebookOptions(ctx, operation, formData);
|
|
513
|
+
}
|
|
514
|
+
if (platforms.includes('tiktok')) {
|
|
515
|
+
applyTiktokOptions(ctx, operation, formData);
|
|
516
|
+
}
|
|
517
|
+
if (platforms.includes('instagram')) {
|
|
518
|
+
applyInstagramOptions(ctx, operation, formData);
|
|
519
|
+
}
|
|
520
|
+
if (platforms.includes('youtube') && operation === 'uploadVideo') {
|
|
521
|
+
await applyYoutubeOptions(ctx, formData);
|
|
522
|
+
}
|
|
523
|
+
if (platforms.includes('x')) {
|
|
524
|
+
applyXOptions(ctx, operation, formData);
|
|
525
|
+
}
|
|
526
|
+
if (operation === 'uploadText' && platforms.includes('threads')) {
|
|
527
|
+
applyThreadsOptions(ctx, formData);
|
|
528
|
+
}
|
|
529
|
+
if (operation === 'uploadText' && platforms.includes('reddit')) {
|
|
530
|
+
applyRedditOptions(ctx, formData);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
const buildUploadPhotosRequest = async (ctx) => {
|
|
534
|
+
const prep = prepareUploadBase(ctx, 'uploadPhotos');
|
|
535
|
+
const photosInput = ctx.node.getNodeParameter('photos', ctx.itemIndex, '');
|
|
536
|
+
let photosToProcess = [];
|
|
537
|
+
if (Array.isArray(photosInput)) {
|
|
538
|
+
photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim().length > 0).map(item => item.trim());
|
|
539
|
+
}
|
|
540
|
+
else if (typeof photosInput === 'string') {
|
|
541
|
+
photosToProcess = ensureArrayFromCommaSeparated(photosInput);
|
|
542
|
+
}
|
|
543
|
+
const photoArray = [];
|
|
544
|
+
for (const photoItem of photosToProcess) {
|
|
545
|
+
if (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://')) {
|
|
546
|
+
photoArray.push(photoItem);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const binaryField = await getBinaryFieldFromItem(ctx, photoItem, 'Binary data for property');
|
|
550
|
+
photoArray.push(binaryField);
|
|
551
|
+
}
|
|
552
|
+
if (photoArray.length > 0) {
|
|
553
|
+
prep.formData['photos[]'] = photoArray;
|
|
554
|
+
}
|
|
555
|
+
await applyUploadPlatformOptions(ctx, 'uploadPhotos', prep);
|
|
556
|
+
return {
|
|
557
|
+
endpoint: '/upload_photos',
|
|
558
|
+
method: 'POST',
|
|
559
|
+
formData: prep.formData,
|
|
560
|
+
isUploadOperation: true,
|
|
561
|
+
waitForCompletion: prep.waitForCompletion,
|
|
562
|
+
pollInterval: prep.pollInterval,
|
|
563
|
+
pollTimeout: prep.pollTimeout,
|
|
564
|
+
};
|
|
565
|
+
};
|
|
566
|
+
const buildUploadVideoRequest = async (ctx) => {
|
|
567
|
+
const prep = prepareUploadBase(ctx, 'uploadVideo');
|
|
568
|
+
const videoInput = ctx.node.getNodeParameter('video', ctx.itemIndex, '');
|
|
569
|
+
if (videoInput) {
|
|
570
|
+
if (videoInput.toLowerCase().startsWith('http://') || videoInput.toLowerCase().startsWith('https://')) {
|
|
571
|
+
prep.formData.video = videoInput;
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
const binaryField = await getBinaryFieldFromItem(ctx, videoInput, 'Binary data for video property');
|
|
575
|
+
prep.formData.video = binaryField;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
await applyUploadPlatformOptions(ctx, 'uploadVideo', prep);
|
|
579
|
+
return {
|
|
580
|
+
endpoint: '/upload',
|
|
581
|
+
method: 'POST',
|
|
582
|
+
formData: prep.formData,
|
|
583
|
+
isUploadOperation: true,
|
|
584
|
+
waitForCompletion: prep.waitForCompletion,
|
|
585
|
+
pollInterval: prep.pollInterval,
|
|
586
|
+
pollTimeout: prep.pollTimeout,
|
|
587
|
+
};
|
|
588
|
+
};
|
|
589
|
+
const buildUploadTextRequest = async (ctx) => {
|
|
590
|
+
const prep = prepareUploadBase(ctx, 'uploadText');
|
|
591
|
+
await applyUploadPlatformOptions(ctx, 'uploadText', prep);
|
|
592
|
+
return {
|
|
593
|
+
endpoint: '/upload_text',
|
|
594
|
+
method: 'POST',
|
|
595
|
+
formData: prep.formData,
|
|
596
|
+
isUploadOperation: true,
|
|
597
|
+
waitForCompletion: prep.waitForCompletion,
|
|
598
|
+
pollInterval: prep.pollInterval,
|
|
599
|
+
pollTimeout: prep.pollTimeout,
|
|
600
|
+
};
|
|
601
|
+
};
|
|
602
|
+
const buildMonitoringRequest = (ctx) => {
|
|
603
|
+
switch (ctx.operation) {
|
|
604
|
+
case 'getStatus': {
|
|
605
|
+
const requestId = ctx.node.getNodeParameter('requestId', ctx.itemIndex);
|
|
606
|
+
return {
|
|
607
|
+
endpoint: '/uploadposts/status',
|
|
608
|
+
method: 'GET',
|
|
609
|
+
qs: { request_id: requestId },
|
|
610
|
+
isUploadOperation: false,
|
|
611
|
+
waitForCompletion: false,
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
case 'getHistory': {
|
|
615
|
+
const page = ctx.node.getNodeParameter('historyPage', ctx.itemIndex, 1);
|
|
616
|
+
const limit = ctx.node.getNodeParameter('historyLimit', ctx.itemIndex, 20);
|
|
617
|
+
return {
|
|
618
|
+
endpoint: '/uploadposts/history',
|
|
619
|
+
method: 'GET',
|
|
620
|
+
qs: { page, limit },
|
|
621
|
+
isUploadOperation: false,
|
|
622
|
+
waitForCompletion: false,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
case 'getAnalytics': {
|
|
626
|
+
const profileUsername = ctx.node.getNodeParameter('analyticsProfileUsername', ctx.itemIndex);
|
|
627
|
+
const analyticsPlatforms = ctx.node.getNodeParameter('analyticsPlatforms', ctx.itemIndex, []);
|
|
628
|
+
const qs = {};
|
|
629
|
+
if (Array.isArray(analyticsPlatforms) && analyticsPlatforms.length > 0) {
|
|
630
|
+
qs.platforms = analyticsPlatforms.join(',');
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
endpoint: `/analytics/${encodeURIComponent(profileUsername)}`,
|
|
634
|
+
method: 'GET',
|
|
635
|
+
qs,
|
|
636
|
+
isUploadOperation: false,
|
|
637
|
+
waitForCompletion: false,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
case 'listScheduled': {
|
|
641
|
+
return {
|
|
642
|
+
endpoint: '/uploadposts/schedule',
|
|
643
|
+
method: 'GET',
|
|
644
|
+
isUploadOperation: false,
|
|
645
|
+
waitForCompletion: false,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
case 'cancelScheduled': {
|
|
649
|
+
const jobId = ctx.node.getNodeParameter('scheduleJobId', ctx.itemIndex);
|
|
650
|
+
return {
|
|
651
|
+
endpoint: `/uploadposts/schedule/${jobId}`,
|
|
652
|
+
method: 'DELETE',
|
|
653
|
+
isUploadOperation: false,
|
|
654
|
+
waitForCompletion: false,
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
case 'editScheduled': {
|
|
658
|
+
const jobId = ctx.node.getNodeParameter('scheduleJobId', ctx.itemIndex);
|
|
659
|
+
const newScheduledDateRaw = ctx.node.getNodeParameter('newScheduledDate', ctx.itemIndex, '');
|
|
660
|
+
const normalizedDate = normalizeDateInput(newScheduledDateRaw);
|
|
661
|
+
const body = {};
|
|
662
|
+
if (normalizedDate) {
|
|
663
|
+
body.scheduled_date = normalizedDate;
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
endpoint: `/uploadposts/schedule/${jobId}`,
|
|
667
|
+
method: 'POST',
|
|
668
|
+
body,
|
|
669
|
+
isUploadOperation: false,
|
|
670
|
+
waitForCompletion: false,
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
default:
|
|
674
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported monitoring operation: ${ctx.operation}`, {
|
|
675
|
+
itemIndex: ctx.itemIndex,
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
const buildUserRequest = (ctx) => {
|
|
680
|
+
switch (ctx.operation) {
|
|
681
|
+
case 'listUsers':
|
|
682
|
+
return {
|
|
683
|
+
endpoint: '/uploadposts/users',
|
|
684
|
+
method: 'GET',
|
|
685
|
+
isUploadOperation: false,
|
|
686
|
+
waitForCompletion: false,
|
|
687
|
+
};
|
|
688
|
+
case 'createUser': {
|
|
689
|
+
const username = ctx.node.getNodeParameter('newUser', ctx.itemIndex);
|
|
690
|
+
return {
|
|
691
|
+
endpoint: '/uploadposts/users',
|
|
692
|
+
method: 'POST',
|
|
693
|
+
body: { username },
|
|
694
|
+
isUploadOperation: false,
|
|
695
|
+
waitForCompletion: false,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
case 'deleteUser': {
|
|
699
|
+
const username = ctx.node.getNodeParameter('deleteUserId', ctx.itemIndex);
|
|
700
|
+
return {
|
|
701
|
+
endpoint: '/uploadposts/users',
|
|
702
|
+
method: 'DELETE',
|
|
703
|
+
body: { username },
|
|
704
|
+
isUploadOperation: false,
|
|
705
|
+
waitForCompletion: false,
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
case 'generateJwt': {
|
|
709
|
+
const username = getUserForOperation(ctx, true);
|
|
710
|
+
const redirectUrl = ctx.node.getNodeParameter('redirectUrl', ctx.itemIndex, '');
|
|
711
|
+
const logoImage = ctx.node.getNodeParameter('logoImage', ctx.itemIndex, '');
|
|
712
|
+
const redirectButtonText = ctx.node.getNodeParameter('redirectButtonText', ctx.itemIndex, '');
|
|
713
|
+
const platforms = ctx.node.getNodeParameter('jwtPlatforms', ctx.itemIndex, []);
|
|
714
|
+
const body = { username };
|
|
715
|
+
if (redirectUrl)
|
|
716
|
+
body.redirect_url = redirectUrl;
|
|
717
|
+
if (logoImage)
|
|
718
|
+
body.logo_image = logoImage;
|
|
719
|
+
if (redirectButtonText)
|
|
720
|
+
body.redirect_button_text = redirectButtonText;
|
|
721
|
+
if (Array.isArray(platforms) && platforms.length > 0)
|
|
722
|
+
body.platforms = platforms;
|
|
723
|
+
return {
|
|
724
|
+
endpoint: '/uploadposts/users/generate-jwt',
|
|
725
|
+
method: 'POST',
|
|
726
|
+
body,
|
|
727
|
+
isUploadOperation: false,
|
|
728
|
+
waitForCompletion: false,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
case 'validateJwt': {
|
|
732
|
+
const jwt = ctx.node.getNodeParameter('jwtToken', ctx.itemIndex);
|
|
733
|
+
return {
|
|
734
|
+
endpoint: '/uploadposts/users/validate-jwt',
|
|
735
|
+
method: 'POST',
|
|
736
|
+
body: { jwt },
|
|
737
|
+
headers: { Authorization: `Bearer ${jwt}` },
|
|
738
|
+
isUploadOperation: false,
|
|
739
|
+
waitForCompletion: false,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
default:
|
|
743
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported user operation: ${ctx.operation}`, {
|
|
744
|
+
itemIndex: ctx.itemIndex,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
const buildRequestConfig = async (ctx) => {
|
|
749
|
+
if (ctx.operation === 'uploadPhotos') {
|
|
750
|
+
return buildUploadPhotosRequest(ctx);
|
|
751
|
+
}
|
|
752
|
+
if (ctx.operation === 'uploadVideo') {
|
|
753
|
+
return buildUploadVideoRequest(ctx);
|
|
754
|
+
}
|
|
755
|
+
if (ctx.operation === 'uploadText') {
|
|
756
|
+
return buildUploadTextRequest(ctx);
|
|
757
|
+
}
|
|
758
|
+
const resource = ctx.node.getNodeParameter('resource', ctx.itemIndex);
|
|
759
|
+
if (resource === 'monitoring') {
|
|
760
|
+
return buildMonitoringRequest(ctx);
|
|
761
|
+
}
|
|
762
|
+
if (resource === 'users') {
|
|
763
|
+
return buildUserRequest(ctx);
|
|
764
|
+
}
|
|
765
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported operation: ${ctx.operation}`, {
|
|
766
|
+
itemIndex: ctx.itemIndex,
|
|
767
|
+
});
|
|
768
|
+
};
|
|
769
|
+
const buildNativeFormData = (payload, node) => {
|
|
770
|
+
if (typeof FormData === 'undefined') {
|
|
771
|
+
throw new n8n_workflow_1.NodeOperationError(node.getNode(), 'FormData is not supported in this runtime environment');
|
|
772
|
+
}
|
|
773
|
+
const form = new FormData();
|
|
774
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
775
|
+
if (Array.isArray(value)) {
|
|
776
|
+
value.forEach(item => appendValue(form, key, item));
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
appendValue(form, key, value);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
return form;
|
|
783
|
+
};
|
|
784
|
+
const appendValue = (form, key, value) => {
|
|
785
|
+
if (isBinaryFormField(value)) {
|
|
786
|
+
appendBinaryValue(form, key, value);
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
form.append(key, value);
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
const appendBinaryValue = (form, key, field) => {
|
|
793
|
+
var _a, _b;
|
|
794
|
+
const { value, options } = field;
|
|
795
|
+
if (typeof value === 'string') {
|
|
796
|
+
form.append(key, value);
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
const filename = (_a = options === null || options === void 0 ? void 0 : options.filename) !== null && _a !== void 0 ? _a : 'upload.bin';
|
|
800
|
+
const contentType = (_b = options === null || options === void 0 ? void 0 : options.contentType) !== null && _b !== void 0 ? _b : 'application/octet-stream';
|
|
801
|
+
if (typeof Blob !== 'undefined') {
|
|
802
|
+
const blob = new Blob([value], { type: contentType });
|
|
803
|
+
form.append(key, blob, filename);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
form.append(key, value, { filename, contentType });
|
|
807
|
+
};
|
|
808
|
+
const pollUploadStatus = async (node, requestId, pollInterval, pollTimeout) => {
|
|
809
|
+
const start = Date.now();
|
|
810
|
+
let finalData = { success: false, message: 'Polling timed out', request_id: requestId };
|
|
811
|
+
while (true) {
|
|
812
|
+
await (0, n8n_workflow_1.sleep)(Math.max(1, pollInterval) * 1000);
|
|
813
|
+
if (Date.now() - start > Math.max(5, pollTimeout) * 1000) {
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
const statusOptions = {
|
|
817
|
+
url: `${API_BASE_URL}/uploadposts/status`,
|
|
818
|
+
method: 'GET',
|
|
819
|
+
qs: { request_id: requestId },
|
|
820
|
+
json: true,
|
|
821
|
+
};
|
|
822
|
+
const statusData = await node.helpers.httpRequestWithAuthentication.call(node, 'uploadPostApi', statusOptions);
|
|
823
|
+
finalData = statusData;
|
|
824
|
+
const statusValue = (statusData && statusData.status);
|
|
825
|
+
if ((statusData && statusData.success === true) ||
|
|
826
|
+
(statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return finalData;
|
|
831
|
+
};
|
|
9
832
|
class UploadPost {
|
|
10
833
|
constructor() {
|
|
11
834
|
this.description = {
|
|
@@ -1532,20 +2355,17 @@ class UploadPost {
|
|
|
1532
2355
|
},
|
|
1533
2356
|
async getFacebookPages() {
|
|
1534
2357
|
try {
|
|
1535
|
-
const credentials = await this.getCredentials('uploadPostApi');
|
|
1536
|
-
const apiKey = credentials.apiKey;
|
|
1537
2358
|
const profile = this.getCurrentNodeParameter('user') || '';
|
|
1538
2359
|
const qs = {};
|
|
1539
2360
|
if (profile)
|
|
1540
2361
|
qs.profile = profile;
|
|
1541
2362
|
const options = {
|
|
1542
|
-
|
|
2363
|
+
url: 'https://api.upload-post.com/api/uploadposts/facebook/pages',
|
|
1543
2364
|
method: 'GET',
|
|
1544
|
-
headers: { Authorization: `ApiKey ${apiKey}` },
|
|
1545
2365
|
qs,
|
|
1546
2366
|
json: true,
|
|
1547
2367
|
};
|
|
1548
|
-
const resp = await this.helpers.
|
|
2368
|
+
const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
|
|
1549
2369
|
const pages = (resp && (resp.pages || resp.data || []));
|
|
1550
2370
|
const pageOptions = (pages || []).map(p => ({ name: p.name ? `${p.name} (${p.id})` : p.id, value: p.id }));
|
|
1551
2371
|
return [
|
|
@@ -1561,20 +2381,17 @@ class UploadPost {
|
|
|
1561
2381
|
},
|
|
1562
2382
|
async getLinkedinPages() {
|
|
1563
2383
|
try {
|
|
1564
|
-
const credentials = await this.getCredentials('uploadPostApi');
|
|
1565
|
-
const apiKey = credentials.apiKey;
|
|
1566
2384
|
const profile = this.getCurrentNodeParameter('user') || '';
|
|
1567
2385
|
const qs = {};
|
|
1568
2386
|
if (profile)
|
|
1569
2387
|
qs.profile = profile;
|
|
1570
2388
|
const options = {
|
|
1571
|
-
|
|
2389
|
+
url: 'https://api.upload-post.com/api/uploadposts/linkedin/pages',
|
|
1572
2390
|
method: 'GET',
|
|
1573
|
-
headers: { Authorization: `ApiKey ${apiKey}` },
|
|
1574
2391
|
qs,
|
|
1575
2392
|
json: true,
|
|
1576
2393
|
};
|
|
1577
|
-
const resp = await this.helpers.
|
|
2394
|
+
const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
|
|
1578
2395
|
const pages = (resp && (resp.pages || resp.data || []));
|
|
1579
2396
|
const pageOptions = (pages || []).map(p => ({ name: p.name ? `${p.name} (${p.id})` : p.id, value: p.id }));
|
|
1580
2397
|
return [
|
|
@@ -1592,20 +2409,17 @@ class UploadPost {
|
|
|
1592
2409
|
},
|
|
1593
2410
|
async getPinterestBoards() {
|
|
1594
2411
|
try {
|
|
1595
|
-
const credentials = await this.getCredentials('uploadPostApi');
|
|
1596
|
-
const apiKey = credentials.apiKey;
|
|
1597
2412
|
const profile = this.getCurrentNodeParameter('user') || '';
|
|
1598
2413
|
const qs = {};
|
|
1599
2414
|
if (profile)
|
|
1600
2415
|
qs.profile = profile;
|
|
1601
2416
|
const options = {
|
|
1602
|
-
|
|
2417
|
+
url: 'https://api.upload-post.com/api/uploadposts/pinterest/boards',
|
|
1603
2418
|
method: 'GET',
|
|
1604
|
-
headers: { Authorization: `ApiKey ${apiKey}` },
|
|
1605
2419
|
qs,
|
|
1606
2420
|
json: true,
|
|
1607
2421
|
};
|
|
1608
|
-
const resp = await this.helpers.
|
|
2422
|
+
const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
|
|
1609
2423
|
const boards = (resp && (resp.boards || resp.data || []));
|
|
1610
2424
|
const boardOptions = (boards || []).map(b => ({ name: b.name ? `${b.name} (${b.id})` : b.id, value: b.id }));
|
|
1611
2425
|
return [
|
|
@@ -1621,15 +2435,12 @@ class UploadPost {
|
|
|
1621
2435
|
},
|
|
1622
2436
|
async getUserProfiles() {
|
|
1623
2437
|
try {
|
|
1624
|
-
const credentials = await this.getCredentials('uploadPostApi');
|
|
1625
|
-
const apiKey = credentials.apiKey;
|
|
1626
2438
|
const options = {
|
|
1627
|
-
|
|
2439
|
+
url: 'https://api.upload-post.com/api/uploadposts/users',
|
|
1628
2440
|
method: 'GET',
|
|
1629
|
-
headers: { Authorization: `ApiKey ${apiKey}` },
|
|
1630
2441
|
json: true,
|
|
1631
2442
|
};
|
|
1632
|
-
const resp = await this.helpers.
|
|
2443
|
+
const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
|
|
1633
2444
|
const profiles = (resp && resp.profiles);
|
|
1634
2445
|
const profileOptions = (profiles || []).map(profile => {
|
|
1635
2446
|
const connectedPlatforms = Object.keys(profile.social_accounts || {})
|
|
@@ -1658,742 +2469,55 @@ class UploadPost {
|
|
|
1658
2469
|
};
|
|
1659
2470
|
}
|
|
1660
2471
|
async execute() {
|
|
1661
|
-
var _a, _b
|
|
2472
|
+
var _a, _b;
|
|
1662
2473
|
const items = this.getInputData();
|
|
1663
2474
|
const returnData = [];
|
|
1664
|
-
for (let
|
|
1665
|
-
const operation = this.getNodeParameter('operation',
|
|
1666
|
-
const
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
const
|
|
1673
|
-
|
|
1674
|
-
:
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
const formData = {};
|
|
1680
|
-
const qs = {};
|
|
1681
|
-
const body = {};
|
|
1682
|
-
if (isUploadOperation) {
|
|
1683
|
-
formData.user = user;
|
|
1684
|
-
formData.title = title;
|
|
1685
|
-
const scheduledDate = this.getNodeParameter('scheduledDate', i);
|
|
1686
|
-
if (scheduledDate) {
|
|
1687
|
-
let normalizedDate = scheduledDate;
|
|
1688
|
-
const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
|
|
1689
|
-
if (!hasTimezone) {
|
|
1690
|
-
normalizedDate = `${normalizedDate}Z`;
|
|
1691
|
-
}
|
|
1692
|
-
formData.scheduled_date = normalizedDate;
|
|
1693
|
-
}
|
|
1694
|
-
const uploadAsync = this.getNodeParameter('uploadAsync', i);
|
|
1695
|
-
if (uploadAsync !== undefined) {
|
|
1696
|
-
formData.async_upload = String(uploadAsync);
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
if (isUploadOperation) {
|
|
1700
|
-
try {
|
|
1701
|
-
if (platforms.includes('instagram')) {
|
|
1702
|
-
const instagramTitle = this.getNodeParameter('instagramTitle', i, '');
|
|
1703
|
-
if (instagramTitle)
|
|
1704
|
-
formData.instagram_title = instagramTitle;
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
catch { }
|
|
1708
|
-
try {
|
|
1709
|
-
if (platforms.includes('facebook')) {
|
|
1710
|
-
const facebookTitle = this.getNodeParameter('facebookTitle', i, '');
|
|
1711
|
-
if (facebookTitle)
|
|
1712
|
-
formData.facebook_title = facebookTitle;
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
catch { }
|
|
1716
|
-
try {
|
|
1717
|
-
if (platforms.includes('tiktok')) {
|
|
1718
|
-
const tiktokTitle = this.getNodeParameter('tiktokTitle', i, '');
|
|
1719
|
-
if (tiktokTitle)
|
|
1720
|
-
formData.tiktok_title = tiktokTitle;
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
catch { }
|
|
1724
|
-
try {
|
|
1725
|
-
if (platforms.includes('linkedin')) {
|
|
1726
|
-
const linkedinTitle = this.getNodeParameter('linkedinTitle', i, '');
|
|
1727
|
-
if (linkedinTitle)
|
|
1728
|
-
formData.linkedin_title = linkedinTitle;
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
catch { }
|
|
1732
|
-
try {
|
|
1733
|
-
if (platforms.includes('x')) {
|
|
1734
|
-
const xTitle = this.getNodeParameter('xTitle', i, '');
|
|
1735
|
-
if (xTitle)
|
|
1736
|
-
formData.x_title = xTitle;
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
catch { }
|
|
1740
|
-
try {
|
|
1741
|
-
if (platforms.includes('youtube')) {
|
|
1742
|
-
const youtubeTitle = this.getNodeParameter('youtubeTitle', i, '');
|
|
1743
|
-
if (youtubeTitle)
|
|
1744
|
-
formData.youtube_title = youtubeTitle;
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
catch { }
|
|
1748
|
-
try {
|
|
1749
|
-
if (platforms.includes('pinterest')) {
|
|
1750
|
-
const pinterestTitle = this.getNodeParameter('pinterestTitle', i, '');
|
|
1751
|
-
if (pinterestTitle)
|
|
1752
|
-
formData.pinterest_title = pinterestTitle;
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
catch { }
|
|
1756
|
-
}
|
|
1757
|
-
if (isUploadOperation) {
|
|
1758
|
-
const genericDescription = this.getNodeParameter('description', i, '');
|
|
1759
|
-
const descriptionPlatforms = new Set(['linkedin', 'facebook', 'youtube', 'pinterest', 'tiktok']);
|
|
1760
|
-
if (genericDescription && platforms.some(p => descriptionPlatforms.has(p))) {
|
|
1761
|
-
formData.description = genericDescription;
|
|
1762
|
-
}
|
|
1763
|
-
try {
|
|
1764
|
-
if (platforms.includes('linkedin')) {
|
|
1765
|
-
const linkedinDescription = this.getNodeParameter('linkedinDescription', i, '');
|
|
1766
|
-
if (linkedinDescription)
|
|
1767
|
-
formData.linkedin_description = linkedinDescription;
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
catch { }
|
|
1771
|
-
try {
|
|
1772
|
-
if (platforms.includes('youtube')) {
|
|
1773
|
-
const youtubeDescription = this.getNodeParameter('youtubeDescription', i, '');
|
|
1774
|
-
if (youtubeDescription)
|
|
1775
|
-
formData.youtube_description = youtubeDescription;
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
catch { }
|
|
1779
|
-
try {
|
|
1780
|
-
if (platforms.includes('facebook')) {
|
|
1781
|
-
const facebookDescription = this.getNodeParameter('facebookDescription', i, '');
|
|
1782
|
-
if (facebookDescription)
|
|
1783
|
-
formData.facebook_description = facebookDescription;
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
catch { }
|
|
1787
|
-
try {
|
|
1788
|
-
if (platforms.includes('tiktok')) {
|
|
1789
|
-
const tiktokDescription = this.getNodeParameter('tiktokDescription', i, '');
|
|
1790
|
-
if (tiktokDescription)
|
|
1791
|
-
formData.tiktok_description = tiktokDescription;
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
catch { }
|
|
1795
|
-
try {
|
|
1796
|
-
if (platforms.includes('pinterest')) {
|
|
1797
|
-
const pinterestDescription = this.getNodeParameter('pinterestDescription', i, '');
|
|
1798
|
-
if (pinterestDescription)
|
|
1799
|
-
formData.pinterest_description = pinterestDescription;
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
catch { }
|
|
1803
|
-
}
|
|
1804
|
-
switch (operation) {
|
|
1805
|
-
case 'uploadPhotos':
|
|
1806
|
-
endpoint = '/upload_photos';
|
|
1807
|
-
let photosInput = this.getNodeParameter('photos', i, []);
|
|
1808
|
-
let photosToProcess;
|
|
1809
|
-
if (typeof photosInput === 'string') {
|
|
1810
|
-
photosToProcess = photosInput.split(',').map(item => item.trim()).filter(item => item !== '');
|
|
1811
|
-
}
|
|
1812
|
-
else {
|
|
1813
|
-
photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim() !== '');
|
|
1814
|
-
}
|
|
1815
|
-
const allowedPhotoPlatforms = ['tiktok', 'instagram', 'linkedin', 'facebook', 'x', 'threads', 'pinterest'];
|
|
1816
|
-
platforms = platforms.filter(p => allowedPhotoPlatforms.includes(p));
|
|
1817
|
-
formData['platform[]'] = platforms;
|
|
1818
|
-
if (photosToProcess.length > 0) {
|
|
1819
|
-
const photoArray = [];
|
|
1820
|
-
for (const photoItem of photosToProcess) {
|
|
1821
|
-
if (typeof photoItem === 'string' && photoItem) {
|
|
1822
|
-
if (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://')) {
|
|
1823
|
-
photoArray.push(photoItem);
|
|
1824
|
-
}
|
|
1825
|
-
else {
|
|
1826
|
-
const binaryPropertyName = photoItem;
|
|
1827
|
-
try {
|
|
1828
|
-
const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
1829
|
-
const binaryFileDetails = items[i].binary[binaryPropertyName];
|
|
1830
|
-
photoArray.push({
|
|
1831
|
-
value: binaryBuffer,
|
|
1832
|
-
options: {
|
|
1833
|
-
filename: (_a = binaryFileDetails.fileName) !== null && _a !== void 0 ? _a : binaryPropertyName,
|
|
1834
|
-
contentType: binaryFileDetails.mimeType,
|
|
1835
|
-
},
|
|
1836
|
-
});
|
|
1837
|
-
}
|
|
1838
|
-
catch (error) {
|
|
1839
|
-
this.logger.warn(`[UploadPost Node] Could not find binary data for property '${binaryPropertyName}' in item ${i}. Error: ${error.message}`);
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
if (photoArray.length > 0) {
|
|
1845
|
-
formData['photos[]'] = photoArray;
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
break;
|
|
1849
|
-
case 'uploadVideo':
|
|
1850
|
-
endpoint = '/upload';
|
|
1851
|
-
const videoInput = this.getNodeParameter('video', i);
|
|
1852
|
-
const allowedVideoPlatforms = ['tiktok', 'instagram', 'linkedin', 'youtube', 'facebook', 'x', 'threads', 'pinterest'];
|
|
1853
|
-
platforms = platforms.filter(p => allowedVideoPlatforms.includes(p));
|
|
1854
|
-
formData['platform[]'] = platforms;
|
|
1855
|
-
if (videoInput) {
|
|
1856
|
-
if (videoInput.toLowerCase().startsWith('http://') || videoInput.toLowerCase().startsWith('https://')) {
|
|
1857
|
-
formData.video = videoInput;
|
|
1858
|
-
}
|
|
1859
|
-
else {
|
|
1860
|
-
const binaryPropertyName = videoInput;
|
|
1861
|
-
try {
|
|
1862
|
-
const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
1863
|
-
const binaryFileDetails = items[i].binary[binaryPropertyName];
|
|
1864
|
-
formData.video = {
|
|
1865
|
-
value: binaryBuffer,
|
|
1866
|
-
options: {
|
|
1867
|
-
filename: (_b = binaryFileDetails.fileName) !== null && _b !== void 0 ? _b : binaryPropertyName,
|
|
1868
|
-
contentType: binaryFileDetails.mimeType,
|
|
1869
|
-
},
|
|
1870
|
-
};
|
|
1871
|
-
}
|
|
1872
|
-
catch (error) {
|
|
1873
|
-
this.logger.warn(`[UploadPost Node] Could not find binary data for video property '${binaryPropertyName}' in item ${i}. Error: ${error.message}`);
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
break;
|
|
1878
|
-
case 'uploadText':
|
|
1879
|
-
endpoint = '/upload_text';
|
|
1880
|
-
const allowedTextPlatforms = ['x', 'linkedin', 'facebook', 'threads', 'reddit'];
|
|
1881
|
-
platforms = platforms.filter(p => allowedTextPlatforms.includes(p));
|
|
1882
|
-
formData['platform[]'] = platforms;
|
|
1883
|
-
break;
|
|
1884
|
-
case 'getStatus':
|
|
1885
|
-
method = 'GET';
|
|
1886
|
-
endpoint = '/uploadposts/status';
|
|
1887
|
-
qs.request_id = this.getNodeParameter('requestId', i);
|
|
1888
|
-
break;
|
|
1889
|
-
case 'getHistory':
|
|
1890
|
-
method = 'GET';
|
|
1891
|
-
endpoint = '/uploadposts/history';
|
|
1892
|
-
const historyPage = this.getNodeParameter('historyPage', i);
|
|
1893
|
-
qs.page = historyPage !== null && historyPage !== void 0 ? historyPage : 1;
|
|
1894
|
-
const historyLimit = this.getNodeParameter('historyLimit', i);
|
|
1895
|
-
qs.limit = historyLimit !== null && historyLimit !== void 0 ? historyLimit : 20;
|
|
1896
|
-
break;
|
|
1897
|
-
case 'getAnalytics':
|
|
1898
|
-
method = 'GET';
|
|
1899
|
-
{
|
|
1900
|
-
const analyticsPlatforms = this.getNodeParameter('analyticsPlatforms', i, []);
|
|
1901
|
-
const profileUsername = this.getNodeParameter('analyticsProfileUsername', i);
|
|
1902
|
-
endpoint = `/analytics/${encodeURIComponent(profileUsername)}`;
|
|
1903
|
-
if (Array.isArray(analyticsPlatforms) && analyticsPlatforms.length > 0) {
|
|
1904
|
-
qs.platforms = analyticsPlatforms.join(',');
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
break;
|
|
1908
|
-
case 'listScheduled':
|
|
1909
|
-
method = 'GET';
|
|
1910
|
-
endpoint = '/uploadposts/schedule';
|
|
1911
|
-
break;
|
|
1912
|
-
case 'cancelScheduled':
|
|
1913
|
-
method = 'DELETE';
|
|
1914
|
-
{
|
|
1915
|
-
const jobId = this.getNodeParameter('scheduleJobId', i);
|
|
1916
|
-
endpoint = `/uploadposts/schedule/${jobId}`;
|
|
1917
|
-
}
|
|
1918
|
-
break;
|
|
1919
|
-
case 'editScheduled':
|
|
1920
|
-
method = 'POST';
|
|
1921
|
-
{
|
|
1922
|
-
const jobId = this.getNodeParameter('scheduleJobId', i);
|
|
1923
|
-
endpoint = `/uploadposts/schedule/${jobId}`;
|
|
1924
|
-
const newScheduledDate = this.getNodeParameter('newScheduledDate', i, '');
|
|
1925
|
-
if (newScheduledDate) {
|
|
1926
|
-
let normalizedDate = newScheduledDate;
|
|
1927
|
-
const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
|
|
1928
|
-
if (!hasTimezone)
|
|
1929
|
-
normalizedDate = `${normalizedDate}Z`;
|
|
1930
|
-
body.scheduled_date = normalizedDate;
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
break;
|
|
1934
|
-
case 'listUsers':
|
|
1935
|
-
method = 'GET';
|
|
1936
|
-
endpoint = '/uploadposts/users';
|
|
1937
|
-
break;
|
|
1938
|
-
case 'createUser':
|
|
1939
|
-
method = 'POST';
|
|
1940
|
-
endpoint = '/uploadposts/users';
|
|
1941
|
-
body.username = this.getNodeParameter('newUser', i);
|
|
1942
|
-
break;
|
|
1943
|
-
case 'deleteUser':
|
|
1944
|
-
method = 'DELETE';
|
|
1945
|
-
endpoint = '/uploadposts/users';
|
|
1946
|
-
body.username = this.getNodeParameter('deleteUserId', i);
|
|
1947
|
-
break;
|
|
1948
|
-
case 'generateJwt':
|
|
1949
|
-
method = 'POST';
|
|
1950
|
-
endpoint = '/uploadposts/users/generate-jwt';
|
|
1951
|
-
body.username = user;
|
|
1952
|
-
const redirectUrl = this.getNodeParameter('redirectUrl', i, '');
|
|
1953
|
-
const logoImage = this.getNodeParameter('logoImage', i, '');
|
|
1954
|
-
const redirectButtonText = this.getNodeParameter('redirectButtonText', i, '');
|
|
1955
|
-
const jwtPlatforms = this.getNodeParameter('jwtPlatforms', i, []);
|
|
1956
|
-
if (redirectUrl)
|
|
1957
|
-
body.redirect_url = redirectUrl;
|
|
1958
|
-
if (logoImage)
|
|
1959
|
-
body.logo_image = logoImage;
|
|
1960
|
-
if (redirectButtonText)
|
|
1961
|
-
body.redirect_button_text = redirectButtonText;
|
|
1962
|
-
if (Array.isArray(jwtPlatforms) && jwtPlatforms.length > 0)
|
|
1963
|
-
body.platforms = jwtPlatforms;
|
|
1964
|
-
break;
|
|
1965
|
-
case 'validateJwt':
|
|
1966
|
-
method = 'POST';
|
|
1967
|
-
endpoint = '/uploadposts/users/validate-jwt';
|
|
1968
|
-
body.jwt = this.getNodeParameter('jwtToken', i);
|
|
1969
|
-
break;
|
|
1970
|
-
}
|
|
1971
|
-
if (isUploadOperation && platforms.includes('pinterest')) {
|
|
1972
|
-
const pinterestSelection = this.getNodeParameter('pinterestBoardId', i);
|
|
1973
|
-
const pinterestManual = pinterestSelection === MANUAL_PINTEREST_VALUE
|
|
1974
|
-
? this.getNodeParameter('pinterestBoardIdManual', i)
|
|
1975
|
-
: '';
|
|
1976
|
-
const pinterestBoardId = pinterestSelection === MANUAL_PINTEREST_VALUE ? pinterestManual : pinterestSelection;
|
|
1977
|
-
if (pinterestBoardId)
|
|
1978
|
-
formData.pinterest_board_id = pinterestBoardId;
|
|
1979
|
-
const pinterestLink = this.getNodeParameter('pinterestLink', i);
|
|
1980
|
-
if (pinterestLink)
|
|
1981
|
-
formData.pinterest_link = pinterestLink;
|
|
1982
|
-
if (operation === 'uploadVideo') {
|
|
1983
|
-
const pinterestCoverImageUrl = this.getNodeParameter('pinterestCoverImageUrl', i);
|
|
1984
|
-
const pinterestCoverImageContentType = this.getNodeParameter('pinterestCoverImageContentType', i);
|
|
1985
|
-
const pinterestCoverImageData = this.getNodeParameter('pinterestCoverImageData', i);
|
|
1986
|
-
const pinterestCoverImageKeyFrameTime = this.getNodeParameter('pinterestCoverImageKeyFrameTime', i);
|
|
1987
|
-
const pinterestLink = this.getNodeParameter('pinterestLink', i);
|
|
1988
|
-
if (pinterestCoverImageUrl) {
|
|
1989
|
-
formData.pinterest_cover_image_url = pinterestCoverImageUrl;
|
|
1990
|
-
}
|
|
1991
|
-
else {
|
|
1992
|
-
if (pinterestCoverImageContentType && pinterestCoverImageData) {
|
|
1993
|
-
formData.pinterest_cover_image_content_type = pinterestCoverImageContentType;
|
|
1994
|
-
formData.pinterest_cover_image_data = pinterestCoverImageData;
|
|
1995
|
-
}
|
|
1996
|
-
else if (pinterestCoverImageKeyFrameTime !== undefined) {
|
|
1997
|
-
formData.pinterest_cover_image_key_frame_time = pinterestCoverImageKeyFrameTime;
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
if (pinterestLink)
|
|
2001
|
-
formData.pinterest_link = pinterestLink;
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
if (isUploadOperation && platforms.includes('linkedin')) {
|
|
2005
|
-
const targetLinkedinSelection = this.getNodeParameter('targetLinkedinPageId', i);
|
|
2006
|
-
const targetLinkedinManual = targetLinkedinSelection === MANUAL_LINKEDIN_VALUE
|
|
2007
|
-
? this.getNodeParameter('targetLinkedinPageIdManual', i)
|
|
2008
|
-
: '';
|
|
2009
|
-
const targetLinkedinPageId = targetLinkedinSelection === MANUAL_LINKEDIN_VALUE ? targetLinkedinManual : targetLinkedinSelection;
|
|
2010
|
-
if (targetLinkedinPageId && targetLinkedinPageId !== 'me') {
|
|
2011
|
-
const match = targetLinkedinPageId.match(/(\d+)$/);
|
|
2012
|
-
if (match) {
|
|
2013
|
-
formData.target_linkedin_page_id = match[1];
|
|
2014
|
-
}
|
|
2015
|
-
else {
|
|
2016
|
-
formData.target_linkedin_page_id = targetLinkedinPageId;
|
|
2017
|
-
}
|
|
2018
|
-
}
|
|
2019
|
-
if (operation === 'uploadPhotos') {
|
|
2020
|
-
const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
|
|
2021
|
-
if (linkedinVisibility === 'PUBLIC') {
|
|
2022
|
-
formData.visibility = 'PUBLIC';
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
else if (operation === 'uploadVideo') {
|
|
2026
|
-
const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
|
|
2027
|
-
formData.visibility = linkedinVisibility;
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
if (isUploadOperation && platforms.includes('facebook')) {
|
|
2031
|
-
const facebookPageSelection = this.getNodeParameter('facebookPageId', i);
|
|
2032
|
-
const facebookPageManual = facebookPageSelection === MANUAL_FACEBOOK_VALUE
|
|
2033
|
-
? this.getNodeParameter('facebookPageIdManual', i)
|
|
2034
|
-
: '';
|
|
2035
|
-
const facebookPageId = facebookPageSelection === MANUAL_FACEBOOK_VALUE ? facebookPageManual : facebookPageSelection;
|
|
2036
|
-
formData.facebook_page_id = facebookPageId;
|
|
2037
|
-
if (operation === 'uploadVideo') {
|
|
2038
|
-
const facebookVideoState = this.getNodeParameter('facebookVideoState', i);
|
|
2039
|
-
if (facebookVideoState)
|
|
2040
|
-
formData.video_state = facebookVideoState;
|
|
2041
|
-
try {
|
|
2042
|
-
const facebookMediaType = this.getNodeParameter('facebookMediaType', i);
|
|
2043
|
-
if (facebookMediaType)
|
|
2044
|
-
formData.facebook_media_type = facebookMediaType;
|
|
2045
|
-
}
|
|
2046
|
-
catch { }
|
|
2047
|
-
}
|
|
2048
|
-
else if (operation === 'uploadText') {
|
|
2049
|
-
const facebookLink = this.getNodeParameter('facebookLink', i);
|
|
2050
|
-
if (facebookLink)
|
|
2051
|
-
formData.facebook_link_url = facebookLink;
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
if (isUploadOperation && platforms.includes('tiktok')) {
|
|
2055
|
-
if (operation === 'uploadPhotos') {
|
|
2056
|
-
const tiktokAutoAddMusic = this.getNodeParameter('tiktokAutoAddMusic', i);
|
|
2057
|
-
const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
|
|
2058
|
-
const brandContentToggle = this.getNodeParameter('brand_content_toggle', i);
|
|
2059
|
-
const brandOrganicToggle = this.getNodeParameter('brand_organic_toggle', i);
|
|
2060
|
-
const tiktokPhotoCoverIndex = this.getNodeParameter('tiktokPhotoCoverIndex', i);
|
|
2061
|
-
const tiktokPhotoDescription = this.getNodeParameter('tiktokPhotoDescription', i);
|
|
2062
|
-
if (tiktokAutoAddMusic !== undefined)
|
|
2063
|
-
formData.auto_add_music = String(tiktokAutoAddMusic);
|
|
2064
|
-
if (tiktokDisableComment !== undefined)
|
|
2065
|
-
formData.disable_comment = String(tiktokDisableComment);
|
|
2066
|
-
if (brandContentToggle !== undefined)
|
|
2067
|
-
formData.brand_content_toggle = String(brandContentToggle);
|
|
2068
|
-
if (brandOrganicToggle !== undefined)
|
|
2069
|
-
formData.brand_organic_toggle = String(brandOrganicToggle);
|
|
2070
|
-
if (tiktokPhotoCoverIndex !== undefined)
|
|
2071
|
-
formData.photo_cover_index = tiktokPhotoCoverIndex;
|
|
2072
|
-
if (tiktokPhotoDescription && formData.description === undefined)
|
|
2073
|
-
formData.description = tiktokPhotoDescription;
|
|
2074
|
-
}
|
|
2075
|
-
else if (operation === 'uploadVideo') {
|
|
2076
|
-
const tiktokPrivacyLevel = this.getNodeParameter('tiktokPrivacyLevel', i);
|
|
2077
|
-
const tiktokDisableDuet = this.getNodeParameter('tiktokDisableDuet', i);
|
|
2078
|
-
const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
|
|
2079
|
-
const tiktokDisableStitch = this.getNodeParameter('tiktokDisableStitch', i);
|
|
2080
|
-
const tiktokCoverTimestamp = this.getNodeParameter('tiktokCoverTimestamp', i);
|
|
2081
|
-
const brandContentToggle = this.getNodeParameter('brand_content_toggle', i);
|
|
2082
|
-
const brandOrganicToggle = this.getNodeParameter('brand_organic_toggle', i);
|
|
2083
|
-
const tiktokIsAigc = this.getNodeParameter('tiktokIsAigc', i);
|
|
2084
|
-
const tiktokPostMode = this.getNodeParameter('tiktokPostMode', i);
|
|
2085
|
-
if (tiktokPrivacyLevel)
|
|
2086
|
-
formData.privacy_level = tiktokPrivacyLevel;
|
|
2087
|
-
if (tiktokDisableDuet !== undefined)
|
|
2088
|
-
formData.disable_duet = String(tiktokDisableDuet);
|
|
2089
|
-
if (tiktokDisableComment !== undefined)
|
|
2090
|
-
formData.disable_comment = String(tiktokDisableComment);
|
|
2091
|
-
if (tiktokDisableStitch !== undefined)
|
|
2092
|
-
formData.disable_stitch = String(tiktokDisableStitch);
|
|
2093
|
-
if (tiktokCoverTimestamp !== undefined)
|
|
2094
|
-
formData.cover_timestamp = tiktokCoverTimestamp;
|
|
2095
|
-
if (brandContentToggle !== undefined)
|
|
2096
|
-
formData.brand_content_toggle = String(brandContentToggle);
|
|
2097
|
-
if (brandOrganicToggle !== undefined)
|
|
2098
|
-
formData.brand_organic_toggle = String(brandOrganicToggle);
|
|
2099
|
-
if (tiktokIsAigc !== undefined)
|
|
2100
|
-
formData.is_aigc = String(tiktokIsAigc);
|
|
2101
|
-
if (tiktokPostMode)
|
|
2102
|
-
formData.post_mode = tiktokPostMode;
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
if (isUploadOperation && platforms.includes('instagram')) {
|
|
2106
|
-
const instagramMediaTypeInput = this.getNodeParameter('instagramMediaType', i);
|
|
2107
|
-
let finalInstagramMediaType = instagramMediaTypeInput;
|
|
2108
|
-
if (operation === 'uploadPhotos') {
|
|
2109
|
-
if (!instagramMediaTypeInput || !['IMAGE', 'STORIES'].includes(instagramMediaTypeInput)) {
|
|
2110
|
-
finalInstagramMediaType = 'IMAGE';
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
else if (operation === 'uploadVideo') {
|
|
2114
|
-
if (!instagramMediaTypeInput || !['REELS', 'STORIES'].includes(instagramMediaTypeInput)) {
|
|
2115
|
-
finalInstagramMediaType = 'REELS';
|
|
2116
|
-
}
|
|
2117
|
-
}
|
|
2118
|
-
if (finalInstagramMediaType)
|
|
2119
|
-
formData.media_type = finalInstagramMediaType;
|
|
2120
|
-
if (operation === 'uploadVideo') {
|
|
2121
|
-
const instagramShareToFeed = this.getNodeParameter('instagramShareToFeed', i);
|
|
2122
|
-
const instagramCollaborators = this.getNodeParameter('instagramCollaborators', i);
|
|
2123
|
-
const instagramCoverUrl = this.getNodeParameter('instagramCoverUrl', i);
|
|
2124
|
-
const instagramAudioName = this.getNodeParameter('instagramAudioName', i);
|
|
2125
|
-
const instagramUserTags = this.getNodeParameter('instagramUserTags', i);
|
|
2126
|
-
const instagramLocationId = this.getNodeParameter('instagramLocationId', i);
|
|
2127
|
-
const instagramThumbOffset = this.getNodeParameter('instagramThumbOffset', i);
|
|
2128
|
-
if (instagramShareToFeed !== undefined)
|
|
2129
|
-
formData.share_to_feed = String(instagramShareToFeed);
|
|
2130
|
-
if (instagramCollaborators)
|
|
2131
|
-
formData.collaborators = instagramCollaborators;
|
|
2132
|
-
if (instagramCoverUrl)
|
|
2133
|
-
formData.cover_url = instagramCoverUrl;
|
|
2134
|
-
if (instagramAudioName)
|
|
2135
|
-
formData.audio_name = instagramAudioName;
|
|
2136
|
-
if (instagramUserTags)
|
|
2137
|
-
formData.user_tags = instagramUserTags;
|
|
2138
|
-
if (instagramLocationId)
|
|
2139
|
-
formData.location_id = instagramLocationId;
|
|
2140
|
-
if (instagramThumbOffset)
|
|
2141
|
-
formData.thumb_offset = instagramThumbOffset;
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
if (isUploadOperation && platforms.includes('youtube') && operation === 'uploadVideo') {
|
|
2145
|
-
const youtubeTagsRaw = this.getNodeParameter('youtubeTags', i);
|
|
2146
|
-
const youtubeCategoryId = this.getNodeParameter('youtubeCategoryId', i);
|
|
2147
|
-
const youtubePrivacyStatus = this.getNodeParameter('youtubePrivacyStatus', i);
|
|
2148
|
-
const youtubeEmbeddable = this.getNodeParameter('youtubeEmbeddable', i);
|
|
2149
|
-
const youtubeLicense = this.getNodeParameter('youtubeLicense', i);
|
|
2150
|
-
const youtubePublicStatsViewable = this.getNodeParameter('youtubePublicStatsViewable', i);
|
|
2151
|
-
const youtubeMadeForKids = this.getNodeParameter('youtubeMadeForKids', i);
|
|
2152
|
-
const youtubeThumbnail = this.getNodeParameter('youtubeThumbnail', i);
|
|
2153
|
-
if (youtubeTagsRaw)
|
|
2154
|
-
formData['tags[]'] = youtubeTagsRaw.split(',').map(tag => tag.trim());
|
|
2155
|
-
if (youtubeCategoryId)
|
|
2156
|
-
formData.categoryId = youtubeCategoryId;
|
|
2157
|
-
if (youtubePrivacyStatus)
|
|
2158
|
-
formData.privacyStatus = youtubePrivacyStatus;
|
|
2159
|
-
if (youtubeEmbeddable !== undefined)
|
|
2160
|
-
formData.embeddable = String(youtubeEmbeddable);
|
|
2161
|
-
if (youtubeLicense)
|
|
2162
|
-
formData.license = youtubeLicense;
|
|
2163
|
-
if (youtubePublicStatsViewable !== undefined)
|
|
2164
|
-
formData.publicStatsViewable = String(youtubePublicStatsViewable);
|
|
2165
|
-
if (youtubeMadeForKids !== undefined)
|
|
2166
|
-
formData.madeForKids = String(youtubeMadeForKids);
|
|
2167
|
-
if (youtubeThumbnail) {
|
|
2168
|
-
if (youtubeThumbnail.toLowerCase().startsWith('http://') || youtubeThumbnail.toLowerCase().startsWith('https://')) {
|
|
2169
|
-
formData.thumbnail_url = youtubeThumbnail;
|
|
2170
|
-
}
|
|
2171
|
-
else {
|
|
2172
|
-
const binaryPropertyName = youtubeThumbnail;
|
|
2173
|
-
try {
|
|
2174
|
-
const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
2175
|
-
const binaryFileDetails = items[i].binary[binaryPropertyName];
|
|
2176
|
-
formData.thumbnail = {
|
|
2177
|
-
value: binaryBuffer,
|
|
2178
|
-
options: {
|
|
2179
|
-
filename: (_c = binaryFileDetails.fileName) !== null && _c !== void 0 ? _c : binaryPropertyName,
|
|
2180
|
-
contentType: binaryFileDetails.mimeType,
|
|
2181
|
-
},
|
|
2182
|
-
};
|
|
2183
|
-
}
|
|
2184
|
-
catch (error) {
|
|
2185
|
-
this.logger.warn(`[UploadPost Node] Could not find binary data for YouTube thumbnail property '${binaryPropertyName}' in item ${i}. Error: ${error.message}`);
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
const youtubeSelfDeclaredMadeForKids = this.getNodeParameter('youtubeSelfDeclaredMadeForKids', i);
|
|
2190
|
-
const youtubeContainsSyntheticMedia = this.getNodeParameter('youtubeContainsSyntheticMedia', i);
|
|
2191
|
-
const youtubeDefaultLanguage = this.getNodeParameter('youtubeDefaultLanguage', i);
|
|
2192
|
-
const youtubeDefaultAudioLanguage = this.getNodeParameter('youtubeDefaultAudioLanguage', i);
|
|
2193
|
-
const youtubeAllowedCountries = this.getNodeParameter('youtubeAllowedCountries', i);
|
|
2194
|
-
const youtubeBlockedCountries = this.getNodeParameter('youtubeBlockedCountries', i);
|
|
2195
|
-
const youtubeHasPaidProductPlacement = this.getNodeParameter('youtubeHasPaidProductPlacement', i);
|
|
2196
|
-
const youtubeRecordingDate = this.getNodeParameter('youtubeRecordingDate', i);
|
|
2197
|
-
if (youtubeSelfDeclaredMadeForKids !== undefined)
|
|
2198
|
-
formData.selfDeclaredMadeForKids = String(youtubeSelfDeclaredMadeForKids);
|
|
2199
|
-
if (youtubeContainsSyntheticMedia !== undefined)
|
|
2200
|
-
formData.containsSyntheticMedia = String(youtubeContainsSyntheticMedia);
|
|
2201
|
-
if (youtubeDefaultLanguage)
|
|
2202
|
-
formData.defaultLanguage = youtubeDefaultLanguage;
|
|
2203
|
-
if (youtubeDefaultAudioLanguage)
|
|
2204
|
-
formData.defaultAudioLanguage = youtubeDefaultAudioLanguage;
|
|
2205
|
-
if (youtubeAllowedCountries)
|
|
2206
|
-
formData.allowedCountries = youtubeAllowedCountries;
|
|
2207
|
-
if (youtubeBlockedCountries)
|
|
2208
|
-
formData.blockedCountries = youtubeBlockedCountries;
|
|
2209
|
-
if (youtubeHasPaidProductPlacement !== undefined)
|
|
2210
|
-
formData.hasPaidProductPlacement = String(youtubeHasPaidProductPlacement);
|
|
2211
|
-
if (youtubeRecordingDate)
|
|
2212
|
-
formData.recordingDate = youtubeRecordingDate;
|
|
2213
|
-
}
|
|
2214
|
-
if (isUploadOperation && platforms.includes('x')) {
|
|
2215
|
-
const xQuoteTweetId = this.getNodeParameter('xQuoteTweetId', i, '');
|
|
2216
|
-
const xGeoPlaceId = this.getNodeParameter('xGeoPlaceId', i, '');
|
|
2217
|
-
const xForSuperFollowersOnly = this.getNodeParameter('xForSuperFollowersOnly', i, false);
|
|
2218
|
-
const xCommunityId = this.getNodeParameter('xCommunityId', i, '');
|
|
2219
|
-
const xShareWithFollowers = this.getNodeParameter('xShareWithFollowers', i, false);
|
|
2220
|
-
const xDirectMessageDeepLink = this.getNodeParameter('xDirectMessageDeepLink', i, '');
|
|
2221
|
-
const xCardUri = this.getNodeParameter('xCardUri', i, '');
|
|
2222
|
-
if (xQuoteTweetId)
|
|
2223
|
-
formData.quote_tweet_id = xQuoteTweetId;
|
|
2224
|
-
if (xGeoPlaceId)
|
|
2225
|
-
formData.geo_place_id = xGeoPlaceId;
|
|
2226
|
-
if (xForSuperFollowersOnly)
|
|
2227
|
-
formData.for_super_followers_only = String(xForSuperFollowersOnly);
|
|
2228
|
-
if (xCommunityId)
|
|
2229
|
-
formData.community_id = xCommunityId;
|
|
2230
|
-
if (xShareWithFollowers)
|
|
2231
|
-
formData.share_with_followers = String(xShareWithFollowers);
|
|
2232
|
-
if (xDirectMessageDeepLink)
|
|
2233
|
-
formData.direct_message_deep_link = xDirectMessageDeepLink;
|
|
2234
|
-
if (xCardUri)
|
|
2235
|
-
formData.card_uri = xCardUri;
|
|
2236
|
-
if (operation === 'uploadText') {
|
|
2237
|
-
const xPostUrlText = this.getNodeParameter('xPostUrlText', i);
|
|
2238
|
-
if (xPostUrlText)
|
|
2239
|
-
formData.post_url = xPostUrlText;
|
|
2240
|
-
const xReplySettingsText = this.getNodeParameter('xReplySettings', i);
|
|
2241
|
-
if (xReplySettingsText && xReplySettingsText !== 'everyone')
|
|
2242
|
-
formData.reply_settings = xReplySettingsText;
|
|
2243
|
-
const xPollDuration = this.getNodeParameter('xPollDuration', i, 1440);
|
|
2244
|
-
const xPollOptionsRaw = this.getNodeParameter('xPollOptions', i, '');
|
|
2245
|
-
const xPollReplySettings = this.getNodeParameter('xPollReplySettings', i, 'following');
|
|
2246
|
-
const xCardUri = this.getNodeParameter('xCardUri', i, '');
|
|
2247
|
-
const xQuoteTweetId = this.getNodeParameter('xQuoteTweetId', i, '');
|
|
2248
|
-
const xDirectMessageDeepLink = this.getNodeParameter('xDirectMessageDeepLink', i, '');
|
|
2249
|
-
const hasPollOptions = xPollOptionsRaw && xPollOptionsRaw.trim();
|
|
2250
|
-
const hasCardUri = xCardUri && xCardUri.trim();
|
|
2251
|
-
const hasQuoteTweetId = xQuoteTweetId && xQuoteTweetId.trim();
|
|
2252
|
-
const hasDirectMessageDeepLink = xDirectMessageDeepLink && xDirectMessageDeepLink.trim();
|
|
2253
|
-
if (hasPollOptions && (hasCardUri || hasQuoteTweetId || hasDirectMessageDeepLink)) {
|
|
2254
|
-
const conflictingFields = [];
|
|
2255
|
-
if (hasCardUri)
|
|
2256
|
-
conflictingFields.push('X Card URI');
|
|
2257
|
-
if (hasQuoteTweetId)
|
|
2258
|
-
conflictingFields.push('X Quote Tweet ID');
|
|
2259
|
-
if (hasDirectMessageDeepLink)
|
|
2260
|
-
conflictingFields.push('X Direct Message Deep Link');
|
|
2261
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options cannot be used with: ${conflictingFields.join(', ')}. These fields are mutually exclusive.`);
|
|
2262
|
-
}
|
|
2263
|
-
if (hasPollOptions) {
|
|
2264
|
-
const pollOptions = xPollOptionsRaw.split(',').map(opt => opt.trim()).filter(opt => opt.length > 0);
|
|
2265
|
-
if (pollOptions.length < 2 || pollOptions.length > 4) {
|
|
2266
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options must contain between 2 and 4 non-empty options. Found: ${pollOptions.length}`);
|
|
2267
|
-
}
|
|
2268
|
-
const invalidOptions = pollOptions.filter(opt => opt.length > 25);
|
|
2269
|
-
if (invalidOptions.length > 0) {
|
|
2270
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options cannot exceed 25 characters each. Invalid options: ${invalidOptions.join(', ')}`);
|
|
2271
|
-
}
|
|
2272
|
-
if (xPollDuration < 5 || xPollDuration > 10080) {
|
|
2273
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Duration must be between 5 and 10080 minutes (5 minutes to 7 days). Provided: ${xPollDuration}`);
|
|
2274
|
-
}
|
|
2275
|
-
formData['poll_options[]'] = pollOptions;
|
|
2276
|
-
formData.poll_duration = xPollDuration;
|
|
2277
|
-
formData.poll_reply_settings = xPollReplySettings;
|
|
2278
|
-
}
|
|
2279
|
-
try {
|
|
2280
|
-
const xLongTextAsPostText = this.getNodeParameter('xLongTextAsPost', i, false);
|
|
2281
|
-
if (xLongTextAsPostText)
|
|
2282
|
-
formData.x_long_text_as_post = String(xLongTextAsPostText);
|
|
2283
|
-
}
|
|
2284
|
-
catch { }
|
|
2285
|
-
delete formData.nullcast;
|
|
2286
|
-
delete formData.place_id;
|
|
2287
|
-
}
|
|
2288
|
-
else if (operation === 'uploadVideo' || operation === 'uploadPhotos') {
|
|
2289
|
-
const xTaggedUserIds = this.getNodeParameter('xTaggedUserIds', i);
|
|
2290
|
-
const xReplySettings = this.getNodeParameter('xReplySettings', i);
|
|
2291
|
-
const xNullcastVideo = this.getNodeParameter('xNullcastVideo', i);
|
|
2292
|
-
if (xTaggedUserIds)
|
|
2293
|
-
formData['tagged_user_ids[]'] = xTaggedUserIds.split(',').map(id => id.trim());
|
|
2294
|
-
if (xReplySettings && xReplySettings !== 'everyone')
|
|
2295
|
-
formData.reply_settings = xReplySettings;
|
|
2296
|
-
if (xNullcastVideo !== undefined)
|
|
2297
|
-
formData.nullcast = String(xNullcastVideo);
|
|
2298
|
-
if (operation === 'uploadVideo') {
|
|
2299
|
-
try {
|
|
2300
|
-
const xLongTextAsPost = this.getNodeParameter('xLongTextAsPost', i, false);
|
|
2301
|
-
if (xLongTextAsPost)
|
|
2302
|
-
formData.x_long_text_as_post = String(xLongTextAsPost);
|
|
2303
|
-
}
|
|
2304
|
-
catch { }
|
|
2305
|
-
}
|
|
2306
|
-
}
|
|
2475
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
2476
|
+
const operation = this.getNodeParameter('operation', itemIndex);
|
|
2477
|
+
const ctx = {
|
|
2478
|
+
node: this,
|
|
2479
|
+
items,
|
|
2480
|
+
itemIndex,
|
|
2481
|
+
operation,
|
|
2482
|
+
};
|
|
2483
|
+
const config = await buildRequestConfig(ctx);
|
|
2484
|
+
const requestOptions = {
|
|
2485
|
+
url: `${API_BASE_URL}${config.endpoint}`,
|
|
2486
|
+
method: config.method,
|
|
2487
|
+
};
|
|
2488
|
+
if (config.headers) {
|
|
2489
|
+
requestOptions.headers = config.headers;
|
|
2307
2490
|
}
|
|
2308
|
-
if (
|
|
2309
|
-
|
|
2310
|
-
const threadsTitle = this.getNodeParameter('threadsTitle', i, '');
|
|
2311
|
-
if (threadsTitle)
|
|
2312
|
-
formData.threads_title = threadsTitle;
|
|
2313
|
-
const threadsLongTextAsPost = this.getNodeParameter('threadsLongTextAsPost', i, false);
|
|
2314
|
-
if (threadsLongTextAsPost)
|
|
2315
|
-
formData.threads_long_text_as_post = String(threadsLongTextAsPost);
|
|
2316
|
-
}
|
|
2491
|
+
if (config.qs) {
|
|
2492
|
+
requestOptions.qs = config.qs;
|
|
2317
2493
|
}
|
|
2318
|
-
if (
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
if (redditFlairId)
|
|
2324
|
-
formData.flair_id = redditFlairId;
|
|
2325
|
-
}
|
|
2494
|
+
if (config.formData) {
|
|
2495
|
+
const multipartPayload = buildMultipartPayload(config.formData);
|
|
2496
|
+
const nativeFormData = buildNativeFormData(multipartPayload, this);
|
|
2497
|
+
requestOptions.body = nativeFormData;
|
|
2498
|
+
requestOptions.json = false;
|
|
2326
2499
|
}
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
uri: `https://api.upload-post.com/api${endpoint}`,
|
|
2331
|
-
method,
|
|
2332
|
-
headers: {},
|
|
2333
|
-
json: true,
|
|
2334
|
-
};
|
|
2335
|
-
if (operation === 'validateJwt') {
|
|
2336
|
-
const jwt = this.getNodeParameter('jwtToken', i);
|
|
2337
|
-
options.headers['Authorization'] = `Bearer ${jwt}`;
|
|
2500
|
+
else if (config.body) {
|
|
2501
|
+
requestOptions.body = config.body;
|
|
2502
|
+
requestOptions.json = true;
|
|
2338
2503
|
}
|
|
2339
2504
|
else {
|
|
2340
|
-
|
|
2341
|
-
}
|
|
2342
|
-
if (method === 'POST') {
|
|
2343
|
-
if (operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText') {
|
|
2344
|
-
options.formData = formData;
|
|
2345
|
-
}
|
|
2346
|
-
else {
|
|
2347
|
-
options.body = body;
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
else if (method === 'GET' || method === 'DELETE') {
|
|
2351
|
-
if (operation === 'deleteUser') {
|
|
2352
|
-
options.body = body;
|
|
2353
|
-
}
|
|
2354
|
-
else {
|
|
2355
|
-
options.qs = qs;
|
|
2356
|
-
}
|
|
2505
|
+
requestOptions.json = true;
|
|
2357
2506
|
}
|
|
2358
|
-
this.
|
|
2359
|
-
const responseData =
|
|
2360
|
-
const shouldConsiderPolling = operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText';
|
|
2361
|
-
const waitForCompletion = shouldConsiderPolling ? this.getNodeParameter('waitForCompletion', i, false) : false;
|
|
2507
|
+
const rawResponse = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', requestOptions);
|
|
2508
|
+
const responseData = parseJsonIfNeeded(rawResponse);
|
|
2362
2509
|
let finalData = responseData;
|
|
2363
|
-
if (
|
|
2364
|
-
const
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
const start = Date.now();
|
|
2370
|
-
while (true) {
|
|
2371
|
-
await (0, n8n_workflow_1.sleep)(Math.max(1, pollIntervalSec) * 1000);
|
|
2372
|
-
if (Date.now() - start > Math.max(5, pollTimeoutSec) * 1000) {
|
|
2373
|
-
finalData = { success: false, message: 'Polling timed out', request_id: requestId };
|
|
2374
|
-
break;
|
|
2375
|
-
}
|
|
2376
|
-
const statusOptions = {
|
|
2377
|
-
uri: `https://api.upload-post.com/api/uploadposts/status`,
|
|
2378
|
-
method: 'GET',
|
|
2379
|
-
headers: { 'Authorization': `ApiKey ${apiKey}` },
|
|
2380
|
-
qs: { request_id: requestId },
|
|
2381
|
-
json: true,
|
|
2382
|
-
};
|
|
2383
|
-
const statusData = await this.helpers.request(statusOptions);
|
|
2384
|
-
finalData = statusData;
|
|
2385
|
-
const statusValue = (statusData && statusData.status);
|
|
2386
|
-
if (statusData.success === true || (statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
|
|
2387
|
-
break;
|
|
2388
|
-
}
|
|
2389
|
-
}
|
|
2510
|
+
if (config.isUploadOperation && config.waitForCompletion) {
|
|
2511
|
+
const requestId = responseData && responseData.request_id
|
|
2512
|
+
? responseData.request_id
|
|
2513
|
+
: undefined;
|
|
2514
|
+
if (requestId) {
|
|
2515
|
+
finalData = await pollUploadStatus(this, requestId, (_a = config.pollInterval) !== null && _a !== void 0 ? _a : 10, (_b = config.pollTimeout) !== null && _b !== void 0 ? _b : 600);
|
|
2390
2516
|
}
|
|
2391
2517
|
}
|
|
2392
2518
|
returnData.push({
|
|
2393
2519
|
json: finalData,
|
|
2394
|
-
pairedItem: {
|
|
2395
|
-
item: i,
|
|
2396
|
-
},
|
|
2520
|
+
pairedItem: { item: itemIndex },
|
|
2397
2521
|
});
|
|
2398
2522
|
}
|
|
2399
2523
|
return [returnData];
|