n8n-nodes-upload-post 0.1.15 → 0.1.17

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,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UploadPost = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
4
5
  class UploadPost {
5
6
  constructor() {
6
7
  this.description = {
@@ -23,32 +24,61 @@ class UploadPost {
23
24
  },
24
25
  ],
25
26
  properties: [
27
+ {
28
+ displayName: 'Resource',
29
+ name: 'resource',
30
+ type: 'options',
31
+ noDataExpression: true,
32
+ options: [
33
+ { name: 'Upload', value: 'uploads' },
34
+ { name: 'Status & History', value: 'monitoring' },
35
+ { name: 'User', value: 'users' },
36
+ ],
37
+ default: 'uploads',
38
+ },
26
39
  {
27
40
  displayName: 'Operation',
28
41
  name: 'operation',
29
42
  type: 'options',
30
43
  noDataExpression: true,
31
44
  options: [
32
- {
33
- name: 'Upload Photo(s)',
34
- value: 'uploadPhotos',
35
- action: 'Upload photos',
36
- description: 'Upload one or more photos (Supports: TikTok, Instagram, LinkedIn, Facebook, X, Threads)',
37
- },
38
- {
39
- name: 'Upload Video',
40
- value: 'uploadVideo',
41
- action: 'Upload a video',
42
- description: 'Upload a single video (Supports: TikTok, Instagram, LinkedIn, YouTube, Facebook, X, Threads)',
43
- },
44
- {
45
- name: 'Upload Text',
46
- value: 'uploadText',
47
- action: 'Upload a text post',
48
- description: 'Upload a text-based post (Supports: X, LinkedIn, Facebook, Threads)',
49
- },
45
+ { name: 'Upload Photo(s)', value: 'uploadPhotos', action: 'Upload photos', description: 'Upload one or more photos (Supports: TikTok, Instagram, LinkedIn, Facebook, X, Threads)' },
46
+ { name: 'Upload Text', value: 'uploadText', action: 'Upload a text post', description: 'Upload a text-based post (Supports: X, LinkedIn, Facebook, Threads)' },
47
+ { name: 'Upload Video', value: 'uploadVideo', action: 'Upload a video', description: 'Upload a single video (Supports: TikTok, Instagram, LinkedIn, YouTube, Facebook, X, Threads)' },
50
48
  ],
51
49
  default: 'uploadPhotos',
50
+ displayOptions: { show: { resource: ['uploads'] } },
51
+ },
52
+ {
53
+ displayName: 'Operation',
54
+ name: 'operation',
55
+ type: 'options',
56
+ noDataExpression: true,
57
+ options: [
58
+ { name: 'Cancel Scheduled Post', value: 'cancelScheduled', action: 'Cancel scheduled post', description: 'Cancel a scheduled post by its job ID' },
59
+ { name: 'Edit Scheduled Post', value: 'editScheduled', action: 'Edit scheduled post', description: 'Edit schedule details (like date/time) by job ID' },
60
+ { name: 'Get Analytics', value: 'getAnalytics', action: 'Get analytics', description: 'Retrieve aggregated analytics for uploads' },
61
+ { name: 'Get Upload History', value: 'getHistory', action: 'Get upload history', description: 'List past uploads with optional filters' },
62
+ { name: 'Get Upload Status', value: 'getStatus', action: 'Get upload status', description: 'Check the status of an upload using the request_id' },
63
+ { name: 'List Scheduled Posts', value: 'listScheduled', action: 'List scheduled posts', description: 'List your scheduled (future) posts' },
64
+ ],
65
+ default: 'getStatus',
66
+ displayOptions: { show: { resource: ['monitoring'] } },
67
+ },
68
+ {
69
+ displayName: 'Operation',
70
+ name: 'operation',
71
+ type: 'options',
72
+ noDataExpression: true,
73
+ options: [
74
+ { name: 'Create User', value: 'createUser', action: 'Create user', description: 'Create a new Upload-Post user (profile name)' },
75
+ { name: 'Delete User', value: 'deleteUser', action: 'Delete user', description: 'Delete an existing Upload-Post user by profile name' },
76
+ { name: 'Generate JWT (for Platform Integration)', value: 'generateJwt', action: 'Generate jwt for platform integration', description: 'Generate a connection URL (JWT) for a profile. Only needed when integrating Upload-Post into your own platform.' },
77
+ { name: 'List Users', value: 'listUsers', action: 'List users', description: 'List Upload-Post users (profiles)' },
78
+ { name: 'Validate JWT (for Platform Integration)', value: 'validateJwt', action: 'Validate jwt for platform integration', description: 'Validate a connection token from your backend. Only needed for custom platform integration.' },
79
+ ],
80
+ default: 'listUsers',
81
+ displayOptions: { show: { resource: ['users'] } },
52
82
  },
53
83
  {
54
84
  displayName: 'User Identifier',
@@ -57,6 +87,12 @@ class UploadPost {
57
87
  required: true,
58
88
  default: '',
59
89
  description: 'The Profile Name you created in your upload-post.com account. You can find it in the \'Manage Users\' section (e.g., app.upload-post.com/manage-users).',
90
+ displayOptions: {
91
+ show: {
92
+ resource: ['uploads', 'users'],
93
+ operation: ['uploadPhotos', 'uploadVideo', 'uploadText', 'generateJwt']
94
+ }
95
+ },
60
96
  },
61
97
  {
62
98
  displayName: 'Platform(s)',
@@ -75,18 +111,7 @@ class UploadPost {
75
111
  ],
76
112
  default: [],
77
113
  description: 'Platform(s) to upload to. Supported platforms vary by operation.',
78
- },
79
- {
80
- displayName: 'Pinterest Board ID',
81
- name: 'pinterestBoardId',
82
- type: 'string',
83
- default: '',
84
- description: 'Target Pinterest board ID. Required when Pinterest is selected.',
85
- displayOptions: {
86
- show: {
87
- platform: ['pinterest']
88
- },
89
- },
114
+ displayOptions: { show: { resource: ['uploads'], operation: ['uploadPhotos', 'uploadVideo', 'uploadText'] } },
90
115
  },
91
116
  {
92
117
  displayName: 'Title / Main Content',
@@ -95,13 +120,63 @@ class UploadPost {
95
120
  required: true,
96
121
  default: '',
97
122
  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.',
123
+ displayOptions: { show: { resource: ['uploads'], operation: ['uploadPhotos', 'uploadVideo', 'uploadText'] } },
98
124
  },
99
125
  {
100
- displayName: 'Scheduled Date',
101
- name: 'scheduledDate',
102
- type: 'dateTime',
126
+ displayName: 'Instagram Title (Override)',
127
+ name: 'instagramTitle',
128
+ type: 'string',
103
129
  default: '',
104
- description: 'Optional scheduling date/time. If set, the API will schedule the publication instead of posting immediately.',
130
+ description: 'Optional override for Instagram title',
131
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['instagram'] } },
132
+ },
133
+ {
134
+ displayName: 'Facebook Title (Override)',
135
+ name: 'facebookTitle',
136
+ type: 'string',
137
+ default: '',
138
+ description: 'Optional override for Facebook title',
139
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['facebook'] } },
140
+ },
141
+ {
142
+ displayName: 'TikTok Title (Override)',
143
+ name: 'tiktokTitle',
144
+ type: 'string',
145
+ default: '',
146
+ description: 'Optional override for TikTok title',
147
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['tiktok'] } },
148
+ },
149
+ {
150
+ displayName: 'LinkedIn Title (Override)',
151
+ name: 'linkedinTitle',
152
+ type: 'string',
153
+ default: '',
154
+ description: 'Optional override for LinkedIn title',
155
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['linkedin'] } },
156
+ },
157
+ {
158
+ displayName: 'X Title (Override)',
159
+ name: 'xTitle',
160
+ type: 'string',
161
+ default: '',
162
+ description: 'Optional override for X title',
163
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['x'] } },
164
+ },
165
+ {
166
+ displayName: 'YouTube Title (Override)',
167
+ name: 'youtubeTitle',
168
+ type: 'string',
169
+ default: '',
170
+ description: 'Optional override for YouTube title',
171
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['youtube'] } },
172
+ },
173
+ {
174
+ displayName: 'Pinterest Title (Override)',
175
+ name: 'pinterestTitle',
176
+ type: 'string',
177
+ default: '',
178
+ description: 'Optional override for Pinterest title',
179
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['pinterest'] } },
105
180
  },
106
181
  {
107
182
  displayName: 'Photos (Files or URLs)',
@@ -117,17 +192,81 @@ class UploadPost {
117
192
  },
118
193
  },
119
194
  {
120
- displayName: 'Caption (Photo/Video Commentary)',
121
- name: 'caption',
195
+ displayName: 'Description (Optional)',
196
+ name: 'description',
122
197
  type: 'string',
123
198
  default: '',
124
- description: 'General caption/commentary for Photo or Video posts. For some video platforms, a specific \'Description\' field might be used instead (see platform-specific options). Not used for Upload Text.',
199
+ description: 'Generic description to use across platforms when supported. Platform-specific overrides below take precedence.',
125
200
  displayOptions: {
126
201
  show: {
127
- operation: ['uploadPhotos', 'uploadVideo'],
128
- },
202
+ operation: ['uploadPhotos', 'uploadVideo']
203
+ }
129
204
  },
130
205
  },
206
+ {
207
+ displayName: 'Instagram Description (Override)',
208
+ name: 'instagramDescription',
209
+ type: 'string',
210
+ default: '',
211
+ description: 'Optional description override for Instagram',
212
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['instagram'] } },
213
+ },
214
+ {
215
+ displayName: 'Facebook Description (Override)',
216
+ name: 'facebookDescription',
217
+ type: 'string',
218
+ default: '',
219
+ description: 'Optional description override for Facebook',
220
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['facebook'] } },
221
+ },
222
+ {
223
+ displayName: 'TikTok Description (Override)',
224
+ name: 'tiktokDescription',
225
+ type: 'string',
226
+ default: '',
227
+ description: 'Optional description override for TikTok',
228
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['tiktok'] } },
229
+ },
230
+ {
231
+ displayName: 'LinkedIn Description (Override)',
232
+ name: 'linkedinDescription',
233
+ type: 'string',
234
+ default: '',
235
+ description: 'Optional description override for LinkedIn',
236
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['linkedin'] } },
237
+ },
238
+ {
239
+ displayName: 'X Description (Override)',
240
+ name: 'xDescription',
241
+ type: 'string',
242
+ default: '',
243
+ description: 'Optional description override for X',
244
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['x'] } },
245
+ },
246
+ {
247
+ displayName: 'YouTube Description (Override)',
248
+ name: 'youtubeDescription',
249
+ type: 'string',
250
+ default: '',
251
+ description: 'Optional description override for YouTube',
252
+ displayOptions: { show: { operation: ['uploadVideo'], platform: ['youtube'] } },
253
+ },
254
+ {
255
+ displayName: 'Pinterest Description (Override)',
256
+ name: 'pinterestDescription',
257
+ type: 'string',
258
+ default: '',
259
+ description: 'Optional description override for Pinterest',
260
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['pinterest'] } },
261
+ },
262
+ {
263
+ displayName: 'Threads Description (Override)',
264
+ name: 'threadsDescription',
265
+ type: 'string',
266
+ default: '',
267
+ description: 'Optional description override for Threads',
268
+ displayOptions: { show: { operation: ['uploadVideo'], platform: ['threads'] } },
269
+ },
131
270
  {
132
271
  displayName: 'Video (File or URL)',
133
272
  name: 'video',
@@ -141,6 +280,213 @@ class UploadPost {
141
280
  },
142
281
  },
143
282
  },
283
+ {
284
+ displayName: 'Scheduled Date',
285
+ name: 'scheduledDate',
286
+ type: 'dateTime',
287
+ default: '',
288
+ description: 'Optional scheduling date/time. If set, the API will schedule the publication instead of posting immediately.',
289
+ displayOptions: { show: { resource: ['uploads'], operation: ['uploadPhotos', 'uploadVideo', 'uploadText'] } },
290
+ },
291
+ {
292
+ displayName: 'Upload Asynchronously',
293
+ name: 'uploadAsync',
294
+ type: 'boolean',
295
+ default: true,
296
+ description: 'Whether to process the upload asynchronously and return immediately. If you set to false but the upload takes longer than 59 seconds, it will automatically switch to asynchronous processing to avoid timeouts. In that case, use the request_id with the Upload Status endpoint to check the upload status and result.',
297
+ displayOptions: {
298
+ show: {
299
+ operation: ['uploadPhotos', 'uploadVideo', 'uploadText']
300
+ }
301
+ },
302
+ },
303
+ {
304
+ displayName: 'Wait for Completion',
305
+ name: 'waitForCompletion',
306
+ type: 'boolean',
307
+ default: false,
308
+ description: 'Whether to perform best-effort sleeping between status checks within this node. Not guaranteed to finish; for reliable long polling use a separate Wait node plus Get Upload Status.',
309
+ displayOptions: {
310
+ show: {
311
+ operation: ['uploadPhotos', 'uploadVideo', 'uploadText']
312
+ }
313
+ },
314
+ },
315
+ {
316
+ displayName: 'Poll Interval (Seconds)',
317
+ name: 'pollInterval',
318
+ type: 'number',
319
+ default: 10,
320
+ description: 'Sleep interval between status checks when waiting for completion',
321
+ displayOptions: {
322
+ show: {
323
+ operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
324
+ waitForCompletion: [true]
325
+ }
326
+ },
327
+ },
328
+ {
329
+ displayName: 'Timeout (Seconds)',
330
+ name: 'pollTimeout',
331
+ type: 'number',
332
+ default: 600,
333
+ description: 'Maximum time to sleep-and-check before giving up inside this node',
334
+ displayOptions: {
335
+ show: {
336
+ operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
337
+ waitForCompletion: [true]
338
+ }
339
+ },
340
+ },
341
+ {
342
+ displayName: 'Request ID',
343
+ name: 'requestId',
344
+ type: 'string',
345
+ required: true,
346
+ default: '',
347
+ description: 'The request_id returned by an async upload to query its status',
348
+ displayOptions: {
349
+ show: {
350
+ operation: ['getStatus']
351
+ }
352
+ },
353
+ },
354
+ {
355
+ displayName: 'Page',
356
+ name: 'historyPage',
357
+ type: 'number',
358
+ default: 1,
359
+ description: 'Page number for pagination',
360
+ displayOptions: {
361
+ show: {
362
+ operation: ['getHistory']
363
+ }
364
+ },
365
+ },
366
+ {
367
+ displayName: 'Limit',
368
+ name: 'historyLimit',
369
+ type: 'number',
370
+ default: 20,
371
+ description: 'Items per page. Can be 20, 50, or 100.',
372
+ displayOptions: {
373
+ show: {
374
+ operation: ['getHistory']
375
+ }
376
+ },
377
+ },
378
+ {
379
+ displayName: 'Job ID',
380
+ name: 'scheduleJobId',
381
+ type: 'string',
382
+ default: '',
383
+ description: 'Scheduled job identifier',
384
+ displayOptions: { show: { operation: ['cancelScheduled', 'editScheduled'] } },
385
+ },
386
+ {
387
+ displayName: 'Profile Username',
388
+ name: 'analyticsProfileUsername',
389
+ type: 'string',
390
+ required: true,
391
+ default: '',
392
+ description: 'Profile username to fetch analytics for',
393
+ displayOptions: { show: { operation: ['getAnalytics'] } },
394
+ },
395
+ {
396
+ displayName: 'New Scheduled Date',
397
+ name: 'newScheduledDate',
398
+ type: 'dateTime',
399
+ default: '',
400
+ description: 'New scheduled date/time for the post',
401
+ displayOptions: { show: { operation: ['editScheduled'] } },
402
+ },
403
+ {
404
+ displayName: 'Platforms (Optional)',
405
+ name: 'analyticsPlatforms',
406
+ type: 'multiOptions',
407
+ options: [
408
+ { name: 'Instagram', value: 'instagram' },
409
+ { name: 'LinkedIn', value: 'linkedin' },
410
+ { name: 'Facebook', value: 'facebook' },
411
+ { name: 'X (Twitter)', value: 'x' },
412
+ ],
413
+ default: [],
414
+ description: 'Platforms to fetch analytics for (comma-joined in request)',
415
+ displayOptions: { show: { operation: ['getAnalytics'] } },
416
+ },
417
+ {
418
+ displayName: 'New User Identifier',
419
+ name: 'newUser',
420
+ type: 'string',
421
+ required: true,
422
+ default: '',
423
+ description: 'Profile name to create',
424
+ displayOptions: {
425
+ show: { operation: ['createUser'] }
426
+ },
427
+ },
428
+ {
429
+ displayName: 'User to Delete',
430
+ name: 'deleteUserId',
431
+ type: 'string',
432
+ required: true,
433
+ default: '',
434
+ description: 'Profile name to delete',
435
+ displayOptions: {
436
+ show: { operation: ['deleteUser'] }
437
+ },
438
+ },
439
+ {
440
+ displayName: 'Redirect URL',
441
+ name: 'redirectUrl',
442
+ type: 'string',
443
+ default: '',
444
+ description: 'Optional URL to redirect the user after linking their social account',
445
+ displayOptions: { show: { operation: ['generateJwt'] } },
446
+ },
447
+ {
448
+ displayName: 'Logo Image URL',
449
+ name: 'logoImage',
450
+ type: 'string',
451
+ default: '',
452
+ description: 'Optional logo image URL to show on the linking page',
453
+ displayOptions: { show: { operation: ['generateJwt'] } },
454
+ },
455
+ {
456
+ displayName: 'Redirect Button Text',
457
+ name: 'redirectButtonText',
458
+ type: 'string',
459
+ default: '',
460
+ description: 'Optional text for the redirect button after linking (default: "Logout connection")',
461
+ displayOptions: { show: { operation: ['generateJwt'] } },
462
+ },
463
+ {
464
+ displayName: 'Platforms (Optional)',
465
+ name: 'jwtPlatforms',
466
+ type: 'multiOptions',
467
+ options: [
468
+ { name: 'Facebook', value: 'facebook' },
469
+ { name: 'Instagram', value: 'instagram' },
470
+ { name: 'LinkedIn', value: 'linkedin' },
471
+ { name: 'Threads', value: 'threads' },
472
+ { name: 'TikTok', value: 'tiktok' },
473
+ { name: 'X (Twitter)', value: 'x' },
474
+ { name: 'YouTube', value: 'youtube' },
475
+ ],
476
+ default: [],
477
+ description: 'Optional list of platforms to show for connection. Defaults to all supported platforms.',
478
+ displayOptions: { show: { operation: ['generateJwt'] } },
479
+ },
480
+ {
481
+ displayName: 'JWT',
482
+ name: 'jwtToken',
483
+ type: 'string',
484
+ typeOptions: { password: true },
485
+ required: true,
486
+ default: '',
487
+ description: 'JWT to validate',
488
+ displayOptions: { show: { operation: ['validateJwt'] } },
489
+ },
144
490
  {
145
491
  displayName: 'LinkedIn Visibility',
146
492
  name: 'linkedinVisibility',
@@ -161,16 +507,17 @@ class UploadPost {
161
507
  },
162
508
  },
163
509
  {
164
- displayName: 'Target LinkedIn Page ID',
510
+ displayName: 'Target LinkedIn Page Name or ID',
165
511
  name: 'targetLinkedinPageId',
166
- type: 'string',
512
+ type: 'options',
167
513
  default: '',
168
- description: 'LinkedIn page ID to upload to an organization (optional). Used for Photos, Video, and Text operations.',
514
+ description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
515
+ typeOptions: { loadOptionsMethod: 'getLinkedinPages' },
169
516
  displayOptions: {
170
517
  show: {
171
518
  operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
172
519
  platform: ['linkedin']
173
- },
520
+ }
174
521
  },
175
522
  },
176
523
  {
@@ -187,17 +534,18 @@ class UploadPost {
187
534
  },
188
535
  },
189
536
  {
190
- displayName: 'Facebook Page ID',
537
+ displayName: 'Facebook Page Name or ID',
191
538
  name: 'facebookPageId',
192
- type: 'string',
539
+ type: 'options',
193
540
  required: true,
194
541
  default: '',
195
- description: 'Facebook Page ID. Required for Photos, Video, and Text operations.',
542
+ description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
543
+ typeOptions: { loadOptionsMethod: 'getFacebookPages' },
196
544
  displayOptions: {
197
545
  show: {
198
546
  operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
199
547
  platform: ['facebook']
200
- },
548
+ }
201
549
  },
202
550
  },
203
551
  {
@@ -244,6 +592,23 @@ class UploadPost {
244
592
  },
245
593
  },
246
594
  },
595
+ {
596
+ displayName: 'Facebook Media Type (Video)',
597
+ name: 'facebookMediaType',
598
+ type: 'options',
599
+ options: [
600
+ { name: 'Reels', value: 'REELS' },
601
+ { name: 'Stories', value: 'STORIES' },
602
+ ],
603
+ default: 'REELS',
604
+ description: 'Choose whether to post as Reels or Stories for Facebook video',
605
+ displayOptions: {
606
+ show: {
607
+ operation: ['uploadVideo'],
608
+ platform: ['facebook']
609
+ },
610
+ },
611
+ },
247
612
  {
248
613
  displayName: 'TikTok Auto Add Music (Photo)',
249
614
  name: 'tiktokAutoAddMusic',
@@ -443,7 +808,24 @@ class UploadPost {
443
808
  show: {
444
809
  operation: ['uploadVideo'],
445
810
  platform: ['tiktok']
446
- },
811
+ }
812
+ },
813
+ },
814
+ {
815
+ displayName: 'TikTok Post Mode (Video)',
816
+ name: 'tiktokPostMode',
817
+ type: 'options',
818
+ options: [
819
+ { name: 'Direct Post', value: 'DIRECT_POST' },
820
+ { name: 'Media Upload (Inbox)', value: 'MEDIA_UPLOAD' },
821
+ ],
822
+ default: 'DIRECT_POST',
823
+ description: 'Choose TikTok posting mode for video',
824
+ displayOptions: {
825
+ show: {
826
+ operation: ['uploadVideo'],
827
+ platform: ['tiktok']
828
+ }
447
829
  },
448
830
  },
449
831
  {
@@ -552,7 +934,7 @@ class UploadPost {
552
934
  show: {
553
935
  operation: ['uploadVideo'],
554
936
  platform: ['instagram']
555
- },
937
+ }
556
938
  },
557
939
  },
558
940
  {
@@ -681,6 +1063,91 @@ class UploadPost {
681
1063
  },
682
1064
  },
683
1065
  },
1066
+ {
1067
+ displayName: 'Pinterest Board Name or ID',
1068
+ name: 'pinterestBoardId',
1069
+ type: 'options',
1070
+ default: '',
1071
+ description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
1072
+ typeOptions: { loadOptionsMethod: 'getPinterestBoards' },
1073
+ displayOptions: {
1074
+ show: {
1075
+ resource: ['uploads'],
1076
+ platform: ['pinterest']
1077
+ },
1078
+ },
1079
+ },
1080
+ {
1081
+ displayName: 'Pinterest Link (Photo/Video)',
1082
+ name: 'pinterestLink',
1083
+ type: 'string',
1084
+ default: '',
1085
+ description: 'Optional link to attach to the Pinterest pin',
1086
+ displayOptions: {
1087
+ show: {
1088
+ operation: ['uploadPhotos', 'uploadVideo'],
1089
+ platform: ['pinterest']
1090
+ }
1091
+ },
1092
+ },
1093
+ {
1094
+ displayName: 'Pinterest Cover Image URL (Video)',
1095
+ name: 'pinterestCoverImageUrl',
1096
+ type: 'string',
1097
+ default: '',
1098
+ description: 'Optional cover image URL for Pinterest video. If provided, overrides other cover options.',
1099
+ displayOptions: {
1100
+ show: {
1101
+ operation: ['uploadVideo'],
1102
+ platform: ['pinterest']
1103
+ }
1104
+ },
1105
+ },
1106
+ {
1107
+ displayName: 'Pinterest Cover Image Content Type (Video)',
1108
+ name: 'pinterestCoverImageContentType',
1109
+ type: 'options',
1110
+ options: [
1111
+ { name: 'JPEG', value: 'image/jpeg' },
1112
+ { name: 'PNG', value: 'image/png' },
1113
+ { name: 'GIF', value: 'image/gif' },
1114
+ { name: 'BMP', value: 'image/bmp' },
1115
+ ],
1116
+ default: 'image/jpeg',
1117
+ description: 'MIME type for the cover image when providing raw base64 data',
1118
+ displayOptions: {
1119
+ show: {
1120
+ operation: ['uploadVideo'],
1121
+ platform: ['pinterest']
1122
+ }
1123
+ },
1124
+ },
1125
+ {
1126
+ displayName: 'Pinterest Cover Image Data (Base64, Video)',
1127
+ name: 'pinterestCoverImageData',
1128
+ type: 'string',
1129
+ default: '',
1130
+ description: 'Base64-encoded image bytes for the cover image. Used if URL is not provided.',
1131
+ displayOptions: {
1132
+ show: {
1133
+ operation: ['uploadVideo'],
1134
+ platform: ['pinterest']
1135
+ }
1136
+ },
1137
+ },
1138
+ {
1139
+ displayName: 'Pinterest Cover Image Key Frame Time (MS, Video)',
1140
+ name: 'pinterestCoverImageKeyFrameTime',
1141
+ type: 'number',
1142
+ default: 0,
1143
+ description: 'Key frame time to use as the cover image if no image is provided',
1144
+ displayOptions: {
1145
+ show: {
1146
+ operation: ['uploadVideo'],
1147
+ platform: ['pinterest']
1148
+ }
1149
+ },
1150
+ },
684
1151
  {
685
1152
  displayName: 'Threads Video Description',
686
1153
  name: 'threadsDescription',
@@ -808,8 +1275,115 @@ class UploadPost {
808
1275
  },
809
1276
  },
810
1277
  },
1278
+ {
1279
+ displayName: 'X Long Text as Single Post',
1280
+ name: 'xLongTextAsPost',
1281
+ type: 'boolean',
1282
+ default: false,
1283
+ description: 'Whether to post long text as a single post instead of splitting into a thread (if supported)',
1284
+ displayOptions: {
1285
+ show: {
1286
+ operation: ['uploadVideo', 'uploadText'],
1287
+ platform: ['x']
1288
+ },
1289
+ },
1290
+ },
1291
+ {
1292
+ displayName: 'Description (Optional)',
1293
+ name: 'description',
1294
+ type: 'string',
1295
+ default: '',
1296
+ description: 'Generic description to use across platforms when supported. Platform-specific overrides below take precedence.',
1297
+ displayOptions: {
1298
+ show: {
1299
+ operation: ['uploadPhotos', 'uploadVideo']
1300
+ }
1301
+ },
1302
+ },
1303
+ {
1304
+ displayName: 'LinkedIn Description (Override)',
1305
+ name: 'linkedinDescription',
1306
+ type: 'string',
1307
+ default: '',
1308
+ description: 'Optional description override for LinkedIn',
1309
+ displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo'], platform: ['linkedin'] } },
1310
+ },
1311
+ {
1312
+ displayName: 'YouTube Description (Override)',
1313
+ name: 'youtubeDescription',
1314
+ type: 'string',
1315
+ default: '',
1316
+ description: 'Optional description override for YouTube',
1317
+ displayOptions: { show: { operation: ['uploadVideo'], platform: ['youtube'] } },
1318
+ },
1319
+ {
1320
+ displayName: 'Threads Description (Override)',
1321
+ name: 'threadsDescription',
1322
+ type: 'string',
1323
+ default: '',
1324
+ description: 'Optional description override for Threads',
1325
+ displayOptions: { show: { operation: ['uploadVideo'], platform: ['threads'] } },
1326
+ },
811
1327
  ],
812
1328
  };
1329
+ this.methods = {
1330
+ loadOptions: {
1331
+ async getFacebookPages() {
1332
+ const credentials = await this.getCredentials('uploadPostApi');
1333
+ const apiKey = credentials.apiKey;
1334
+ const profile = this.getCurrentNodeParameter('user') || '';
1335
+ const qs = {};
1336
+ if (profile)
1337
+ qs.profile = profile;
1338
+ const options = {
1339
+ uri: 'https://api.upload-post.com/api/uploadposts/facebook/pages',
1340
+ method: 'GET',
1341
+ headers: { Authorization: `ApiKey ${apiKey}` },
1342
+ qs,
1343
+ json: true,
1344
+ };
1345
+ const resp = await this.helpers.request(options);
1346
+ const pages = (resp && (resp.pages || resp.data || []));
1347
+ return (pages || []).map(p => ({ name: p.name ? `${p.name} (${p.id})` : p.id, value: p.id }));
1348
+ },
1349
+ async getLinkedinPages() {
1350
+ const credentials = await this.getCredentials('uploadPostApi');
1351
+ const apiKey = credentials.apiKey;
1352
+ const profile = this.getCurrentNodeParameter('user') || '';
1353
+ const qs = {};
1354
+ if (profile)
1355
+ qs.profile = profile;
1356
+ const options = {
1357
+ uri: 'https://api.upload-post.com/api/uploadposts/linkedin/pages',
1358
+ method: 'GET',
1359
+ headers: { Authorization: `ApiKey ${apiKey}` },
1360
+ qs,
1361
+ json: true,
1362
+ };
1363
+ const resp = await this.helpers.request(options);
1364
+ const pages = (resp && (resp.pages || resp.data || []));
1365
+ return (pages || []).map(p => ({ name: p.name ? `${p.name} (${p.id})` : p.id, value: p.id }));
1366
+ },
1367
+ async getPinterestBoards() {
1368
+ const credentials = await this.getCredentials('uploadPostApi');
1369
+ const apiKey = credentials.apiKey;
1370
+ const profile = this.getCurrentNodeParameter('user') || '';
1371
+ const qs = {};
1372
+ if (profile)
1373
+ qs.profile = profile;
1374
+ const options = {
1375
+ uri: 'https://api.upload-post.com/api/uploadposts/pinterest/boards',
1376
+ method: 'GET',
1377
+ headers: { Authorization: `ApiKey ${apiKey}` },
1378
+ qs,
1379
+ json: true,
1380
+ };
1381
+ const resp = await this.helpers.request(options);
1382
+ const boards = (resp && (resp.boards || resp.data || []));
1383
+ return (boards || []).map(b => ({ name: b.name ? `${b.name} (${b.id})` : b.id, value: b.id }));
1384
+ },
1385
+ },
1386
+ };
813
1387
  }
814
1388
  async execute() {
815
1389
  var _a, _b, _c;
@@ -817,26 +1391,163 @@ class UploadPost {
817
1391
  const returnData = [];
818
1392
  for (let i = 0; i < items.length; i++) {
819
1393
  const operation = this.getNodeParameter('operation', i);
820
- const user = this.getNodeParameter('user', i);
821
- let platforms = this.getNodeParameter('platform', i);
822
- const title = this.getNodeParameter('title', i);
1394
+ const isUploadOperation = ['uploadPhotos', 'uploadVideo', 'uploadText'].includes(operation);
1395
+ const needsUser = isUploadOperation || operation === 'generateJwt';
1396
+ const user = needsUser ? this.getNodeParameter('user', i) : '';
1397
+ let platforms = isUploadOperation ? this.getNodeParameter('platform', i) : [];
1398
+ const title = isUploadOperation ? this.getNodeParameter('title', i) : '';
823
1399
  let endpoint = '';
1400
+ let method = 'POST';
824
1401
  const formData = {};
825
- formData.user = user;
826
- formData.title = title;
827
- const scheduledDate = this.getNodeParameter('scheduledDate', i);
828
- if (scheduledDate) {
829
- let normalizedDate = scheduledDate;
830
- const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
831
- if (!hasTimezone) {
832
- normalizedDate = `${normalizedDate}Z`;
1402
+ const qs = {};
1403
+ const body = {};
1404
+ if (isUploadOperation) {
1405
+ formData.user = user;
1406
+ formData.title = title;
1407
+ const scheduledDate = this.getNodeParameter('scheduledDate', i);
1408
+ if (scheduledDate) {
1409
+ let normalizedDate = scheduledDate;
1410
+ const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
1411
+ if (!hasTimezone) {
1412
+ normalizedDate = `${normalizedDate}Z`;
1413
+ }
1414
+ formData.scheduled_date = normalizedDate;
1415
+ }
1416
+ const uploadAsync = this.getNodeParameter('uploadAsync', i);
1417
+ if (uploadAsync !== undefined) {
1418
+ formData.async_upload = String(uploadAsync);
1419
+ }
1420
+ }
1421
+ if (isUploadOperation) {
1422
+ try {
1423
+ if (platforms.includes('instagram')) {
1424
+ const instagramTitle = this.getNodeParameter('instagramTitle', i, '');
1425
+ if (instagramTitle)
1426
+ formData.instagram_title = instagramTitle;
1427
+ }
1428
+ }
1429
+ catch { }
1430
+ try {
1431
+ if (platforms.includes('facebook')) {
1432
+ const facebookTitle = this.getNodeParameter('facebookTitle', i, '');
1433
+ if (facebookTitle)
1434
+ formData.facebook_title = facebookTitle;
1435
+ }
1436
+ }
1437
+ catch { }
1438
+ try {
1439
+ if (platforms.includes('tiktok')) {
1440
+ const tiktokTitle = this.getNodeParameter('tiktokTitle', i, '');
1441
+ if (tiktokTitle)
1442
+ formData.tiktok_title = tiktokTitle;
1443
+ }
1444
+ }
1445
+ catch { }
1446
+ try {
1447
+ if (platforms.includes('linkedin')) {
1448
+ const linkedinTitle = this.getNodeParameter('linkedinTitle', i, '');
1449
+ if (linkedinTitle)
1450
+ formData.linkedin_title = linkedinTitle;
1451
+ }
1452
+ }
1453
+ catch { }
1454
+ try {
1455
+ if (platforms.includes('x')) {
1456
+ const xTitle = this.getNodeParameter('xTitle', i, '');
1457
+ if (xTitle)
1458
+ formData.x_title = xTitle;
1459
+ }
1460
+ }
1461
+ catch { }
1462
+ try {
1463
+ if (platforms.includes('youtube')) {
1464
+ const youtubeTitle = this.getNodeParameter('youtubeTitle', i, '');
1465
+ if (youtubeTitle)
1466
+ formData.youtube_title = youtubeTitle;
1467
+ }
1468
+ }
1469
+ catch { }
1470
+ try {
1471
+ if (platforms.includes('pinterest')) {
1472
+ const pinterestTitle = this.getNodeParameter('pinterestTitle', i, '');
1473
+ if (pinterestTitle)
1474
+ formData.pinterest_title = pinterestTitle;
1475
+ }
1476
+ }
1477
+ catch { }
1478
+ }
1479
+ if (isUploadOperation) {
1480
+ const genericDescription = this.getNodeParameter('description', i, '');
1481
+ if (genericDescription)
1482
+ formData.description = genericDescription;
1483
+ try {
1484
+ if (platforms.includes('linkedin')) {
1485
+ const linkedinDescription = this.getNodeParameter('linkedinDescription', i, '');
1486
+ if (linkedinDescription)
1487
+ formData.linkedin_description = linkedinDescription;
1488
+ }
1489
+ }
1490
+ catch { }
1491
+ try {
1492
+ if (platforms.includes('youtube')) {
1493
+ const youtubeDescription = this.getNodeParameter('youtubeDescription', i, '');
1494
+ if (youtubeDescription)
1495
+ formData.youtube_description = youtubeDescription;
1496
+ }
1497
+ }
1498
+ catch { }
1499
+ try {
1500
+ if (platforms.includes('threads')) {
1501
+ const threadsDescription = this.getNodeParameter('threadsDescription', i, '');
1502
+ if (threadsDescription)
1503
+ formData.threads_description = threadsDescription;
1504
+ }
833
1505
  }
834
- formData.scheduled_date = normalizedDate;
1506
+ catch { }
1507
+ try {
1508
+ if (platforms.includes('facebook')) {
1509
+ const facebookDescription = this.getNodeParameter('facebookDescription', i, '');
1510
+ if (facebookDescription)
1511
+ formData.facebook_description = facebookDescription;
1512
+ }
1513
+ }
1514
+ catch { }
1515
+ try {
1516
+ if (platforms.includes('instagram')) {
1517
+ const instagramDescription = this.getNodeParameter('instagramDescription', i, '');
1518
+ if (instagramDescription)
1519
+ formData.instagram_description = instagramDescription;
1520
+ }
1521
+ }
1522
+ catch { }
1523
+ try {
1524
+ if (platforms.includes('tiktok')) {
1525
+ const tiktokDescription = this.getNodeParameter('tiktokDescription', i, '');
1526
+ if (tiktokDescription)
1527
+ formData.tiktok_description = tiktokDescription;
1528
+ }
1529
+ }
1530
+ catch { }
1531
+ try {
1532
+ if (platforms.includes('x')) {
1533
+ const xDescription = this.getNodeParameter('xDescription', i, '');
1534
+ if (xDescription)
1535
+ formData.x_description = xDescription;
1536
+ }
1537
+ }
1538
+ catch { }
1539
+ try {
1540
+ if (platforms.includes('pinterest')) {
1541
+ const pinterestDescription = this.getNodeParameter('pinterestDescription', i, '');
1542
+ if (pinterestDescription)
1543
+ formData.pinterest_description = pinterestDescription;
1544
+ }
1545
+ }
1546
+ catch { }
835
1547
  }
836
1548
  switch (operation) {
837
1549
  case 'uploadPhotos':
838
1550
  endpoint = '/upload_photos';
839
- const photoCaption = this.getNodeParameter('caption', i);
840
1551
  let photosInput = this.getNodeParameter('photos', i, []);
841
1552
  let photosToProcess;
842
1553
  if (typeof photosInput === 'string') {
@@ -845,7 +1556,7 @@ class UploadPost {
845
1556
  else {
846
1557
  photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim() !== '');
847
1558
  }
848
- const allowedPhotoPlatforms = ['tiktok', 'instagram', 'linkedin', 'facebook', 'x', 'threads'];
1559
+ const allowedPhotoPlatforms = ['tiktok', 'instagram', 'linkedin', 'facebook', 'x', 'threads', 'pinterest'];
849
1560
  platforms = platforms.filter(p => allowedPhotoPlatforms.includes(p));
850
1561
  formData['platform[]'] = platforms;
851
1562
  if (photosToProcess.length > 0) {
@@ -878,8 +1589,6 @@ class UploadPost {
878
1589
  formData['photos[]'] = photoArray;
879
1590
  }
880
1591
  }
881
- if (photoCaption)
882
- formData.caption = photoCaption;
883
1592
  break;
884
1593
  case 'uploadVideo':
885
1594
  endpoint = '/upload';
@@ -916,16 +1625,133 @@ class UploadPost {
916
1625
  platforms = platforms.filter(p => allowedTextPlatforms.includes(p));
917
1626
  formData['platform[]'] = platforms;
918
1627
  break;
1628
+ case 'getStatus':
1629
+ method = 'GET';
1630
+ endpoint = '/uploadposts/status';
1631
+ qs.request_id = this.getNodeParameter('requestId', i);
1632
+ break;
1633
+ case 'getHistory':
1634
+ method = 'GET';
1635
+ endpoint = '/uploadposts/history';
1636
+ const historyPage = this.getNodeParameter('historyPage', i);
1637
+ qs.page = historyPage !== null && historyPage !== void 0 ? historyPage : 1;
1638
+ const historyLimit = this.getNodeParameter('historyLimit', i);
1639
+ qs.limit = historyLimit !== null && historyLimit !== void 0 ? historyLimit : 20;
1640
+ break;
1641
+ case 'getAnalytics':
1642
+ method = 'GET';
1643
+ {
1644
+ const analyticsPlatforms = this.getNodeParameter('analyticsPlatforms', i, []);
1645
+ const profileUsername = this.getNodeParameter('analyticsProfileUsername', i);
1646
+ endpoint = `/analytics/${encodeURIComponent(profileUsername)}`;
1647
+ if (Array.isArray(analyticsPlatforms) && analyticsPlatforms.length > 0) {
1648
+ qs.platforms = analyticsPlatforms.join(',');
1649
+ }
1650
+ }
1651
+ break;
1652
+ case 'listScheduled':
1653
+ method = 'GET';
1654
+ endpoint = '/uploadposts/schedule';
1655
+ break;
1656
+ case 'cancelScheduled':
1657
+ method = 'DELETE';
1658
+ {
1659
+ const jobId = this.getNodeParameter('scheduleJobId', i);
1660
+ endpoint = `/uploadposts/schedule/${jobId}`;
1661
+ }
1662
+ break;
1663
+ case 'editScheduled':
1664
+ method = 'POST';
1665
+ {
1666
+ const jobId = this.getNodeParameter('scheduleJobId', i);
1667
+ endpoint = `/uploadposts/schedule/${jobId}`;
1668
+ const newScheduledDate = this.getNodeParameter('newScheduledDate', i, '');
1669
+ if (newScheduledDate) {
1670
+ let normalizedDate = newScheduledDate;
1671
+ const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
1672
+ if (!hasTimezone)
1673
+ normalizedDate = `${normalizedDate}Z`;
1674
+ body.scheduled_date = normalizedDate;
1675
+ }
1676
+ }
1677
+ break;
1678
+ case 'listUsers':
1679
+ method = 'GET';
1680
+ endpoint = '/uploadposts/users';
1681
+ break;
1682
+ case 'createUser':
1683
+ method = 'POST';
1684
+ endpoint = '/uploadposts/users';
1685
+ body.username = this.getNodeParameter('newUser', i);
1686
+ break;
1687
+ case 'deleteUser':
1688
+ method = 'DELETE';
1689
+ endpoint = '/uploadposts/users';
1690
+ body.username = this.getNodeParameter('deleteUserId', i);
1691
+ break;
1692
+ case 'generateJwt':
1693
+ method = 'POST';
1694
+ endpoint = '/uploadposts/users/generate-jwt';
1695
+ body.username = user;
1696
+ const redirectUrl = this.getNodeParameter('redirectUrl', i, '');
1697
+ const logoImage = this.getNodeParameter('logoImage', i, '');
1698
+ const redirectButtonText = this.getNodeParameter('redirectButtonText', i, '');
1699
+ const jwtPlatforms = this.getNodeParameter('jwtPlatforms', i, []);
1700
+ if (redirectUrl)
1701
+ body.redirect_url = redirectUrl;
1702
+ if (logoImage)
1703
+ body.logo_image = logoImage;
1704
+ if (redirectButtonText)
1705
+ body.redirect_button_text = redirectButtonText;
1706
+ if (Array.isArray(jwtPlatforms) && jwtPlatforms.length > 0)
1707
+ body.platforms = jwtPlatforms;
1708
+ break;
1709
+ case 'validateJwt':
1710
+ method = 'POST';
1711
+ endpoint = '/uploadposts/users/validate-jwt';
1712
+ body.jwt = this.getNodeParameter('jwtToken', i);
1713
+ break;
919
1714
  }
920
- if (platforms.includes('pinterest')) {
1715
+ if (isUploadOperation && platforms.includes('pinterest')) {
921
1716
  const pinterestBoardId = this.getNodeParameter('pinterestBoardId', i);
922
1717
  if (pinterestBoardId)
923
1718
  formData.pinterest_board_id = pinterestBoardId;
1719
+ const pinterestLink = this.getNodeParameter('pinterestLink', i);
1720
+ if (pinterestLink)
1721
+ formData.pinterest_link = pinterestLink;
1722
+ if (operation === 'uploadVideo') {
1723
+ const pinterestCoverImageUrl = this.getNodeParameter('pinterestCoverImageUrl', i);
1724
+ const pinterestCoverImageContentType = this.getNodeParameter('pinterestCoverImageContentType', i);
1725
+ const pinterestCoverImageData = this.getNodeParameter('pinterestCoverImageData', i);
1726
+ const pinterestCoverImageKeyFrameTime = this.getNodeParameter('pinterestCoverImageKeyFrameTime', i);
1727
+ const pinterestLink = this.getNodeParameter('pinterestLink', i);
1728
+ if (pinterestCoverImageUrl) {
1729
+ formData.pinterest_cover_image_url = pinterestCoverImageUrl;
1730
+ }
1731
+ else {
1732
+ if (pinterestCoverImageContentType && pinterestCoverImageData) {
1733
+ formData.pinterest_cover_image_content_type = pinterestCoverImageContentType;
1734
+ formData.pinterest_cover_image_data = pinterestCoverImageData;
1735
+ }
1736
+ else if (pinterestCoverImageKeyFrameTime !== undefined) {
1737
+ formData.pinterest_cover_image_key_frame_time = pinterestCoverImageKeyFrameTime;
1738
+ }
1739
+ }
1740
+ if (pinterestLink)
1741
+ formData.pinterest_link = pinterestLink;
1742
+ }
924
1743
  }
925
- if (platforms.includes('linkedin')) {
1744
+ if (isUploadOperation && platforms.includes('linkedin')) {
926
1745
  const targetLinkedinPageId = this.getNodeParameter('targetLinkedinPageId', i);
927
- if (targetLinkedinPageId)
928
- formData.target_linkedin_page_id = targetLinkedinPageId;
1746
+ if (targetLinkedinPageId) {
1747
+ const match = targetLinkedinPageId.match(/(\d+)$/);
1748
+ if (match) {
1749
+ formData.target_linkedin_page_id = match[1];
1750
+ }
1751
+ else {
1752
+ formData.target_linkedin_page_id = targetLinkedinPageId;
1753
+ }
1754
+ }
929
1755
  if (operation === 'uploadPhotos') {
930
1756
  const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
931
1757
  if (linkedinVisibility === 'PUBLIC') {
@@ -934,22 +1760,22 @@ class UploadPost {
934
1760
  }
935
1761
  else if (operation === 'uploadVideo') {
936
1762
  const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
937
- const linkedinDescription = this.getNodeParameter('linkedinDescription', i);
938
1763
  formData.visibility = linkedinVisibility;
939
- if (linkedinDescription)
940
- formData.description = linkedinDescription;
941
1764
  }
942
1765
  }
943
- if (platforms.includes('facebook')) {
1766
+ if (isUploadOperation && platforms.includes('facebook')) {
944
1767
  const facebookPageId = this.getNodeParameter('facebookPageId', i);
945
1768
  formData.facebook_page_id = facebookPageId;
946
1769
  if (operation === 'uploadVideo') {
947
- const facebookVideoDescription = this.getNodeParameter('facebookVideoDescription', i);
948
1770
  const facebookVideoState = this.getNodeParameter('facebookVideoState', i);
949
- if (facebookVideoDescription)
950
- formData.description = facebookVideoDescription;
951
1771
  if (facebookVideoState)
952
1772
  formData.video_state = facebookVideoState;
1773
+ try {
1774
+ const facebookMediaType = this.getNodeParameter('facebookMediaType', i);
1775
+ if (facebookMediaType)
1776
+ formData.facebook_media_type = facebookMediaType;
1777
+ }
1778
+ catch { }
953
1779
  }
954
1780
  else if (operation === 'uploadText') {
955
1781
  const facebookLink = this.getNodeParameter('facebookLink', i);
@@ -957,7 +1783,7 @@ class UploadPost {
957
1783
  formData.link = facebookLink;
958
1784
  }
959
1785
  }
960
- if (platforms.includes('tiktok')) {
1786
+ if (isUploadOperation && platforms.includes('tiktok')) {
961
1787
  if (operation === 'uploadPhotos') {
962
1788
  const tiktokAutoAddMusic = this.getNodeParameter('tiktokAutoAddMusic', i);
963
1789
  const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
@@ -975,7 +1801,7 @@ class UploadPost {
975
1801
  formData.disclose_commercial = String(tiktokDiscloseCommercialPhoto);
976
1802
  if (tiktokPhotoCoverIndex !== undefined)
977
1803
  formData.photo_cover_index = tiktokPhotoCoverIndex;
978
- if (tiktokPhotoDescription)
1804
+ if (tiktokPhotoDescription && formData.description === undefined)
979
1805
  formData.description = tiktokPhotoDescription;
980
1806
  }
981
1807
  else if (operation === 'uploadVideo') {
@@ -989,6 +1815,7 @@ class UploadPost {
989
1815
  const tiktokBrandedContentVideo = this.getNodeParameter('tiktokBrandedContentVideo', i);
990
1816
  const tiktokBrandOrganicToggle = this.getNodeParameter('tiktokBrandOrganicToggle', i);
991
1817
  const tiktokIsAigc = this.getNodeParameter('tiktokIsAigc', i);
1818
+ const tiktokPostMode = this.getNodeParameter('tiktokPostMode', i);
992
1819
  if (tiktokPrivacyLevel)
993
1820
  formData.privacy_level = tiktokPrivacyLevel;
994
1821
  if (tiktokDisableDuet !== undefined)
@@ -1009,9 +1836,11 @@ class UploadPost {
1009
1836
  formData.brand_organic_toggle = String(tiktokBrandOrganicToggle);
1010
1837
  if (tiktokIsAigc !== undefined)
1011
1838
  formData.is_aigc = String(tiktokIsAigc);
1839
+ if (tiktokPostMode)
1840
+ formData.post_mode = tiktokPostMode;
1012
1841
  }
1013
1842
  }
1014
- if (platforms.includes('instagram')) {
1843
+ if (isUploadOperation && platforms.includes('instagram')) {
1015
1844
  const instagramMediaTypeInput = this.getNodeParameter('instagramMediaType', i);
1016
1845
  let finalInstagramMediaType = instagramMediaTypeInput;
1017
1846
  if (operation === 'uploadPhotos') {
@@ -1050,8 +1879,7 @@ class UploadPost {
1050
1879
  formData.thumb_offset = instagramThumbOffset;
1051
1880
  }
1052
1881
  }
1053
- if (platforms.includes('youtube') && operation === 'uploadVideo') {
1054
- const youtubeDescription = this.getNodeParameter('youtubeDescription', i);
1882
+ if (isUploadOperation && platforms.includes('youtube') && operation === 'uploadVideo') {
1055
1883
  const youtubeTagsRaw = this.getNodeParameter('youtubeTags', i);
1056
1884
  const youtubeCategoryId = this.getNodeParameter('youtubeCategoryId', i);
1057
1885
  const youtubePrivacyStatus = this.getNodeParameter('youtubePrivacyStatus', i);
@@ -1060,8 +1888,6 @@ class UploadPost {
1060
1888
  const youtubePublicStatsViewable = this.getNodeParameter('youtubePublicStatsViewable', i);
1061
1889
  const youtubeMadeForKids = this.getNodeParameter('youtubeMadeForKids', i);
1062
1890
  const youtubeThumbnail = this.getNodeParameter('youtubeThumbnail', i);
1063
- if (youtubeDescription)
1064
- formData.description = youtubeDescription;
1065
1891
  if (youtubeTagsRaw)
1066
1892
  formData.tags = youtubeTagsRaw.split(',').map(tag => tag.trim());
1067
1893
  if (youtubeCategoryId)
@@ -1099,14 +1925,7 @@ class UploadPost {
1099
1925
  }
1100
1926
  }
1101
1927
  }
1102
- if (platforms.includes('threads')) {
1103
- if (operation === 'uploadVideo') {
1104
- const threadsDescription = this.getNodeParameter('threadsDescription', i);
1105
- if (threadsDescription)
1106
- formData.description = threadsDescription;
1107
- }
1108
- }
1109
- if (platforms.includes('x')) {
1928
+ if (isUploadOperation && platforms.includes('x')) {
1110
1929
  if (operation === 'uploadText') {
1111
1930
  const xPostUrlText = this.getNodeParameter('xPostUrlText', i);
1112
1931
  if (xPostUrlText)
@@ -1117,6 +1936,12 @@ class UploadPost {
1117
1936
  formData.tagged_user_ids = xTaggedUserIdsText.split(',').map(id => id.trim());
1118
1937
  if (xReplySettingsText)
1119
1938
  formData.reply_settings = xReplySettingsText;
1939
+ try {
1940
+ const xLongTextAsPostText = this.getNodeParameter('xLongTextAsPost', i, false);
1941
+ if (xLongTextAsPostText)
1942
+ formData.x_long_text_as_post = String(xLongTextAsPostText);
1943
+ }
1944
+ catch { }
1120
1945
  delete formData.nullcast;
1121
1946
  delete formData.place_id;
1122
1947
  delete formData.poll_duration;
@@ -1131,6 +1956,7 @@ class UploadPost {
1131
1956
  const xPollDurationVideo = this.getNodeParameter('xPollDurationVideo', i);
1132
1957
  const xPollOptionsVideoRaw = this.getNodeParameter('xPollOptionsVideo', i);
1133
1958
  const xPollReplySettingsVideo = this.getNodeParameter('xPollReplySettingsVideo', i);
1959
+ const xLongTextAsPost = this.getNodeParameter('xLongTextAsPost', i, false);
1134
1960
  if (xTaggedUserIds)
1135
1961
  formData.tagged_user_ids = xTaggedUserIds.split(',').map(id => id.trim());
1136
1962
  if (xReplySettings)
@@ -1145,22 +1971,76 @@ class UploadPost {
1145
1971
  formData.poll_options = xPollOptionsVideoRaw.split(',').map(opt => opt.trim());
1146
1972
  if (xPollReplySettingsVideo)
1147
1973
  formData.poll_reply_settings = xPollReplySettingsVideo;
1974
+ if (xLongTextAsPost)
1975
+ formData.x_long_text_as_post = String(xLongTextAsPost);
1148
1976
  }
1149
1977
  }
1150
1978
  const credentials = await this.getCredentials('uploadPostApi');
1151
1979
  const apiKey = credentials.apiKey;
1152
1980
  const options = {
1153
1981
  uri: `https://api.upload-post.com/api${endpoint}`,
1154
- method: 'POST',
1155
- headers: {
1156
- 'Authorization': `Apikey ${apiKey}`,
1157
- },
1158
- formData,
1982
+ method,
1983
+ headers: {},
1159
1984
  json: true,
1160
1985
  };
1986
+ if (operation === 'validateJwt') {
1987
+ const jwt = this.getNodeParameter('jwtToken', i);
1988
+ options.headers['Authorization'] = `Bearer ${jwt}`;
1989
+ }
1990
+ else {
1991
+ options.headers['Authorization'] = `ApiKey ${apiKey}`;
1992
+ }
1993
+ if (method === 'POST') {
1994
+ if (operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText') {
1995
+ options.formData = formData;
1996
+ }
1997
+ else {
1998
+ options.body = body;
1999
+ }
2000
+ }
2001
+ else if (method === 'GET' || method === 'DELETE') {
2002
+ if (operation === 'deleteUser') {
2003
+ options.body = body;
2004
+ }
2005
+ else {
2006
+ options.qs = qs;
2007
+ }
2008
+ }
1161
2009
  const responseData = await this.helpers.request(options);
2010
+ const shouldConsiderPolling = operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText';
2011
+ const waitForCompletion = shouldConsiderPolling ? this.getNodeParameter('waitForCompletion', i, false) : false;
2012
+ let finalData = responseData;
2013
+ if (shouldConsiderPolling && waitForCompletion) {
2014
+ const maybeRequestId = (responseData && responseData.request_id) ? responseData.request_id : undefined;
2015
+ if (maybeRequestId) {
2016
+ const requestId = maybeRequestId;
2017
+ const pollIntervalSec = this.getNodeParameter('pollInterval', i, 10);
2018
+ const pollTimeoutSec = this.getNodeParameter('pollTimeout', i, 600);
2019
+ const start = Date.now();
2020
+ while (true) {
2021
+ await (0, n8n_workflow_1.sleep)(Math.max(1, pollIntervalSec) * 1000);
2022
+ if (Date.now() - start > Math.max(5, pollTimeoutSec) * 1000) {
2023
+ finalData = { success: false, message: 'Polling timed out', request_id: requestId };
2024
+ break;
2025
+ }
2026
+ const statusOptions = {
2027
+ uri: `https://api.upload-post.com/api/uploadposts/status`,
2028
+ method: 'GET',
2029
+ headers: { 'Authorization': `ApiKey ${apiKey}` },
2030
+ qs: { request_id: requestId },
2031
+ json: true,
2032
+ };
2033
+ const statusData = await this.helpers.request(statusOptions);
2034
+ finalData = statusData;
2035
+ const statusValue = (statusData && statusData.status);
2036
+ if (statusData.success === true || (statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
2037
+ break;
2038
+ }
2039
+ }
2040
+ }
2041
+ }
1162
2042
  returnData.push({
1163
- json: responseData,
2043
+ json: finalData,
1164
2044
  pairedItem: {
1165
2045
  item: i,
1166
2046
  },