n8n-nodes-upload-post 0.1.22 → 0.1.31
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.
|
@@ -1,15 +1,835 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.UploadPost = void 0;
|
|
7
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
8
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
9
5
|
const MANUAL_USER_VALUE = '__manual_user__';
|
|
10
6
|
const MANUAL_FACEBOOK_VALUE = '__manual_facebook__';
|
|
11
7
|
const MANUAL_LINKEDIN_VALUE = '__manual_linkedin__';
|
|
12
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: ['bluesky', 'facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x'],
|
|
90
|
+
uploadVideo: ['bluesky', 'facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x', 'youtube'],
|
|
91
|
+
uploadText: ['bluesky', 'facebook', 'linkedin', 'reddit', 'threads', 'x'],
|
|
92
|
+
};
|
|
93
|
+
const DESCRIPTION_ENABLED_PLATFORMS = new Set(['linkedin', 'facebook', 'youtube', 'pinterest', 'tiktok']);
|
|
94
|
+
const TITLE_OVERRIDES = [
|
|
95
|
+
{ platform: 'bluesky', param: 'blueskyTitle', field: 'bluesky_title' },
|
|
96
|
+
{ platform: 'instagram', param: 'instagramTitle', field: 'instagram_title' },
|
|
97
|
+
{ platform: 'facebook', param: 'facebookTitle', field: 'facebook_title' },
|
|
98
|
+
{ platform: 'tiktok', param: 'tiktokTitle', field: 'tiktok_title' },
|
|
99
|
+
{ platform: 'linkedin', param: 'linkedinTitle', field: 'linkedin_title' },
|
|
100
|
+
{ platform: 'x', param: 'xTitle', field: 'x_title' },
|
|
101
|
+
{ platform: 'youtube', param: 'youtubeTitle', field: 'youtube_title', operations: ['uploadVideo'] },
|
|
102
|
+
{ platform: 'pinterest', param: 'pinterestTitle', field: 'pinterest_title' },
|
|
103
|
+
{ platform: 'threads', param: 'threadsTitle', field: 'threads_title', operations: ['uploadText'] },
|
|
104
|
+
];
|
|
105
|
+
const DESCRIPTION_OVERRIDES = [
|
|
106
|
+
{ platform: 'linkedin', param: 'linkedinDescription', field: 'linkedin_description', operations: ['uploadPhotos', 'uploadVideo'] },
|
|
107
|
+
{ platform: 'youtube', param: 'youtubeDescription', field: 'youtube_description', operations: ['uploadVideo'] },
|
|
108
|
+
{ platform: 'facebook', param: 'facebookDescription', field: 'facebook_description', operations: ['uploadPhotos', 'uploadVideo'] },
|
|
109
|
+
{ platform: 'tiktok', param: 'tiktokDescription', field: 'tiktok_description', operations: ['uploadPhotos'] },
|
|
110
|
+
{ platform: 'pinterest', param: 'pinterestDescription', field: 'pinterest_description', operations: ['uploadPhotos', 'uploadVideo'] },
|
|
111
|
+
];
|
|
112
|
+
const getFilteredPlatforms = (operation, platforms) => {
|
|
113
|
+
var _a;
|
|
114
|
+
const allowed = (_a = PLATFORM_SUPPORT[operation]) !== null && _a !== void 0 ? _a : [];
|
|
115
|
+
return platforms.filter(platform => allowed.includes(platform));
|
|
116
|
+
};
|
|
117
|
+
const applyTitleOverrides = (ctx, operation, platforms, formData) => {
|
|
118
|
+
for (const override of TITLE_OVERRIDES) {
|
|
119
|
+
if (!platforms.includes(override.platform))
|
|
120
|
+
continue;
|
|
121
|
+
if (override.operations && !override.operations.includes(operation))
|
|
122
|
+
continue;
|
|
123
|
+
const value = ctx.node.getNodeParameter(override.param, ctx.itemIndex, '');
|
|
124
|
+
if (value) {
|
|
125
|
+
formData[override.field] = value;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const applyDescriptionOverrides = (ctx, operation, platforms, formData) => {
|
|
130
|
+
const genericDescription = ctx.node.getNodeParameter('description', ctx.itemIndex, '');
|
|
131
|
+
if (genericDescription &&
|
|
132
|
+
(operation === 'uploadPhotos' || operation === 'uploadVideo') &&
|
|
133
|
+
platforms.some(platform => DESCRIPTION_ENABLED_PLATFORMS.has(platform))) {
|
|
134
|
+
formData.description = genericDescription;
|
|
135
|
+
}
|
|
136
|
+
for (const override of DESCRIPTION_OVERRIDES) {
|
|
137
|
+
if (!platforms.includes(override.platform))
|
|
138
|
+
continue;
|
|
139
|
+
if (override.operations && !override.operations.includes(operation))
|
|
140
|
+
continue;
|
|
141
|
+
const value = ctx.node.getNodeParameter(override.param, ctx.itemIndex, '');
|
|
142
|
+
if (value) {
|
|
143
|
+
formData[override.field] = value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const getUserForOperation = (ctx, needsUser) => {
|
|
148
|
+
if (!needsUser) {
|
|
149
|
+
return '';
|
|
150
|
+
}
|
|
151
|
+
const selection = ctx.node.getNodeParameter('user', ctx.itemIndex);
|
|
152
|
+
if (selection === MANUAL_USER_VALUE) {
|
|
153
|
+
return ctx.node.getNodeParameter('userManual', ctx.itemIndex);
|
|
154
|
+
}
|
|
155
|
+
return selection;
|
|
156
|
+
};
|
|
157
|
+
const prepareUploadBase = (ctx, operation) => {
|
|
158
|
+
const formData = {};
|
|
159
|
+
const user = getUserForOperation(ctx, true);
|
|
160
|
+
const title = ctx.node.getNodeParameter('title', ctx.itemIndex);
|
|
161
|
+
formData.user = user;
|
|
162
|
+
formData.title = title;
|
|
163
|
+
const scheduledDate = normalizeDateInput(ctx.node.getNodeParameter('scheduledDate', ctx.itemIndex, ''));
|
|
164
|
+
if (scheduledDate) {
|
|
165
|
+
formData.scheduled_date = scheduledDate;
|
|
166
|
+
}
|
|
167
|
+
const uploadAsync = ctx.node.getNodeParameter('uploadAsync', ctx.itemIndex);
|
|
168
|
+
if (uploadAsync !== undefined) {
|
|
169
|
+
formData.async_upload = String(uploadAsync);
|
|
170
|
+
}
|
|
171
|
+
const rawPlatforms = ctx.node.getNodeParameter('platform', ctx.itemIndex);
|
|
172
|
+
const platforms = getFilteredPlatforms(operation, Array.isArray(rawPlatforms) ? rawPlatforms : []);
|
|
173
|
+
formData['platform[]'] = platforms;
|
|
174
|
+
applyTitleOverrides(ctx, operation, platforms, formData);
|
|
175
|
+
applyDescriptionOverrides(ctx, operation, platforms, formData);
|
|
176
|
+
const waitForCompletion = ctx.node.getNodeParameter('waitForCompletion', ctx.itemIndex, false);
|
|
177
|
+
const pollInterval = ctx.node.getNodeParameter('pollInterval', ctx.itemIndex, 10);
|
|
178
|
+
const pollTimeout = ctx.node.getNodeParameter('pollTimeout', ctx.itemIndex, 600);
|
|
179
|
+
return {
|
|
180
|
+
formData,
|
|
181
|
+
platforms,
|
|
182
|
+
waitForCompletion,
|
|
183
|
+
pollInterval,
|
|
184
|
+
pollTimeout,
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
const applyPinterestOptions = (ctx, operation, formData) => {
|
|
188
|
+
const selection = ctx.node.getNodeParameter('pinterestBoardId', ctx.itemIndex, '');
|
|
189
|
+
const pinterestBoardId = selection === MANUAL_PINTEREST_VALUE
|
|
190
|
+
? ctx.node.getNodeParameter('pinterestBoardIdManual', ctx.itemIndex)
|
|
191
|
+
: selection;
|
|
192
|
+
if (pinterestBoardId) {
|
|
193
|
+
formData.pinterest_board_id = pinterestBoardId;
|
|
194
|
+
}
|
|
195
|
+
const pinterestLink = ctx.node.getNodeParameter('pinterestLink', ctx.itemIndex, '');
|
|
196
|
+
if (pinterestLink) {
|
|
197
|
+
formData.pinterest_link = pinterestLink;
|
|
198
|
+
}
|
|
199
|
+
if (operation === 'uploadVideo') {
|
|
200
|
+
const pinterestCoverImageUrl = ctx.node.getNodeParameter('pinterestCoverImageUrl', ctx.itemIndex, '');
|
|
201
|
+
const pinterestCoverImageContentType = ctx.node.getNodeParameter('pinterestCoverImageContentType', ctx.itemIndex, '');
|
|
202
|
+
const pinterestCoverImageData = ctx.node.getNodeParameter('pinterestCoverImageData', ctx.itemIndex, '');
|
|
203
|
+
const pinterestCoverImageKeyFrameTime = ctx.node.getNodeParameter('pinterestCoverImageKeyFrameTime', ctx.itemIndex, 0);
|
|
204
|
+
if (pinterestCoverImageUrl) {
|
|
205
|
+
formData.pinterest_cover_image_url = pinterestCoverImageUrl;
|
|
206
|
+
}
|
|
207
|
+
else if (pinterestCoverImageContentType && pinterestCoverImageData) {
|
|
208
|
+
formData.pinterest_cover_image_content_type = pinterestCoverImageContentType;
|
|
209
|
+
formData.pinterest_cover_image_data = pinterestCoverImageData;
|
|
210
|
+
}
|
|
211
|
+
else if (pinterestCoverImageKeyFrameTime !== undefined) {
|
|
212
|
+
formData.pinterest_cover_image_key_frame_time = pinterestCoverImageKeyFrameTime;
|
|
213
|
+
}
|
|
214
|
+
if (pinterestLink) {
|
|
215
|
+
formData.pinterest_link = pinterestLink;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
const applyLinkedinOptions = (ctx, operation, formData) => {
|
|
220
|
+
const selection = ctx.node.getNodeParameter('targetLinkedinPageId', ctx.itemIndex, '');
|
|
221
|
+
const resolvedValue = selection === MANUAL_LINKEDIN_VALUE
|
|
222
|
+
? ctx.node.getNodeParameter('targetLinkedinPageIdManual', ctx.itemIndex)
|
|
223
|
+
: selection;
|
|
224
|
+
if (resolvedValue && resolvedValue !== 'me') {
|
|
225
|
+
const match = resolvedValue.match(/(\d+)$/);
|
|
226
|
+
formData.target_linkedin_page_id = match ? match[1] : resolvedValue;
|
|
227
|
+
}
|
|
228
|
+
if (operation === 'uploadPhotos') {
|
|
229
|
+
const linkedinVisibility = ctx.node.getNodeParameter('linkedinVisibility', ctx.itemIndex, 'PUBLIC');
|
|
230
|
+
if (linkedinVisibility === 'PUBLIC') {
|
|
231
|
+
formData.visibility = 'PUBLIC';
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else if (operation === 'uploadVideo') {
|
|
235
|
+
const linkedinVisibility = ctx.node.getNodeParameter('linkedinVisibility', ctx.itemIndex, 'PUBLIC');
|
|
236
|
+
formData.visibility = linkedinVisibility;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const applyFacebookOptions = (ctx, operation, formData) => {
|
|
240
|
+
const selection = ctx.node.getNodeParameter('facebookPageId', ctx.itemIndex);
|
|
241
|
+
const resolvedValue = selection === MANUAL_FACEBOOK_VALUE
|
|
242
|
+
? ctx.node.getNodeParameter('facebookPageIdManual', ctx.itemIndex)
|
|
243
|
+
: selection;
|
|
244
|
+
formData.facebook_page_id = resolvedValue;
|
|
245
|
+
if (operation === 'uploadVideo') {
|
|
246
|
+
const facebookVideoState = ctx.node.getNodeParameter('facebookVideoState', ctx.itemIndex, '');
|
|
247
|
+
const facebookMediaType = ctx.node.getNodeParameter('facebookMediaType', ctx.itemIndex, '');
|
|
248
|
+
if (facebookVideoState) {
|
|
249
|
+
formData.video_state = facebookVideoState;
|
|
250
|
+
}
|
|
251
|
+
if (facebookMediaType) {
|
|
252
|
+
formData.facebook_media_type = facebookMediaType;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else if (operation === 'uploadText') {
|
|
256
|
+
const facebookLink = ctx.node.getNodeParameter('facebookLink', ctx.itemIndex, '');
|
|
257
|
+
if (facebookLink) {
|
|
258
|
+
formData.facebook_link_url = facebookLink;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const applyTiktokOptions = (ctx, operation, formData) => {
|
|
263
|
+
if (operation === 'uploadPhotos') {
|
|
264
|
+
const autoAddMusic = ctx.node.getNodeParameter('tiktokAutoAddMusic', ctx.itemIndex, false);
|
|
265
|
+
const disableComment = ctx.node.getNodeParameter('tiktokDisableComment', ctx.itemIndex, false);
|
|
266
|
+
const brandContentToggle = ctx.node.getNodeParameter('brand_content_toggle', ctx.itemIndex, false);
|
|
267
|
+
const brandOrganicToggle = ctx.node.getNodeParameter('brand_organic_toggle', ctx.itemIndex, false);
|
|
268
|
+
const photoCoverIndex = ctx.node.getNodeParameter('tiktokPhotoCoverIndex', ctx.itemIndex, 0);
|
|
269
|
+
const photoDescription = ctx.node.getNodeParameter('tiktokPhotoDescription', ctx.itemIndex, '');
|
|
270
|
+
formData.auto_add_music = String(autoAddMusic);
|
|
271
|
+
formData.disable_comment = String(disableComment);
|
|
272
|
+
formData.brand_content_toggle = String(brandContentToggle);
|
|
273
|
+
formData.brand_organic_toggle = String(brandOrganicToggle);
|
|
274
|
+
formData.photo_cover_index = photoCoverIndex;
|
|
275
|
+
if (photoDescription && formData.description === undefined) {
|
|
276
|
+
formData.description = photoDescription;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else if (operation === 'uploadVideo') {
|
|
280
|
+
const privacyLevel = ctx.node.getNodeParameter('tiktokPrivacyLevel', ctx.itemIndex, '');
|
|
281
|
+
const disableDuet = ctx.node.getNodeParameter('tiktokDisableDuet', ctx.itemIndex, false);
|
|
282
|
+
const disableComment = ctx.node.getNodeParameter('tiktokDisableComment', ctx.itemIndex, false);
|
|
283
|
+
const disableStitch = ctx.node.getNodeParameter('tiktokDisableStitch', ctx.itemIndex, false);
|
|
284
|
+
const coverTimestamp = ctx.node.getNodeParameter('tiktokCoverTimestamp', ctx.itemIndex, 1000);
|
|
285
|
+
const brandContentToggle = ctx.node.getNodeParameter('brand_content_toggle', ctx.itemIndex, false);
|
|
286
|
+
const brandOrganicToggle = ctx.node.getNodeParameter('brand_organic_toggle', ctx.itemIndex, false);
|
|
287
|
+
const isAigc = ctx.node.getNodeParameter('tiktokIsAigc', ctx.itemIndex, false);
|
|
288
|
+
const postMode = ctx.node.getNodeParameter('tiktokPostMode', ctx.itemIndex, '');
|
|
289
|
+
if (privacyLevel)
|
|
290
|
+
formData.privacy_level = privacyLevel;
|
|
291
|
+
formData.disable_duet = String(disableDuet);
|
|
292
|
+
formData.disable_comment = String(disableComment);
|
|
293
|
+
formData.disable_stitch = String(disableStitch);
|
|
294
|
+
formData.cover_timestamp = coverTimestamp;
|
|
295
|
+
formData.brand_content_toggle = String(brandContentToggle);
|
|
296
|
+
formData.brand_organic_toggle = String(brandOrganicToggle);
|
|
297
|
+
formData.is_aigc = String(isAigc);
|
|
298
|
+
if (postMode)
|
|
299
|
+
formData.post_mode = postMode;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const applyInstagramOptions = (ctx, operation, formData) => {
|
|
303
|
+
const providedMediaType = ctx.node.getNodeParameter('instagramMediaType', ctx.itemIndex, '');
|
|
304
|
+
let finalMediaType = providedMediaType;
|
|
305
|
+
if (operation === 'uploadPhotos') {
|
|
306
|
+
if (!['IMAGE', 'STORIES'].includes(providedMediaType)) {
|
|
307
|
+
finalMediaType = 'IMAGE';
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (operation === 'uploadVideo') {
|
|
311
|
+
if (!['REELS', 'STORIES'].includes(providedMediaType)) {
|
|
312
|
+
finalMediaType = 'REELS';
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (finalMediaType) {
|
|
316
|
+
formData.media_type = finalMediaType;
|
|
317
|
+
}
|
|
318
|
+
if (operation === 'uploadVideo') {
|
|
319
|
+
const shareToFeed = ctx.node.getNodeParameter('instagramShareToFeed', ctx.itemIndex, true);
|
|
320
|
+
const collaborators = ctx.node.getNodeParameter('instagramCollaborators', ctx.itemIndex, '');
|
|
321
|
+
const coverUrl = ctx.node.getNodeParameter('instagramCoverUrl', ctx.itemIndex, '');
|
|
322
|
+
const audioName = ctx.node.getNodeParameter('instagramAudioName', ctx.itemIndex, '');
|
|
323
|
+
const userTags = ctx.node.getNodeParameter('instagramUserTags', ctx.itemIndex, '');
|
|
324
|
+
const locationId = ctx.node.getNodeParameter('instagramLocationId', ctx.itemIndex, '');
|
|
325
|
+
const thumbOffset = ctx.node.getNodeParameter('instagramThumbOffset', ctx.itemIndex, '');
|
|
326
|
+
formData.share_to_feed = String(shareToFeed);
|
|
327
|
+
if (collaborators)
|
|
328
|
+
formData.collaborators = collaborators;
|
|
329
|
+
if (coverUrl)
|
|
330
|
+
formData.cover_url = coverUrl;
|
|
331
|
+
if (audioName)
|
|
332
|
+
formData.audio_name = audioName;
|
|
333
|
+
if (userTags)
|
|
334
|
+
formData.user_tags = userTags;
|
|
335
|
+
if (locationId)
|
|
336
|
+
formData.location_id = locationId;
|
|
337
|
+
if (thumbOffset)
|
|
338
|
+
formData.thumb_offset = thumbOffset;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
const applyYoutubeOptions = async (ctx, formData) => {
|
|
342
|
+
const tagsRaw = ctx.node.getNodeParameter('youtubeTags', ctx.itemIndex, '');
|
|
343
|
+
const categoryId = ctx.node.getNodeParameter('youtubeCategoryId', ctx.itemIndex, '');
|
|
344
|
+
const privacyStatus = ctx.node.getNodeParameter('youtubePrivacyStatus', ctx.itemIndex, '');
|
|
345
|
+
const embeddable = ctx.node.getNodeParameter('youtubeEmbeddable', ctx.itemIndex, true);
|
|
346
|
+
const license = ctx.node.getNodeParameter('youtubeLicense', ctx.itemIndex, '');
|
|
347
|
+
const publicStatsViewable = ctx.node.getNodeParameter('youtubePublicStatsViewable', ctx.itemIndex, true);
|
|
348
|
+
const madeForKids = ctx.node.getNodeParameter('youtubeMadeForKids', ctx.itemIndex, false);
|
|
349
|
+
const thumbnailInput = ctx.node.getNodeParameter('youtubeThumbnail', ctx.itemIndex, '');
|
|
350
|
+
if (tagsRaw)
|
|
351
|
+
formData['tags[]'] = ensureArrayFromCommaSeparated(tagsRaw);
|
|
352
|
+
if (categoryId)
|
|
353
|
+
formData.categoryId = categoryId;
|
|
354
|
+
if (privacyStatus)
|
|
355
|
+
formData.privacyStatus = privacyStatus;
|
|
356
|
+
formData.embeddable = String(embeddable);
|
|
357
|
+
if (license)
|
|
358
|
+
formData.license = license;
|
|
359
|
+
formData.publicStatsViewable = String(publicStatsViewable);
|
|
360
|
+
formData.madeForKids = String(madeForKids);
|
|
361
|
+
if (thumbnailInput) {
|
|
362
|
+
if (thumbnailInput.toLowerCase().startsWith('http://') || thumbnailInput.toLowerCase().startsWith('https://')) {
|
|
363
|
+
formData.thumbnail_url = thumbnailInput;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
const thumbnailBinary = await getBinaryFieldFromItem(ctx, thumbnailInput, 'Binary data for YouTube thumbnail property');
|
|
367
|
+
formData.thumbnail = thumbnailBinary;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const selfDeclaredMadeForKids = ctx.node.getNodeParameter('youtubeSelfDeclaredMadeForKids', ctx.itemIndex, false);
|
|
371
|
+
const containsSyntheticMedia = ctx.node.getNodeParameter('youtubeContainsSyntheticMedia', ctx.itemIndex, false);
|
|
372
|
+
const defaultLanguage = ctx.node.getNodeParameter('youtubeDefaultLanguage', ctx.itemIndex, '');
|
|
373
|
+
const defaultAudioLanguage = ctx.node.getNodeParameter('youtubeDefaultAudioLanguage', ctx.itemIndex, '');
|
|
374
|
+
const allowedCountries = ctx.node.getNodeParameter('youtubeAllowedCountries', ctx.itemIndex, '');
|
|
375
|
+
const blockedCountries = ctx.node.getNodeParameter('youtubeBlockedCountries', ctx.itemIndex, '');
|
|
376
|
+
const hasPaidProductPlacement = ctx.node.getNodeParameter('youtubeHasPaidProductPlacement', ctx.itemIndex, false);
|
|
377
|
+
const recordingDate = ctx.node.getNodeParameter('youtubeRecordingDate', ctx.itemIndex, '');
|
|
378
|
+
formData.selfDeclaredMadeForKids = String(selfDeclaredMadeForKids);
|
|
379
|
+
formData.containsSyntheticMedia = String(containsSyntheticMedia);
|
|
380
|
+
if (defaultLanguage)
|
|
381
|
+
formData.defaultLanguage = defaultLanguage;
|
|
382
|
+
if (defaultAudioLanguage)
|
|
383
|
+
formData.defaultAudioLanguage = defaultAudioLanguage;
|
|
384
|
+
if (allowedCountries)
|
|
385
|
+
formData.allowedCountries = allowedCountries;
|
|
386
|
+
if (blockedCountries)
|
|
387
|
+
formData.blockedCountries = blockedCountries;
|
|
388
|
+
formData.hasPaidProductPlacement = String(hasPaidProductPlacement);
|
|
389
|
+
if (recordingDate)
|
|
390
|
+
formData.recordingDate = recordingDate;
|
|
391
|
+
};
|
|
392
|
+
const validateXPollConfiguration = (ctx, operation, formData) => {
|
|
393
|
+
if (operation !== 'uploadText') {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const pollOptionsRaw = ctx.node.getNodeParameter('xPollOptions', ctx.itemIndex, '');
|
|
397
|
+
const hasPollOptions = pollOptionsRaw.trim().length > 0;
|
|
398
|
+
if (!hasPollOptions) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const conflictingFields = [];
|
|
402
|
+
const cardUri = ctx.node.getNodeParameter('xCardUri', ctx.itemIndex, '');
|
|
403
|
+
const quoteTweetId = ctx.node.getNodeParameter('xQuoteTweetId', ctx.itemIndex, '');
|
|
404
|
+
const directMessageDeepLink = ctx.node.getNodeParameter('xDirectMessageDeepLink', ctx.itemIndex, '');
|
|
405
|
+
if (cardUri.trim().length > 0)
|
|
406
|
+
conflictingFields.push('X Card URI');
|
|
407
|
+
if (quoteTweetId.trim().length > 0)
|
|
408
|
+
conflictingFields.push('X Quote Tweet ID');
|
|
409
|
+
if (directMessageDeepLink.trim().length > 0)
|
|
410
|
+
conflictingFields.push('X Direct Message Deep Link');
|
|
411
|
+
if (conflictingFields.length > 0) {
|
|
412
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options cannot be used with: ${conflictingFields.join(', ')}. These fields are mutually exclusive.`);
|
|
413
|
+
}
|
|
414
|
+
const pollOptions = ensureArrayFromCommaSeparated(pollOptionsRaw);
|
|
415
|
+
if (pollOptions.length < 2 || pollOptions.length > 4) {
|
|
416
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options must contain between 2 and 4 non-empty options. Found: ${pollOptions.length}`);
|
|
417
|
+
}
|
|
418
|
+
const invalidOptions = pollOptions.filter(option => option.length > 25);
|
|
419
|
+
if (invalidOptions.length > 0) {
|
|
420
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options cannot exceed 25 characters each. Invalid options: ${invalidOptions.join(', ')}`);
|
|
421
|
+
}
|
|
422
|
+
const pollDuration = ctx.node.getNodeParameter('xPollDuration', ctx.itemIndex, 1440);
|
|
423
|
+
if (pollDuration < 5 || pollDuration > 10080) {
|
|
424
|
+
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}`);
|
|
425
|
+
}
|
|
426
|
+
formData['poll_options[]'] = pollOptions;
|
|
427
|
+
formData.poll_duration = pollDuration;
|
|
428
|
+
const pollReplySettings = ctx.node.getNodeParameter('xPollReplySettings', ctx.itemIndex, 'following');
|
|
429
|
+
formData.poll_reply_settings = pollReplySettings;
|
|
430
|
+
};
|
|
431
|
+
const applyXOptions = (ctx, operation, formData) => {
|
|
432
|
+
const quoteTweetId = ctx.node.getNodeParameter('xQuoteTweetId', ctx.itemIndex, '');
|
|
433
|
+
const geoPlaceId = ctx.node.getNodeParameter('xGeoPlaceId', ctx.itemIndex, '');
|
|
434
|
+
const forSuperFollowersOnly = ctx.node.getNodeParameter('xForSuperFollowersOnly', ctx.itemIndex, false);
|
|
435
|
+
const communityId = ctx.node.getNodeParameter('xCommunityId', ctx.itemIndex, '');
|
|
436
|
+
const shareWithFollowers = ctx.node.getNodeParameter('xShareWithFollowers', ctx.itemIndex, false);
|
|
437
|
+
const directMessageDeepLink = ctx.node.getNodeParameter('xDirectMessageDeepLink', ctx.itemIndex, '');
|
|
438
|
+
const cardUri = ctx.node.getNodeParameter('xCardUri', ctx.itemIndex, '');
|
|
439
|
+
if (quoteTweetId)
|
|
440
|
+
formData.quote_tweet_id = quoteTweetId;
|
|
441
|
+
if (geoPlaceId)
|
|
442
|
+
formData.geo_place_id = geoPlaceId;
|
|
443
|
+
if (forSuperFollowersOnly)
|
|
444
|
+
formData.for_super_followers_only = String(forSuperFollowersOnly);
|
|
445
|
+
if (communityId)
|
|
446
|
+
formData.community_id = communityId;
|
|
447
|
+
if (shareWithFollowers)
|
|
448
|
+
formData.share_with_followers = String(shareWithFollowers);
|
|
449
|
+
if (directMessageDeepLink)
|
|
450
|
+
formData.direct_message_deep_link = directMessageDeepLink;
|
|
451
|
+
if (cardUri)
|
|
452
|
+
formData.card_uri = cardUri;
|
|
453
|
+
if (operation === 'uploadText') {
|
|
454
|
+
const postUrl = ctx.node.getNodeParameter('xPostUrlText', ctx.itemIndex, '');
|
|
455
|
+
const replySettings = ctx.node.getNodeParameter('xReplySettings', ctx.itemIndex, 'everyone');
|
|
456
|
+
if (postUrl)
|
|
457
|
+
formData.post_url = postUrl;
|
|
458
|
+
if (replySettings && replySettings !== 'everyone')
|
|
459
|
+
formData.reply_settings = replySettings;
|
|
460
|
+
validateXPollConfiguration(ctx, operation, formData);
|
|
461
|
+
const xLongTextAsPost = ctx.node.getNodeParameter('xLongTextAsPost', ctx.itemIndex, false);
|
|
462
|
+
if (xLongTextAsPost) {
|
|
463
|
+
formData.x_long_text_as_post = String(xLongTextAsPost);
|
|
464
|
+
}
|
|
465
|
+
delete formData.nullcast;
|
|
466
|
+
delete formData.place_id;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
const taggedUserIds = ctx.node.getNodeParameter('xTaggedUserIds', ctx.itemIndex, '');
|
|
470
|
+
const replySettings = ctx.node.getNodeParameter('xReplySettings', ctx.itemIndex, 'everyone');
|
|
471
|
+
const nullcast = ctx.node.getNodeParameter('xNullcastVideo', ctx.itemIndex, false);
|
|
472
|
+
if (taggedUserIds) {
|
|
473
|
+
formData['tagged_user_ids[]'] = ensureArrayFromCommaSeparated(taggedUserIds);
|
|
474
|
+
}
|
|
475
|
+
if (replySettings && replySettings !== 'everyone')
|
|
476
|
+
formData.reply_settings = replySettings;
|
|
477
|
+
formData.nullcast = String(nullcast);
|
|
478
|
+
if (operation === 'uploadVideo') {
|
|
479
|
+
const xLongTextAsPost = ctx.node.getNodeParameter('xLongTextAsPost', ctx.itemIndex, false);
|
|
480
|
+
if (xLongTextAsPost) {
|
|
481
|
+
formData.x_long_text_as_post = String(xLongTextAsPost);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const xPlaceIdVideo = ctx.node.getNodeParameter('xPlaceIdVideo', ctx.itemIndex, '');
|
|
485
|
+
if (operation === 'uploadVideo' && xPlaceIdVideo) {
|
|
486
|
+
formData.place_id = xPlaceIdVideo;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
const applyThreadsOptions = (ctx, formData) => {
|
|
491
|
+
const threadsLongTextAsPost = ctx.node.getNodeParameter('threadsLongTextAsPost', ctx.itemIndex, false);
|
|
492
|
+
if (threadsLongTextAsPost) {
|
|
493
|
+
formData.threads_long_text_as_post = String(threadsLongTextAsPost);
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
const applyRedditOptions = (ctx, formData) => {
|
|
497
|
+
const subreddit = ctx.node.getNodeParameter('redditSubreddit', ctx.itemIndex);
|
|
498
|
+
const flairId = ctx.node.getNodeParameter('redditFlairId', ctx.itemIndex, '');
|
|
499
|
+
formData.subreddit = subreddit;
|
|
500
|
+
if (flairId) {
|
|
501
|
+
formData.flair_id = flairId;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
const applyUploadPlatformOptions = async (ctx, operation, prep) => {
|
|
505
|
+
const { formData, platforms } = prep;
|
|
506
|
+
if (platforms.includes('pinterest')) {
|
|
507
|
+
applyPinterestOptions(ctx, operation, formData);
|
|
508
|
+
}
|
|
509
|
+
if (platforms.includes('linkedin')) {
|
|
510
|
+
applyLinkedinOptions(ctx, operation, formData);
|
|
511
|
+
}
|
|
512
|
+
if (platforms.includes('facebook')) {
|
|
513
|
+
applyFacebookOptions(ctx, operation, formData);
|
|
514
|
+
}
|
|
515
|
+
if (platforms.includes('tiktok')) {
|
|
516
|
+
applyTiktokOptions(ctx, operation, formData);
|
|
517
|
+
}
|
|
518
|
+
if (platforms.includes('instagram')) {
|
|
519
|
+
applyInstagramOptions(ctx, operation, formData);
|
|
520
|
+
}
|
|
521
|
+
if (platforms.includes('youtube') && operation === 'uploadVideo') {
|
|
522
|
+
await applyYoutubeOptions(ctx, formData);
|
|
523
|
+
}
|
|
524
|
+
if (platforms.includes('x')) {
|
|
525
|
+
applyXOptions(ctx, operation, formData);
|
|
526
|
+
}
|
|
527
|
+
if (operation === 'uploadText' && platforms.includes('threads')) {
|
|
528
|
+
applyThreadsOptions(ctx, formData);
|
|
529
|
+
}
|
|
530
|
+
if (operation === 'uploadText' && platforms.includes('reddit')) {
|
|
531
|
+
applyRedditOptions(ctx, formData);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
const buildUploadPhotosRequest = async (ctx) => {
|
|
535
|
+
const prep = prepareUploadBase(ctx, 'uploadPhotos');
|
|
536
|
+
const photosInput = ctx.node.getNodeParameter('photos', ctx.itemIndex, '');
|
|
537
|
+
let photosToProcess = [];
|
|
538
|
+
if (Array.isArray(photosInput)) {
|
|
539
|
+
photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim().length > 0).map(item => item.trim());
|
|
540
|
+
}
|
|
541
|
+
else if (typeof photosInput === 'string') {
|
|
542
|
+
photosToProcess = ensureArrayFromCommaSeparated(photosInput);
|
|
543
|
+
}
|
|
544
|
+
const photoArray = [];
|
|
545
|
+
for (const photoItem of photosToProcess) {
|
|
546
|
+
if (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://')) {
|
|
547
|
+
photoArray.push(photoItem);
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
const binaryField = await getBinaryFieldFromItem(ctx, photoItem, 'Binary data for property');
|
|
551
|
+
photoArray.push(binaryField);
|
|
552
|
+
}
|
|
553
|
+
if (photoArray.length > 0) {
|
|
554
|
+
prep.formData['photos[]'] = photoArray;
|
|
555
|
+
}
|
|
556
|
+
await applyUploadPlatformOptions(ctx, 'uploadPhotos', prep);
|
|
557
|
+
return {
|
|
558
|
+
endpoint: '/upload_photos',
|
|
559
|
+
method: 'POST',
|
|
560
|
+
formData: prep.formData,
|
|
561
|
+
isUploadOperation: true,
|
|
562
|
+
waitForCompletion: prep.waitForCompletion,
|
|
563
|
+
pollInterval: prep.pollInterval,
|
|
564
|
+
pollTimeout: prep.pollTimeout,
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
const buildUploadVideoRequest = async (ctx) => {
|
|
568
|
+
const prep = prepareUploadBase(ctx, 'uploadVideo');
|
|
569
|
+
const videoInput = ctx.node.getNodeParameter('video', ctx.itemIndex, '');
|
|
570
|
+
if (videoInput) {
|
|
571
|
+
if (videoInput.toLowerCase().startsWith('http://') || videoInput.toLowerCase().startsWith('https://')) {
|
|
572
|
+
prep.formData.video = videoInput;
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
const binaryField = await getBinaryFieldFromItem(ctx, videoInput, 'Binary data for video property');
|
|
576
|
+
prep.formData.video = binaryField;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
await applyUploadPlatformOptions(ctx, 'uploadVideo', prep);
|
|
580
|
+
return {
|
|
581
|
+
endpoint: '/upload',
|
|
582
|
+
method: 'POST',
|
|
583
|
+
formData: prep.formData,
|
|
584
|
+
isUploadOperation: true,
|
|
585
|
+
waitForCompletion: prep.waitForCompletion,
|
|
586
|
+
pollInterval: prep.pollInterval,
|
|
587
|
+
pollTimeout: prep.pollTimeout,
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
const buildUploadTextRequest = async (ctx) => {
|
|
591
|
+
const prep = prepareUploadBase(ctx, 'uploadText');
|
|
592
|
+
await applyUploadPlatformOptions(ctx, 'uploadText', prep);
|
|
593
|
+
return {
|
|
594
|
+
endpoint: '/upload_text',
|
|
595
|
+
method: 'POST',
|
|
596
|
+
formData: prep.formData,
|
|
597
|
+
isUploadOperation: true,
|
|
598
|
+
waitForCompletion: prep.waitForCompletion,
|
|
599
|
+
pollInterval: prep.pollInterval,
|
|
600
|
+
pollTimeout: prep.pollTimeout,
|
|
601
|
+
};
|
|
602
|
+
};
|
|
603
|
+
const buildMonitoringRequest = (ctx) => {
|
|
604
|
+
switch (ctx.operation) {
|
|
605
|
+
case 'getStatus': {
|
|
606
|
+
const requestId = ctx.node.getNodeParameter('requestId', ctx.itemIndex);
|
|
607
|
+
return {
|
|
608
|
+
endpoint: '/uploadposts/status',
|
|
609
|
+
method: 'GET',
|
|
610
|
+
qs: { request_id: requestId },
|
|
611
|
+
isUploadOperation: false,
|
|
612
|
+
waitForCompletion: false,
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
case 'getHistory': {
|
|
616
|
+
const page = ctx.node.getNodeParameter('historyPage', ctx.itemIndex, 1);
|
|
617
|
+
const limit = ctx.node.getNodeParameter('historyLimit', ctx.itemIndex, 20);
|
|
618
|
+
return {
|
|
619
|
+
endpoint: '/uploadposts/history',
|
|
620
|
+
method: 'GET',
|
|
621
|
+
qs: { page, limit },
|
|
622
|
+
isUploadOperation: false,
|
|
623
|
+
waitForCompletion: false,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
case 'getAnalytics': {
|
|
627
|
+
const profileUsername = ctx.node.getNodeParameter('analyticsProfileUsername', ctx.itemIndex);
|
|
628
|
+
const analyticsPlatforms = ctx.node.getNodeParameter('analyticsPlatforms', ctx.itemIndex, []);
|
|
629
|
+
const qs = {};
|
|
630
|
+
if (Array.isArray(analyticsPlatforms) && analyticsPlatforms.length > 0) {
|
|
631
|
+
qs.platforms = analyticsPlatforms.join(',');
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
endpoint: `/analytics/${encodeURIComponent(profileUsername)}`,
|
|
635
|
+
method: 'GET',
|
|
636
|
+
qs,
|
|
637
|
+
isUploadOperation: false,
|
|
638
|
+
waitForCompletion: false,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
case 'listScheduled': {
|
|
642
|
+
return {
|
|
643
|
+
endpoint: '/uploadposts/schedule',
|
|
644
|
+
method: 'GET',
|
|
645
|
+
isUploadOperation: false,
|
|
646
|
+
waitForCompletion: false,
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
case 'cancelScheduled': {
|
|
650
|
+
const jobId = ctx.node.getNodeParameter('scheduleJobId', ctx.itemIndex);
|
|
651
|
+
return {
|
|
652
|
+
endpoint: `/uploadposts/schedule/${jobId}`,
|
|
653
|
+
method: 'DELETE',
|
|
654
|
+
isUploadOperation: false,
|
|
655
|
+
waitForCompletion: false,
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
case 'editScheduled': {
|
|
659
|
+
const jobId = ctx.node.getNodeParameter('scheduleJobId', ctx.itemIndex);
|
|
660
|
+
const newScheduledDateRaw = ctx.node.getNodeParameter('newScheduledDate', ctx.itemIndex, '');
|
|
661
|
+
const normalizedDate = normalizeDateInput(newScheduledDateRaw);
|
|
662
|
+
const body = {};
|
|
663
|
+
if (normalizedDate) {
|
|
664
|
+
body.scheduled_date = normalizedDate;
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
endpoint: `/uploadposts/schedule/${jobId}`,
|
|
668
|
+
method: 'POST',
|
|
669
|
+
body,
|
|
670
|
+
isUploadOperation: false,
|
|
671
|
+
waitForCompletion: false,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
default:
|
|
675
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported monitoring operation: ${ctx.operation}`, {
|
|
676
|
+
itemIndex: ctx.itemIndex,
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
const buildUserRequest = (ctx) => {
|
|
681
|
+
switch (ctx.operation) {
|
|
682
|
+
case 'listUsers':
|
|
683
|
+
return {
|
|
684
|
+
endpoint: '/uploadposts/users',
|
|
685
|
+
method: 'GET',
|
|
686
|
+
isUploadOperation: false,
|
|
687
|
+
waitForCompletion: false,
|
|
688
|
+
};
|
|
689
|
+
case 'createUser': {
|
|
690
|
+
const username = ctx.node.getNodeParameter('newUser', ctx.itemIndex);
|
|
691
|
+
return {
|
|
692
|
+
endpoint: '/uploadposts/users',
|
|
693
|
+
method: 'POST',
|
|
694
|
+
body: { username },
|
|
695
|
+
isUploadOperation: false,
|
|
696
|
+
waitForCompletion: false,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
case 'deleteUser': {
|
|
700
|
+
const username = ctx.node.getNodeParameter('deleteUserId', ctx.itemIndex);
|
|
701
|
+
return {
|
|
702
|
+
endpoint: '/uploadposts/users',
|
|
703
|
+
method: 'DELETE',
|
|
704
|
+
body: { username },
|
|
705
|
+
isUploadOperation: false,
|
|
706
|
+
waitForCompletion: false,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
case 'generateJwt': {
|
|
710
|
+
const username = getUserForOperation(ctx, true);
|
|
711
|
+
const redirectUrl = ctx.node.getNodeParameter('redirectUrl', ctx.itemIndex, '');
|
|
712
|
+
const logoImage = ctx.node.getNodeParameter('logoImage', ctx.itemIndex, '');
|
|
713
|
+
const redirectButtonText = ctx.node.getNodeParameter('redirectButtonText', ctx.itemIndex, '');
|
|
714
|
+
const platforms = ctx.node.getNodeParameter('jwtPlatforms', ctx.itemIndex, []);
|
|
715
|
+
const body = { username };
|
|
716
|
+
if (redirectUrl)
|
|
717
|
+
body.redirect_url = redirectUrl;
|
|
718
|
+
if (logoImage)
|
|
719
|
+
body.logo_image = logoImage;
|
|
720
|
+
if (redirectButtonText)
|
|
721
|
+
body.redirect_button_text = redirectButtonText;
|
|
722
|
+
if (Array.isArray(platforms) && platforms.length > 0)
|
|
723
|
+
body.platforms = platforms;
|
|
724
|
+
return {
|
|
725
|
+
endpoint: '/uploadposts/users/generate-jwt',
|
|
726
|
+
method: 'POST',
|
|
727
|
+
body,
|
|
728
|
+
isUploadOperation: false,
|
|
729
|
+
waitForCompletion: false,
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
case 'validateJwt': {
|
|
733
|
+
const jwt = ctx.node.getNodeParameter('jwtToken', ctx.itemIndex);
|
|
734
|
+
return {
|
|
735
|
+
endpoint: '/uploadposts/users/validate-jwt',
|
|
736
|
+
method: 'POST',
|
|
737
|
+
body: { jwt },
|
|
738
|
+
headers: { Authorization: `Bearer ${jwt}` },
|
|
739
|
+
isUploadOperation: false,
|
|
740
|
+
waitForCompletion: false,
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
default:
|
|
744
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported user operation: ${ctx.operation}`, {
|
|
745
|
+
itemIndex: ctx.itemIndex,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
const buildRequestConfig = async (ctx) => {
|
|
750
|
+
if (ctx.operation === 'uploadPhotos') {
|
|
751
|
+
return buildUploadPhotosRequest(ctx);
|
|
752
|
+
}
|
|
753
|
+
if (ctx.operation === 'uploadVideo') {
|
|
754
|
+
return buildUploadVideoRequest(ctx);
|
|
755
|
+
}
|
|
756
|
+
if (ctx.operation === 'uploadText') {
|
|
757
|
+
return buildUploadTextRequest(ctx);
|
|
758
|
+
}
|
|
759
|
+
const resource = ctx.node.getNodeParameter('resource', ctx.itemIndex);
|
|
760
|
+
if (resource === 'monitoring') {
|
|
761
|
+
return buildMonitoringRequest(ctx);
|
|
762
|
+
}
|
|
763
|
+
if (resource === 'users') {
|
|
764
|
+
return buildUserRequest(ctx);
|
|
765
|
+
}
|
|
766
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported operation: ${ctx.operation}`, {
|
|
767
|
+
itemIndex: ctx.itemIndex,
|
|
768
|
+
});
|
|
769
|
+
};
|
|
770
|
+
const buildNativeFormData = (payload, node) => {
|
|
771
|
+
if (typeof FormData === 'undefined') {
|
|
772
|
+
throw new n8n_workflow_1.NodeOperationError(node.getNode(), 'FormData is not supported in this runtime environment');
|
|
773
|
+
}
|
|
774
|
+
const form = new FormData();
|
|
775
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
776
|
+
if (Array.isArray(value)) {
|
|
777
|
+
value.forEach(item => appendValue(form, key, item));
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
appendValue(form, key, value);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return form;
|
|
784
|
+
};
|
|
785
|
+
const appendValue = (form, key, value) => {
|
|
786
|
+
if (isBinaryFormField(value)) {
|
|
787
|
+
appendBinaryValue(form, key, value);
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
form.append(key, value);
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
const appendBinaryValue = (form, key, field) => {
|
|
794
|
+
var _a, _b;
|
|
795
|
+
const { value, options } = field;
|
|
796
|
+
if (typeof value === 'string') {
|
|
797
|
+
form.append(key, value);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const filename = (_a = options === null || options === void 0 ? void 0 : options.filename) !== null && _a !== void 0 ? _a : 'upload.bin';
|
|
801
|
+
const contentType = (_b = options === null || options === void 0 ? void 0 : options.contentType) !== null && _b !== void 0 ? _b : 'application/octet-stream';
|
|
802
|
+
if (typeof Blob !== 'undefined') {
|
|
803
|
+
const blob = new Blob([value], { type: contentType });
|
|
804
|
+
form.append(key, blob, filename);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
form.append(key, value, { filename, contentType });
|
|
808
|
+
};
|
|
809
|
+
const pollUploadStatus = async (node, requestId, pollInterval, pollTimeout) => {
|
|
810
|
+
const start = Date.now();
|
|
811
|
+
let finalData = { success: false, message: 'Polling timed out', request_id: requestId };
|
|
812
|
+
while (true) {
|
|
813
|
+
await (0, n8n_workflow_1.sleep)(Math.max(1, pollInterval) * 1000);
|
|
814
|
+
if (Date.now() - start > Math.max(5, pollTimeout) * 1000) {
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
const statusOptions = {
|
|
818
|
+
url: `${API_BASE_URL}/uploadposts/status`,
|
|
819
|
+
method: 'GET',
|
|
820
|
+
qs: { request_id: requestId },
|
|
821
|
+
json: true,
|
|
822
|
+
};
|
|
823
|
+
const statusData = await node.helpers.httpRequestWithAuthentication.call(node, 'uploadPostApi', statusOptions);
|
|
824
|
+
finalData = statusData;
|
|
825
|
+
const statusValue = (statusData && statusData.status);
|
|
826
|
+
if ((statusData && statusData.success === true) ||
|
|
827
|
+
(statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return finalData;
|
|
832
|
+
};
|
|
13
833
|
class UploadPost {
|
|
14
834
|
constructor() {
|
|
15
835
|
this.description = {
|
|
@@ -138,6 +958,14 @@ class UploadPost {
|
|
|
138
958
|
description: 'Title of the post. For Upload Text, this is the main text content. For some video platforms, this acts as a fallback for description if a specific description is not provided.',
|
|
139
959
|
displayOptions: { show: { resource: ['uploads'], operation: ['uploadPhotos', 'uploadVideo', 'uploadText'] } },
|
|
140
960
|
},
|
|
961
|
+
{
|
|
962
|
+
displayName: 'Bluesky Title (Override)',
|
|
963
|
+
name: 'blueskyTitle',
|
|
964
|
+
type: 'string',
|
|
965
|
+
default: '',
|
|
966
|
+
description: 'Optional override for Bluesky title (max 300 characters)',
|
|
967
|
+
displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['bluesky'] } },
|
|
968
|
+
},
|
|
141
969
|
{
|
|
142
970
|
displayName: 'Instagram Title (Override)',
|
|
143
971
|
name: 'instagramTitle',
|
|
@@ -1516,6 +2344,7 @@ class UploadPost {
|
|
|
1516
2344
|
async getPlatforms() {
|
|
1517
2345
|
const operation = this.getCurrentNodeParameter('operation');
|
|
1518
2346
|
const allPlatforms = [
|
|
2347
|
+
{ name: 'Bluesky', value: 'bluesky' },
|
|
1519
2348
|
{ name: 'Facebook', value: 'facebook' },
|
|
1520
2349
|
{ name: 'Instagram', value: 'instagram' },
|
|
1521
2350
|
{ name: 'LinkedIn', value: 'linkedin' },
|
|
@@ -1527,9 +2356,9 @@ class UploadPost {
|
|
|
1527
2356
|
{ name: 'YouTube', value: 'youtube' },
|
|
1528
2357
|
];
|
|
1529
2358
|
const platformSupport = {
|
|
1530
|
-
uploadPhotos: ['facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x'],
|
|
1531
|
-
uploadVideo: ['facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x', 'youtube'],
|
|
1532
|
-
uploadText: ['facebook', 'linkedin', 'reddit', 'threads', 'x'],
|
|
2359
|
+
uploadPhotos: ['bluesky', 'facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x'],
|
|
2360
|
+
uploadVideo: ['bluesky', 'facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x', 'youtube'],
|
|
2361
|
+
uploadText: ['bluesky', 'facebook', 'linkedin', 'reddit', 'threads', 'x'],
|
|
1533
2362
|
};
|
|
1534
2363
|
const supportedPlatforms = platformSupport[operation] || [];
|
|
1535
2364
|
return allPlatforms.filter(platform => supportedPlatforms.includes(platform.value));
|
|
@@ -1650,777 +2479,55 @@ class UploadPost {
|
|
|
1650
2479
|
};
|
|
1651
2480
|
}
|
|
1652
2481
|
async execute() {
|
|
1653
|
-
var _a, _b
|
|
2482
|
+
var _a, _b;
|
|
1654
2483
|
const items = this.getInputData();
|
|
1655
2484
|
const returnData = [];
|
|
1656
|
-
for (let
|
|
1657
|
-
const operation = this.getNodeParameter('operation',
|
|
1658
|
-
const
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
const
|
|
1665
|
-
|
|
1666
|
-
:
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
const formData = {};
|
|
1672
|
-
const qs = {};
|
|
1673
|
-
const body = {};
|
|
1674
|
-
if (isUploadOperation) {
|
|
1675
|
-
formData.user = user;
|
|
1676
|
-
formData.title = title;
|
|
1677
|
-
const scheduledDate = this.getNodeParameter('scheduledDate', i);
|
|
1678
|
-
if (scheduledDate) {
|
|
1679
|
-
let normalizedDate = scheduledDate;
|
|
1680
|
-
const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
|
|
1681
|
-
if (!hasTimezone) {
|
|
1682
|
-
normalizedDate = `${normalizedDate}Z`;
|
|
1683
|
-
}
|
|
1684
|
-
formData.scheduled_date = normalizedDate;
|
|
1685
|
-
}
|
|
1686
|
-
const uploadAsync = this.getNodeParameter('uploadAsync', i);
|
|
1687
|
-
if (uploadAsync !== undefined) {
|
|
1688
|
-
formData.async_upload = String(uploadAsync);
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
if (isUploadOperation) {
|
|
1692
|
-
try {
|
|
1693
|
-
if (platforms.includes('instagram')) {
|
|
1694
|
-
const instagramTitle = this.getNodeParameter('instagramTitle', i, '');
|
|
1695
|
-
if (instagramTitle)
|
|
1696
|
-
formData.instagram_title = instagramTitle;
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
catch { }
|
|
1700
|
-
try {
|
|
1701
|
-
if (platforms.includes('facebook')) {
|
|
1702
|
-
const facebookTitle = this.getNodeParameter('facebookTitle', i, '');
|
|
1703
|
-
if (facebookTitle)
|
|
1704
|
-
formData.facebook_title = facebookTitle;
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
catch { }
|
|
1708
|
-
try {
|
|
1709
|
-
if (platforms.includes('tiktok')) {
|
|
1710
|
-
const tiktokTitle = this.getNodeParameter('tiktokTitle', i, '');
|
|
1711
|
-
if (tiktokTitle)
|
|
1712
|
-
formData.tiktok_title = tiktokTitle;
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
catch { }
|
|
1716
|
-
try {
|
|
1717
|
-
if (platforms.includes('linkedin')) {
|
|
1718
|
-
const linkedinTitle = this.getNodeParameter('linkedinTitle', i, '');
|
|
1719
|
-
if (linkedinTitle)
|
|
1720
|
-
formData.linkedin_title = linkedinTitle;
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
catch { }
|
|
1724
|
-
try {
|
|
1725
|
-
if (platforms.includes('x')) {
|
|
1726
|
-
const xTitle = this.getNodeParameter('xTitle', i, '');
|
|
1727
|
-
if (xTitle)
|
|
1728
|
-
formData.x_title = xTitle;
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
catch { }
|
|
1732
|
-
try {
|
|
1733
|
-
if (platforms.includes('youtube')) {
|
|
1734
|
-
const youtubeTitle = this.getNodeParameter('youtubeTitle', i, '');
|
|
1735
|
-
if (youtubeTitle)
|
|
1736
|
-
formData.youtube_title = youtubeTitle;
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
catch { }
|
|
1740
|
-
try {
|
|
1741
|
-
if (platforms.includes('pinterest')) {
|
|
1742
|
-
const pinterestTitle = this.getNodeParameter('pinterestTitle', i, '');
|
|
1743
|
-
if (pinterestTitle)
|
|
1744
|
-
formData.pinterest_title = pinterestTitle;
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
catch { }
|
|
1748
|
-
}
|
|
1749
|
-
if (isUploadOperation) {
|
|
1750
|
-
const genericDescription = this.getNodeParameter('description', i, '');
|
|
1751
|
-
const descriptionPlatforms = new Set(['linkedin', 'facebook', 'youtube', 'pinterest', 'tiktok']);
|
|
1752
|
-
if (genericDescription && platforms.some(p => descriptionPlatforms.has(p))) {
|
|
1753
|
-
formData.description = genericDescription;
|
|
1754
|
-
}
|
|
1755
|
-
try {
|
|
1756
|
-
if (platforms.includes('linkedin')) {
|
|
1757
|
-
const linkedinDescription = this.getNodeParameter('linkedinDescription', i, '');
|
|
1758
|
-
if (linkedinDescription)
|
|
1759
|
-
formData.linkedin_description = linkedinDescription;
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
catch { }
|
|
1763
|
-
try {
|
|
1764
|
-
if (platforms.includes('youtube')) {
|
|
1765
|
-
const youtubeDescription = this.getNodeParameter('youtubeDescription', i, '');
|
|
1766
|
-
if (youtubeDescription)
|
|
1767
|
-
formData.youtube_description = youtubeDescription;
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
catch { }
|
|
1771
|
-
try {
|
|
1772
|
-
if (platforms.includes('facebook')) {
|
|
1773
|
-
const facebookDescription = this.getNodeParameter('facebookDescription', i, '');
|
|
1774
|
-
if (facebookDescription)
|
|
1775
|
-
formData.facebook_description = facebookDescription;
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
catch { }
|
|
1779
|
-
try {
|
|
1780
|
-
if (platforms.includes('tiktok')) {
|
|
1781
|
-
const tiktokDescription = this.getNodeParameter('tiktokDescription', i, '');
|
|
1782
|
-
if (tiktokDescription)
|
|
1783
|
-
formData.tiktok_description = tiktokDescription;
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
catch { }
|
|
1787
|
-
try {
|
|
1788
|
-
if (platforms.includes('pinterest')) {
|
|
1789
|
-
const pinterestDescription = this.getNodeParameter('pinterestDescription', i, '');
|
|
1790
|
-
if (pinterestDescription)
|
|
1791
|
-
formData.pinterest_description = pinterestDescription;
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
catch { }
|
|
1795
|
-
}
|
|
1796
|
-
switch (operation) {
|
|
1797
|
-
case 'uploadPhotos':
|
|
1798
|
-
endpoint = '/upload_photos';
|
|
1799
|
-
let photosInput = this.getNodeParameter('photos', i, []);
|
|
1800
|
-
let photosToProcess;
|
|
1801
|
-
if (typeof photosInput === 'string') {
|
|
1802
|
-
photosToProcess = photosInput.split(',').map(item => item.trim()).filter(item => item !== '');
|
|
1803
|
-
}
|
|
1804
|
-
else {
|
|
1805
|
-
photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim() !== '');
|
|
1806
|
-
}
|
|
1807
|
-
const allowedPhotoPlatforms = ['tiktok', 'instagram', 'linkedin', 'facebook', 'x', 'threads', 'pinterest'];
|
|
1808
|
-
platforms = platforms.filter(p => allowedPhotoPlatforms.includes(p));
|
|
1809
|
-
formData['platform[]'] = platforms;
|
|
1810
|
-
if (photosToProcess.length > 0) {
|
|
1811
|
-
const photoArray = [];
|
|
1812
|
-
for (const photoItem of photosToProcess) {
|
|
1813
|
-
if (typeof photoItem === 'string' && photoItem) {
|
|
1814
|
-
if (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://')) {
|
|
1815
|
-
photoArray.push(photoItem);
|
|
1816
|
-
}
|
|
1817
|
-
else {
|
|
1818
|
-
const binaryPropertyName = photoItem;
|
|
1819
|
-
try {
|
|
1820
|
-
const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
1821
|
-
const binaryFileDetails = items[i].binary[binaryPropertyName];
|
|
1822
|
-
photoArray.push({
|
|
1823
|
-
value: binaryBuffer,
|
|
1824
|
-
options: {
|
|
1825
|
-
filename: (_a = binaryFileDetails.fileName) !== null && _a !== void 0 ? _a : binaryPropertyName,
|
|
1826
|
-
contentType: binaryFileDetails.mimeType,
|
|
1827
|
-
},
|
|
1828
|
-
});
|
|
1829
|
-
}
|
|
1830
|
-
catch (error) {
|
|
1831
|
-
const errorMessage = error instanceof Error ? error.message : '';
|
|
1832
|
-
const details = errorMessage ? ` (${errorMessage})` : '';
|
|
1833
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Binary data for property '${binaryPropertyName}' was not found in item ${i}.${details}`, {
|
|
1834
|
-
itemIndex: i,
|
|
1835
|
-
});
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
if (photoArray.length > 0) {
|
|
1841
|
-
formData['photos[]'] = photoArray;
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
break;
|
|
1845
|
-
case 'uploadVideo':
|
|
1846
|
-
endpoint = '/upload';
|
|
1847
|
-
const videoInput = this.getNodeParameter('video', i);
|
|
1848
|
-
const allowedVideoPlatforms = ['tiktok', 'instagram', 'linkedin', 'youtube', 'facebook', 'x', 'threads', 'pinterest'];
|
|
1849
|
-
platforms = platforms.filter(p => allowedVideoPlatforms.includes(p));
|
|
1850
|
-
formData['platform[]'] = platforms;
|
|
1851
|
-
if (videoInput) {
|
|
1852
|
-
if (videoInput.toLowerCase().startsWith('http://') || videoInput.toLowerCase().startsWith('https://')) {
|
|
1853
|
-
formData.video = videoInput;
|
|
1854
|
-
}
|
|
1855
|
-
else {
|
|
1856
|
-
const binaryPropertyName = videoInput;
|
|
1857
|
-
try {
|
|
1858
|
-
const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
1859
|
-
const binaryFileDetails = items[i].binary[binaryPropertyName];
|
|
1860
|
-
formData.video = {
|
|
1861
|
-
value: binaryBuffer,
|
|
1862
|
-
options: {
|
|
1863
|
-
filename: (_b = binaryFileDetails.fileName) !== null && _b !== void 0 ? _b : binaryPropertyName,
|
|
1864
|
-
contentType: binaryFileDetails.mimeType,
|
|
1865
|
-
},
|
|
1866
|
-
};
|
|
1867
|
-
}
|
|
1868
|
-
catch (error) {
|
|
1869
|
-
const errorMessage = error instanceof Error ? error.message : '';
|
|
1870
|
-
const details = errorMessage ? ` (${errorMessage})` : '';
|
|
1871
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Binary data for video property '${binaryPropertyName}' was not found in item ${i}.${details}`, {
|
|
1872
|
-
itemIndex: i,
|
|
1873
|
-
});
|
|
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
|
-
const errorMessage = error instanceof Error ? error.message : '';
|
|
2186
|
-
const details = errorMessage ? ` (${errorMessage})` : '';
|
|
2187
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Binary data for YouTube thumbnail property '${binaryPropertyName}' was not found in item ${i}.${details}`, {
|
|
2188
|
-
itemIndex: i,
|
|
2189
|
-
});
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
}
|
|
2193
|
-
const youtubeSelfDeclaredMadeForKids = this.getNodeParameter('youtubeSelfDeclaredMadeForKids', i);
|
|
2194
|
-
const youtubeContainsSyntheticMedia = this.getNodeParameter('youtubeContainsSyntheticMedia', i);
|
|
2195
|
-
const youtubeDefaultLanguage = this.getNodeParameter('youtubeDefaultLanguage', i);
|
|
2196
|
-
const youtubeDefaultAudioLanguage = this.getNodeParameter('youtubeDefaultAudioLanguage', i);
|
|
2197
|
-
const youtubeAllowedCountries = this.getNodeParameter('youtubeAllowedCountries', i);
|
|
2198
|
-
const youtubeBlockedCountries = this.getNodeParameter('youtubeBlockedCountries', i);
|
|
2199
|
-
const youtubeHasPaidProductPlacement = this.getNodeParameter('youtubeHasPaidProductPlacement', i);
|
|
2200
|
-
const youtubeRecordingDate = this.getNodeParameter('youtubeRecordingDate', i);
|
|
2201
|
-
if (youtubeSelfDeclaredMadeForKids !== undefined)
|
|
2202
|
-
formData.selfDeclaredMadeForKids = String(youtubeSelfDeclaredMadeForKids);
|
|
2203
|
-
if (youtubeContainsSyntheticMedia !== undefined)
|
|
2204
|
-
formData.containsSyntheticMedia = String(youtubeContainsSyntheticMedia);
|
|
2205
|
-
if (youtubeDefaultLanguage)
|
|
2206
|
-
formData.defaultLanguage = youtubeDefaultLanguage;
|
|
2207
|
-
if (youtubeDefaultAudioLanguage)
|
|
2208
|
-
formData.defaultAudioLanguage = youtubeDefaultAudioLanguage;
|
|
2209
|
-
if (youtubeAllowedCountries)
|
|
2210
|
-
formData.allowedCountries = youtubeAllowedCountries;
|
|
2211
|
-
if (youtubeBlockedCountries)
|
|
2212
|
-
formData.blockedCountries = youtubeBlockedCountries;
|
|
2213
|
-
if (youtubeHasPaidProductPlacement !== undefined)
|
|
2214
|
-
formData.hasPaidProductPlacement = String(youtubeHasPaidProductPlacement);
|
|
2215
|
-
if (youtubeRecordingDate)
|
|
2216
|
-
formData.recordingDate = youtubeRecordingDate;
|
|
2217
|
-
}
|
|
2218
|
-
if (isUploadOperation && platforms.includes('x')) {
|
|
2219
|
-
const xQuoteTweetId = this.getNodeParameter('xQuoteTweetId', i, '');
|
|
2220
|
-
const xGeoPlaceId = this.getNodeParameter('xGeoPlaceId', i, '');
|
|
2221
|
-
const xForSuperFollowersOnly = this.getNodeParameter('xForSuperFollowersOnly', i, false);
|
|
2222
|
-
const xCommunityId = this.getNodeParameter('xCommunityId', i, '');
|
|
2223
|
-
const xShareWithFollowers = this.getNodeParameter('xShareWithFollowers', i, false);
|
|
2224
|
-
const xDirectMessageDeepLink = this.getNodeParameter('xDirectMessageDeepLink', i, '');
|
|
2225
|
-
const xCardUri = this.getNodeParameter('xCardUri', i, '');
|
|
2226
|
-
if (xQuoteTweetId)
|
|
2227
|
-
formData.quote_tweet_id = xQuoteTweetId;
|
|
2228
|
-
if (xGeoPlaceId)
|
|
2229
|
-
formData.geo_place_id = xGeoPlaceId;
|
|
2230
|
-
if (xForSuperFollowersOnly)
|
|
2231
|
-
formData.for_super_followers_only = String(xForSuperFollowersOnly);
|
|
2232
|
-
if (xCommunityId)
|
|
2233
|
-
formData.community_id = xCommunityId;
|
|
2234
|
-
if (xShareWithFollowers)
|
|
2235
|
-
formData.share_with_followers = String(xShareWithFollowers);
|
|
2236
|
-
if (xDirectMessageDeepLink)
|
|
2237
|
-
formData.direct_message_deep_link = xDirectMessageDeepLink;
|
|
2238
|
-
if (xCardUri)
|
|
2239
|
-
formData.card_uri = xCardUri;
|
|
2240
|
-
if (operation === 'uploadText') {
|
|
2241
|
-
const xPostUrlText = this.getNodeParameter('xPostUrlText', i);
|
|
2242
|
-
if (xPostUrlText)
|
|
2243
|
-
formData.post_url = xPostUrlText;
|
|
2244
|
-
const xReplySettingsText = this.getNodeParameter('xReplySettings', i);
|
|
2245
|
-
if (xReplySettingsText && xReplySettingsText !== 'everyone')
|
|
2246
|
-
formData.reply_settings = xReplySettingsText;
|
|
2247
|
-
const xPollDuration = this.getNodeParameter('xPollDuration', i, 1440);
|
|
2248
|
-
const xPollOptionsRaw = this.getNodeParameter('xPollOptions', i, '');
|
|
2249
|
-
const xPollReplySettings = this.getNodeParameter('xPollReplySettings', i, 'following');
|
|
2250
|
-
const xCardUri = this.getNodeParameter('xCardUri', i, '');
|
|
2251
|
-
const xQuoteTweetId = this.getNodeParameter('xQuoteTweetId', i, '');
|
|
2252
|
-
const xDirectMessageDeepLink = this.getNodeParameter('xDirectMessageDeepLink', i, '');
|
|
2253
|
-
const hasPollOptions = xPollOptionsRaw && xPollOptionsRaw.trim();
|
|
2254
|
-
const hasCardUri = xCardUri && xCardUri.trim();
|
|
2255
|
-
const hasQuoteTweetId = xQuoteTweetId && xQuoteTweetId.trim();
|
|
2256
|
-
const hasDirectMessageDeepLink = xDirectMessageDeepLink && xDirectMessageDeepLink.trim();
|
|
2257
|
-
if (hasPollOptions && (hasCardUri || hasQuoteTweetId || hasDirectMessageDeepLink)) {
|
|
2258
|
-
const conflictingFields = [];
|
|
2259
|
-
if (hasCardUri)
|
|
2260
|
-
conflictingFields.push('X Card URI');
|
|
2261
|
-
if (hasQuoteTweetId)
|
|
2262
|
-
conflictingFields.push('X Quote Tweet ID');
|
|
2263
|
-
if (hasDirectMessageDeepLink)
|
|
2264
|
-
conflictingFields.push('X Direct Message Deep Link');
|
|
2265
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options cannot be used with: ${conflictingFields.join(', ')}. These fields are mutually exclusive.`);
|
|
2266
|
-
}
|
|
2267
|
-
if (hasPollOptions) {
|
|
2268
|
-
const pollOptions = xPollOptionsRaw.split(',').map(opt => opt.trim()).filter(opt => opt.length > 0);
|
|
2269
|
-
if (pollOptions.length < 2 || pollOptions.length > 4) {
|
|
2270
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options must contain between 2 and 4 non-empty options. Found: ${pollOptions.length}`);
|
|
2271
|
-
}
|
|
2272
|
-
const invalidOptions = pollOptions.filter(opt => opt.length > 25);
|
|
2273
|
-
if (invalidOptions.length > 0) {
|
|
2274
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options cannot exceed 25 characters each. Invalid options: ${invalidOptions.join(', ')}`);
|
|
2275
|
-
}
|
|
2276
|
-
if (xPollDuration < 5 || xPollDuration > 10080) {
|
|
2277
|
-
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}`);
|
|
2278
|
-
}
|
|
2279
|
-
formData['poll_options[]'] = pollOptions;
|
|
2280
|
-
formData.poll_duration = xPollDuration;
|
|
2281
|
-
formData.poll_reply_settings = xPollReplySettings;
|
|
2282
|
-
}
|
|
2283
|
-
try {
|
|
2284
|
-
const xLongTextAsPostText = this.getNodeParameter('xLongTextAsPost', i, false);
|
|
2285
|
-
if (xLongTextAsPostText)
|
|
2286
|
-
formData.x_long_text_as_post = String(xLongTextAsPostText);
|
|
2287
|
-
}
|
|
2288
|
-
catch { }
|
|
2289
|
-
delete formData.nullcast;
|
|
2290
|
-
delete formData.place_id;
|
|
2291
|
-
}
|
|
2292
|
-
else if (operation === 'uploadVideo' || operation === 'uploadPhotos') {
|
|
2293
|
-
const xTaggedUserIds = this.getNodeParameter('xTaggedUserIds', i);
|
|
2294
|
-
const xReplySettings = this.getNodeParameter('xReplySettings', i);
|
|
2295
|
-
const xNullcastVideo = this.getNodeParameter('xNullcastVideo', i);
|
|
2296
|
-
if (xTaggedUserIds)
|
|
2297
|
-
formData['tagged_user_ids[]'] = xTaggedUserIds.split(',').map(id => id.trim());
|
|
2298
|
-
if (xReplySettings && xReplySettings !== 'everyone')
|
|
2299
|
-
formData.reply_settings = xReplySettings;
|
|
2300
|
-
if (xNullcastVideo !== undefined)
|
|
2301
|
-
formData.nullcast = String(xNullcastVideo);
|
|
2302
|
-
if (operation === 'uploadVideo') {
|
|
2303
|
-
try {
|
|
2304
|
-
const xLongTextAsPost = this.getNodeParameter('xLongTextAsPost', i, false);
|
|
2305
|
-
if (xLongTextAsPost)
|
|
2306
|
-
formData.x_long_text_as_post = String(xLongTextAsPost);
|
|
2307
|
-
}
|
|
2308
|
-
catch { }
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
}
|
|
2312
|
-
if (isUploadOperation && platforms.includes('threads')) {
|
|
2313
|
-
if (operation === 'uploadText') {
|
|
2314
|
-
const threadsTitle = this.getNodeParameter('threadsTitle', i, '');
|
|
2315
|
-
if (threadsTitle)
|
|
2316
|
-
formData.threads_title = threadsTitle;
|
|
2317
|
-
const threadsLongTextAsPost = this.getNodeParameter('threadsLongTextAsPost', i, false);
|
|
2318
|
-
if (threadsLongTextAsPost)
|
|
2319
|
-
formData.threads_long_text_as_post = String(threadsLongTextAsPost);
|
|
2320
|
-
}
|
|
2485
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
2486
|
+
const operation = this.getNodeParameter('operation', itemIndex);
|
|
2487
|
+
const ctx = {
|
|
2488
|
+
node: this,
|
|
2489
|
+
items,
|
|
2490
|
+
itemIndex,
|
|
2491
|
+
operation,
|
|
2492
|
+
};
|
|
2493
|
+
const config = await buildRequestConfig(ctx);
|
|
2494
|
+
const requestOptions = {
|
|
2495
|
+
url: `${API_BASE_URL}${config.endpoint}`,
|
|
2496
|
+
method: config.method,
|
|
2497
|
+
};
|
|
2498
|
+
if (config.headers) {
|
|
2499
|
+
requestOptions.headers = config.headers;
|
|
2321
2500
|
}
|
|
2322
|
-
if (
|
|
2323
|
-
|
|
2324
|
-
const redditSubreddit = this.getNodeParameter('redditSubreddit', i);
|
|
2325
|
-
formData.subreddit = redditSubreddit;
|
|
2326
|
-
const redditFlairId = this.getNodeParameter('redditFlairId', i, '');
|
|
2327
|
-
if (redditFlairId)
|
|
2328
|
-
formData.flair_id = redditFlairId;
|
|
2329
|
-
}
|
|
2501
|
+
if (config.qs) {
|
|
2502
|
+
requestOptions.qs = config.qs;
|
|
2330
2503
|
}
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
if (operation === 'validateJwt') {
|
|
2337
|
-
const jwt = this.getNodeParameter('jwtToken', i);
|
|
2338
|
-
options.headers = { Authorization: `Bearer ${jwt}` };
|
|
2504
|
+
if (config.formData) {
|
|
2505
|
+
const multipartPayload = buildMultipartPayload(config.formData);
|
|
2506
|
+
const nativeFormData = buildNativeFormData(multipartPayload, this);
|
|
2507
|
+
requestOptions.body = nativeFormData;
|
|
2508
|
+
requestOptions.json = false;
|
|
2339
2509
|
}
|
|
2340
|
-
if (
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
for (const [key, value] of Object.entries(formData)) {
|
|
2344
|
-
if (value !== undefined && value !== null) {
|
|
2345
|
-
if (Array.isArray(value)) {
|
|
2346
|
-
for (const item of value) {
|
|
2347
|
-
if (item !== undefined && item !== null) {
|
|
2348
|
-
if (typeof item === 'string') {
|
|
2349
|
-
formDataObj.append(key, item);
|
|
2350
|
-
}
|
|
2351
|
-
else if (item && typeof item === 'object' && 'value' in item && 'options' in item) {
|
|
2352
|
-
const binaryValue = item;
|
|
2353
|
-
formDataObj.append(key, binaryValue.value, binaryValue.options);
|
|
2354
|
-
}
|
|
2355
|
-
else {
|
|
2356
|
-
formDataObj.append(key, String(item));
|
|
2357
|
-
}
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
else if (value && typeof value === 'object' && 'value' in value && 'options' in value) {
|
|
2362
|
-
const binaryValue = value;
|
|
2363
|
-
formDataObj.append(key, binaryValue.value, binaryValue.options);
|
|
2364
|
-
}
|
|
2365
|
-
else {
|
|
2366
|
-
formDataObj.append(key, String(value));
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
}
|
|
2370
|
-
options.body = formDataObj;
|
|
2371
|
-
if (!options.headers)
|
|
2372
|
-
options.headers = {};
|
|
2373
|
-
}
|
|
2374
|
-
else {
|
|
2375
|
-
options.body = body;
|
|
2376
|
-
}
|
|
2510
|
+
else if (config.body) {
|
|
2511
|
+
requestOptions.body = config.body;
|
|
2512
|
+
requestOptions.json = true;
|
|
2377
2513
|
}
|
|
2378
|
-
else
|
|
2379
|
-
|
|
2380
|
-
options.body = body;
|
|
2381
|
-
}
|
|
2382
|
-
else {
|
|
2383
|
-
options.qs = qs;
|
|
2384
|
-
}
|
|
2514
|
+
else {
|
|
2515
|
+
requestOptions.json = true;
|
|
2385
2516
|
}
|
|
2386
|
-
this.
|
|
2387
|
-
const responseData =
|
|
2388
|
-
const shouldConsiderPolling = operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText';
|
|
2389
|
-
const waitForCompletion = shouldConsiderPolling ? this.getNodeParameter('waitForCompletion', i, false) : false;
|
|
2517
|
+
const rawResponse = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', requestOptions);
|
|
2518
|
+
const responseData = parseJsonIfNeeded(rawResponse);
|
|
2390
2519
|
let finalData = responseData;
|
|
2391
|
-
if (
|
|
2392
|
-
const
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
const start = Date.now();
|
|
2398
|
-
while (true) {
|
|
2399
|
-
await (0, n8n_workflow_1.sleep)(Math.max(1, pollIntervalSec) * 1000);
|
|
2400
|
-
if (Date.now() - start > Math.max(5, pollTimeoutSec) * 1000) {
|
|
2401
|
-
finalData = { success: false, message: 'Polling timed out', request_id: requestId };
|
|
2402
|
-
break;
|
|
2403
|
-
}
|
|
2404
|
-
const statusOptions = {
|
|
2405
|
-
url: `https://api.upload-post.com/api/uploadposts/status`,
|
|
2406
|
-
method: 'GET',
|
|
2407
|
-
qs: { request_id: requestId },
|
|
2408
|
-
json: true,
|
|
2409
|
-
};
|
|
2410
|
-
const statusData = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', statusOptions);
|
|
2411
|
-
finalData = statusData;
|
|
2412
|
-
const statusValue = (statusData && statusData.status);
|
|
2413
|
-
if (statusData.success === true || (statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
|
|
2414
|
-
break;
|
|
2415
|
-
}
|
|
2416
|
-
}
|
|
2520
|
+
if (config.isUploadOperation && config.waitForCompletion) {
|
|
2521
|
+
const requestId = responseData && responseData.request_id
|
|
2522
|
+
? responseData.request_id
|
|
2523
|
+
: undefined;
|
|
2524
|
+
if (requestId) {
|
|
2525
|
+
finalData = await pollUploadStatus(this, requestId, (_a = config.pollInterval) !== null && _a !== void 0 ? _a : 10, (_b = config.pollTimeout) !== null && _b !== void 0 ? _b : 600);
|
|
2417
2526
|
}
|
|
2418
2527
|
}
|
|
2419
2528
|
returnData.push({
|
|
2420
2529
|
json: finalData,
|
|
2421
|
-
pairedItem: {
|
|
2422
|
-
item: i,
|
|
2423
|
-
},
|
|
2530
|
+
pairedItem: { item: itemIndex },
|
|
2424
2531
|
});
|
|
2425
2532
|
}
|
|
2426
2533
|
return [returnData];
|