n8n-nodes-upload-post 0.1.8 → 0.1.10

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,7 +1,6 @@
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");
5
4
  class UploadPost {
6
5
  constructor() {
7
6
  this.description = {
@@ -23,12 +22,6 @@ class UploadPost {
23
22
  required: true,
24
23
  },
25
24
  ],
26
- requestDefaults: {
27
- baseURL: 'https://api.upload-post.com/api',
28
- headers: {
29
- 'Accept': 'application/json',
30
- },
31
- },
32
25
  properties: [
33
26
  {
34
27
  displayName: 'Operation',
@@ -40,37 +33,19 @@ class UploadPost {
40
33
  name: 'Upload Photo(s)',
41
34
  value: 'uploadPhotos',
42
35
  action: 'Upload photos',
43
- description: 'Upload one or more photos',
44
- routing: {
45
- request: {
46
- method: 'POST',
47
- url: '/upload_photos',
48
- },
49
- },
36
+ description: 'Upload one or more photos (Supports: TikTok, Instagram, LinkedIn, Facebook, X, Threads)',
50
37
  },
51
38
  {
52
39
  name: 'Upload Video',
53
40
  value: 'uploadVideo',
54
41
  action: 'Upload a video',
55
- description: 'Upload a single video',
56
- routing: {
57
- request: {
58
- method: 'POST',
59
- url: '/upload',
60
- },
61
- },
42
+ description: 'Upload a single video (Supports: TikTok, Instagram, LinkedIn, YouTube, Facebook, X, Threads)',
62
43
  },
63
44
  {
64
45
  name: 'Upload Text',
65
46
  value: 'uploadText',
66
47
  action: 'Upload a text post',
67
- description: 'Upload a text-based post',
68
- routing: {
69
- request: {
70
- method: 'POST',
71
- url: '/upload_text',
72
- },
73
- },
48
+ description: 'Upload a text-based post (Supports: X, LinkedIn, Facebook, Threads)',
74
49
  },
75
50
  ],
76
51
  default: 'uploadPhotos',
@@ -82,12 +57,6 @@ class UploadPost {
82
57
  required: true,
83
58
  default: '',
84
59
  description: 'User identifier for Upload-Post',
85
- routing: {
86
- send: {
87
- type: 'body',
88
- property: 'user',
89
- }
90
- }
91
60
  },
92
61
  {
93
62
  displayName: 'Platform(s)',
@@ -104,27 +73,15 @@ class UploadPost {
104
73
  { name: 'YouTube', value: 'youtube' },
105
74
  ],
106
75
  default: [],
107
- description: 'Platform(s) to upload to',
108
- routing: {
109
- send: {
110
- type: 'body',
111
- property: 'platform[]',
112
- }
113
- }
76
+ description: 'Platform(s) to upload to. Supported platforms vary by operation.',
114
77
  },
115
78
  {
116
- displayName: 'Title',
79
+ displayName: 'Title / Main Content',
117
80
  name: 'title',
118
81
  type: 'string',
119
82
  required: true,
120
83
  default: '',
121
- description: 'Title of the post/video/text',
122
- routing: {
123
- send: {
124
- type: 'body',
125
- property: 'title',
126
- }
127
- }
84
+ 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.',
128
85
  },
129
86
  {
130
87
  displayName: 'Photos (Files or URLs)',
@@ -142,31 +99,18 @@ class UploadPost {
142
99
  multiple: true,
143
100
  multipleValueButtonText: 'Add Photo',
144
101
  },
145
- routing: {
146
- send: {
147
- type: 'body',
148
- property: 'photos[]',
149
- value: '={{ $value.startsWith("http") ? $value : { "data": $value, "isBinary": true } }}',
150
- }
151
- }
152
102
  },
153
103
  {
154
- displayName: 'Caption',
104
+ displayName: 'Caption (Photo/Video Commentary)',
155
105
  name: 'caption',
156
106
  type: 'string',
157
107
  default: '',
158
- description: 'Caption/description for the photos (post commentary)',
108
+ 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.',
159
109
  displayOptions: {
160
110
  show: {
161
- operation: ['uploadPhotos'],
111
+ operation: ['uploadPhotos', 'uploadVideo'],
162
112
  },
163
113
  },
164
- routing: {
165
- send: {
166
- type: 'body',
167
- property: 'caption',
168
- }
169
- }
170
114
  },
171
115
  {
172
116
  displayName: 'Video (File or URL)',
@@ -180,13 +124,6 @@ class UploadPost {
180
124
  operation: ['uploadVideo'],
181
125
  },
182
126
  },
183
- routing: {
184
- send: {
185
- type: 'body',
186
- property: 'video',
187
- value: '={{ $value.startsWith("http") ? $value : { "data": $value, "isBinary": true } }}',
188
- }
189
- }
190
127
  },
191
128
  {
192
129
  displayName: 'LinkedIn Visibility',
@@ -194,62 +131,44 @@ class UploadPost {
194
131
  type: 'options',
195
132
  options: [
196
133
  { name: 'Public', value: 'PUBLIC' },
197
- { name: 'Connections', value: 'CONNECTIONS', displayOptions: { show: { operation: ['uploadVideo'] } } },
134
+ { name: 'Connections', value: 'CONNECTIONS' },
198
135
  { name: 'Logged In', value: 'LOGGED_IN', displayOptions: { show: { operation: ['uploadVideo'] } } },
199
136
  { name: 'Container', value: 'CONTAINER', displayOptions: { show: { operation: ['uploadVideo'] } } },
200
137
  ],
201
138
  default: 'PUBLIC',
202
- description: 'Visibility setting for the LinkedIn post',
139
+ description: 'Visibility for LinkedIn. For Photos, only PUBLIC is supported by API. For Video, CONNECTIONS, PUBLIC, LOGGED_IN, CONTAINER. Not used for Upload Text.',
203
140
  displayOptions: {
204
141
  show: {
205
- operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
142
+ operation: ['uploadPhotos', 'uploadVideo'],
206
143
  platform: ['linkedin']
207
144
  },
208
145
  },
209
- routing: {
210
- send: {
211
- type: 'body',
212
- property: 'visibility',
213
- }
214
- }
215
146
  },
216
147
  {
217
148
  displayName: 'Target LinkedIn Page ID',
218
149
  name: 'targetLinkedinPageId',
219
150
  type: 'string',
220
151
  default: '',
221
- description: 'LinkedIn page ID to upload to an organization (optional)',
152
+ description: 'LinkedIn page ID to upload to an organization (optional). Used for Photos, Video, and Text operations.',
222
153
  displayOptions: {
223
154
  show: {
224
155
  operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
225
156
  platform: ['linkedin']
226
157
  },
227
158
  },
228
- routing: {
229
- send: {
230
- type: 'body',
231
- property: 'target_linkedin_page_id',
232
- }
233
- }
234
159
  },
235
160
  {
236
- displayName: 'LinkedIn Description',
161
+ displayName: 'LinkedIn Video Description',
237
162
  name: 'linkedinDescription',
238
163
  type: 'string',
239
164
  default: '',
240
- description: 'The user generated commentary for the post (LinkedIn Video/Text). If not provided, title is used for video.',
165
+ description: 'User commentary for LinkedIn Video. If not provided, Title is used. Not for Photos/Text.',
241
166
  displayOptions: {
242
167
  show: {
243
- operation: ['uploadVideo', 'uploadText'],
168
+ operation: ['uploadVideo'],
244
169
  platform: ['linkedin']
245
170
  },
246
171
  },
247
- routing: {
248
- send: {
249
- type: 'body',
250
- property: 'description',
251
- }
252
- }
253
172
  },
254
173
  {
255
174
  displayName: 'Facebook Page ID',
@@ -257,38 +176,26 @@ class UploadPost {
257
176
  type: 'string',
258
177
  required: true,
259
178
  default: '',
260
- description: 'Facebook Page ID where the content will be posted',
179
+ description: 'Facebook Page ID. Required for Photos, Video, and Text operations.',
261
180
  displayOptions: {
262
181
  show: {
263
182
  operation: ['uploadPhotos', 'uploadVideo', 'uploadText'],
264
183
  platform: ['facebook']
265
184
  },
266
185
  },
267
- routing: {
268
- send: {
269
- type: 'body',
270
- property: 'facebook_page_id',
271
- }
272
- }
273
186
  },
274
187
  {
275
188
  displayName: 'Facebook Video Description',
276
189
  name: 'facebookVideoDescription',
277
190
  type: 'string',
278
191
  default: '',
279
- description: 'Description of the video for Facebook. If not provided, title is used.',
192
+ description: 'Description for Facebook Video. If not provided, Title is used. Not for Photos/Text.',
280
193
  displayOptions: {
281
194
  show: {
282
195
  operation: ['uploadVideo'],
283
196
  platform: ['facebook']
284
197
  },
285
198
  },
286
- routing: {
287
- send: {
288
- type: 'body',
289
- property: 'description',
290
- }
291
- }
292
199
  },
293
200
  {
294
201
  displayName: 'Facebook Video State',
@@ -300,95 +207,65 @@ class UploadPost {
300
207
  { name: 'Scheduled', value: 'SCHEDULED' },
301
208
  ],
302
209
  default: 'PUBLISHED',
303
- description: 'Desired state of the video on Facebook',
210
+ description: 'State for Facebook Video (DRAFT, PUBLISHED, SCHEDULED). Not for Photos/Text.',
304
211
  displayOptions: {
305
212
  show: {
306
213
  operation: ['uploadVideo'],
307
214
  platform: ['facebook']
308
215
  },
309
216
  },
310
- routing: {
311
- send: {
312
- type: 'body',
313
- property: 'video_state',
314
- }
315
- }
316
217
  },
317
218
  {
318
- displayName: 'TikTok Auto Add Music',
219
+ displayName: 'TikTok Auto Add Music (Photo)',
319
220
  name: 'tiktokAutoAddMusic',
320
221
  type: 'boolean',
321
222
  default: false,
322
- description: 'Whether to automatically add background music to photos on TikTok',
223
+ description: 'Whether to auto add music to TikTok photos. Only for Upload Photos.',
323
224
  displayOptions: {
324
225
  show: {
325
226
  operation: ['uploadPhotos'],
326
227
  platform: ['tiktok']
327
228
  },
328
229
  },
329
- routing: {
330
- send: {
331
- type: 'body',
332
- property: 'auto_add_music',
333
- }
334
- }
335
230
  },
336
231
  {
337
232
  displayName: 'TikTok Disable Comment',
338
233
  name: 'tiktokDisableComment',
339
234
  type: 'boolean',
340
235
  default: false,
341
- description: 'Whether to disable comments on the TikTok post',
236
+ description: 'Whether to disable comments on TikTok post. For Photos & Video.',
342
237
  displayOptions: {
343
238
  show: {
344
239
  operation: ['uploadPhotos', 'uploadVideo'],
345
240
  platform: ['tiktok']
346
241
  },
347
242
  },
348
- routing: {
349
- send: {
350
- type: 'body',
351
- property: 'disable_comment',
352
- }
353
- }
354
243
  },
355
244
  {
356
245
  displayName: 'TikTok Branded Content (Photo)',
357
246
  name: 'tiktokBrandedContentPhoto',
358
247
  type: 'boolean',
359
248
  default: false,
360
- description: 'Whether to indicate if the photo post is branded content (requires Disclose Commercial to be true)',
249
+ description: 'Whether to indicate photo post is branded content (requires Disclose Commercial). Only for Upload Photos.',
361
250
  displayOptions: {
362
251
  show: {
363
252
  operation: ['uploadPhotos'],
364
253
  platform: ['tiktok']
365
254
  },
366
255
  },
367
- routing: {
368
- send: {
369
- type: 'body',
370
- property: 'branded_content',
371
- }
372
- }
373
256
  },
374
257
  {
375
258
  displayName: 'TikTok Disclose Commercial (Photo)',
376
259
  name: 'tiktokDiscloseCommercialPhoto',
377
260
  type: 'boolean',
378
261
  default: false,
379
- description: 'Whether to disclose the commercial nature of the photo post (used with Branded Content)',
262
+ description: 'Whether to disclose commercial nature of photo post. Only for Upload Photos.',
380
263
  displayOptions: {
381
264
  show: {
382
265
  operation: ['uploadPhotos'],
383
266
  platform: ['tiktok']
384
267
  },
385
268
  },
386
- routing: {
387
- send: {
388
- type: 'body',
389
- property: 'disclose_commercial',
390
- }
391
- }
392
269
  },
393
270
  {
394
271
  displayName: 'TikTok Photo Cover Index',
@@ -396,41 +273,29 @@ class UploadPost {
396
273
  type: 'number',
397
274
  default: 0,
398
275
  typeOptions: { minValue: 0 },
399
- description: 'Index (starting at 0) of the photo to use as the cover/thumbnail for the TikTok photo post',
276
+ description: 'Index (0-based) of photo to use as cover for TikTok photo post. Only for Upload Photos.',
400
277
  displayOptions: {
401
278
  show: {
402
279
  operation: ['uploadPhotos'],
403
280
  platform: ['tiktok']
404
281
  },
405
282
  },
406
- routing: {
407
- send: {
408
- type: 'body',
409
- property: 'photo_cover_index',
410
- }
411
- }
412
283
  },
413
284
  {
414
285
  displayName: 'TikTok Photo Description',
415
286
  name: 'tiktokPhotoDescription',
416
287
  type: 'string',
417
288
  default: '',
418
- description: 'Description for the TikTok photo post. If not provided, the common Title value will be used.',
289
+ description: 'Description for TikTok photo post. If not provided, Title is used. Only for Upload Photos.',
419
290
  displayOptions: {
420
291
  show: {
421
292
  operation: ['uploadPhotos'],
422
293
  platform: ['tiktok']
423
294
  },
424
295
  },
425
- routing: {
426
- send: {
427
- type: 'body',
428
- property: 'description',
429
- }
430
- }
431
296
  },
432
297
  {
433
- displayName: 'TikTok Privacy Level',
298
+ displayName: 'TikTok Privacy Level (Video)',
434
299
  name: 'tiktokPrivacyLevel',
435
300
  type: 'options',
436
301
  options: [
@@ -440,408 +305,265 @@ class UploadPost {
440
305
  { name: 'Self Only', value: 'SELF_ONLY' },
441
306
  ],
442
307
  default: 'PUBLIC_TO_EVERYONE',
443
- description: 'Privacy setting for the TikTok video',
308
+ description: 'Privacy setting for TikTok video (PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, etc.). Only for Upload Video.',
444
309
  displayOptions: {
445
310
  show: {
446
311
  operation: ['uploadVideo'],
447
312
  platform: ['tiktok']
448
313
  },
449
314
  },
450
- routing: {
451
- send: {
452
- type: 'body',
453
- property: 'privacy_level',
454
- }
455
- }
456
315
  },
457
316
  {
458
- displayName: 'TikTok Disable Duet',
317
+ displayName: 'TikTok Disable Duet (Video)',
459
318
  name: 'tiktokDisableDuet',
460
319
  type: 'boolean',
461
320
  default: false,
462
- description: 'Whether to disable duet feature for the TikTok video',
321
+ description: 'Whether to disable duet for TikTok video. Only for Upload Video.',
463
322
  displayOptions: {
464
323
  show: {
465
324
  operation: ['uploadVideo'],
466
325
  platform: ['tiktok']
467
326
  },
468
327
  },
469
- routing: {
470
- send: {
471
- type: 'body',
472
- property: 'disable_duet',
473
- }
474
- }
475
328
  },
476
329
  {
477
- displayName: 'TikTok Disable Stitch',
330
+ displayName: 'TikTok Disable Stitch (Video)',
478
331
  name: 'tiktokDisableStitch',
479
332
  type: 'boolean',
480
333
  default: false,
481
- description: 'Whether to disable stitch feature for the TikTok video',
334
+ description: 'Whether to disable stitch for TikTok video. Only for Upload Video.',
482
335
  displayOptions: {
483
336
  show: {
484
337
  operation: ['uploadVideo'],
485
338
  platform: ['tiktok']
486
339
  },
487
340
  },
488
- routing: {
489
- send: {
490
- type: 'body',
491
- property: 'disable_stitch',
492
- }
493
- }
494
341
  },
495
342
  {
496
- displayName: 'TikTok Cover Timestamp (Ms)',
343
+ displayName: 'TikTok Cover Timestamp (Ms, Video)',
497
344
  name: 'tiktokCoverTimestamp',
498
345
  type: 'number',
499
346
  default: 1000,
500
- description: 'Timestamp in milliseconds for video cover on TikTok',
347
+ description: 'Timestamp (ms) for video cover on TikTok. Only for Upload Video.',
501
348
  displayOptions: {
502
349
  show: {
503
350
  operation: ['uploadVideo'],
504
351
  platform: ['tiktok']
505
352
  },
506
353
  },
507
- routing: {
508
- send: {
509
- type: 'body',
510
- property: 'cover_timestamp',
511
- }
512
- }
513
354
  },
514
355
  {
515
- displayName: 'TikTok Brand Content Toggle',
356
+ displayName: 'TikTok Brand Content Toggle (Video)',
516
357
  name: 'tiktokBrandContentToggle',
517
358
  type: 'boolean',
518
359
  default: false,
519
- description: 'Whether to enable branded content for TikTok video',
360
+ description: 'Whether to enable branded content for TikTok video. Only for Upload Video.',
520
361
  displayOptions: {
521
362
  show: {
522
363
  operation: ['uploadVideo'],
523
364
  platform: ['tiktok']
524
365
  },
525
366
  },
526
- routing: {
527
- send: {
528
- type: 'body',
529
- property: 'brand_content_toggle',
530
- }
531
- }
532
367
  },
533
368
  {
534
- displayName: 'TikTok Brand Organic',
369
+ displayName: 'TikTok Brand Organic (Video)',
535
370
  name: 'tiktokBrandOrganic',
536
371
  type: 'boolean',
537
372
  default: false,
538
- description: 'Whether to enable organic branded content for TikTok video',
373
+ description: 'Whether to enable organic branded content for TikTok video. Only for Upload Video.',
539
374
  displayOptions: {
540
375
  show: {
541
376
  operation: ['uploadVideo'],
542
377
  platform: ['tiktok']
543
378
  },
544
379
  },
545
- routing: {
546
- send: {
547
- type: 'body',
548
- property: 'brand_organic',
549
- }
550
- }
551
380
  },
552
381
  {
553
382
  displayName: 'TikTok Branded Content (Video)',
554
383
  name: 'tiktokBrandedContentVideo',
555
384
  type: 'boolean',
556
385
  default: false,
557
- description: 'Whether to enable branded content with disclosure for TikTok video',
386
+ description: 'Whether to enable branded content with disclosure for TikTok video. Only for Upload Video.',
558
387
  displayOptions: {
559
388
  show: {
560
389
  operation: ['uploadVideo'],
561
390
  platform: ['tiktok']
562
391
  },
563
392
  },
564
- routing: {
565
- send: {
566
- type: 'body',
567
- property: 'branded_content',
568
- }
569
- }
570
393
  },
571
394
  {
572
- displayName: 'TikTok Brand Organic Toggle',
395
+ displayName: 'TikTok Brand Organic Toggle (Video)',
573
396
  name: 'tiktokBrandOrganicToggle',
574
397
  type: 'boolean',
575
398
  default: false,
576
- description: 'Whether to enable organic branded content toggle for TikTok video',
399
+ description: 'Whether to enable organic branded content toggle for TikTok video. Only for Upload Video.',
577
400
  displayOptions: {
578
401
  show: {
579
402
  operation: ['uploadVideo'],
580
403
  platform: ['tiktok']
581
404
  },
582
405
  },
583
- routing: {
584
- send: {
585
- type: 'body',
586
- property: 'brand_organic_toggle',
587
- }
588
- }
589
406
  },
590
407
  {
591
- displayName: 'TikTok Is AIGC',
408
+ displayName: 'TikTok Is AIGC (Video)',
592
409
  name: 'tiktokIsAigc',
593
410
  type: 'boolean',
594
411
  default: false,
595
- description: 'Whether to indicate if content is AI-generated for TikTok video',
412
+ description: 'Whether to indicate if content is AI-generated for TikTok video. Only for Upload Video.',
596
413
  displayOptions: {
597
414
  show: {
598
415
  operation: ['uploadVideo'],
599
416
  platform: ['tiktok']
600
417
  },
601
418
  },
602
- routing: {
603
- send: {
604
- type: 'body',
605
- property: 'is_aigc',
606
- }
607
- }
608
419
  },
609
420
  {
610
- displayName: 'Instagram Photo Media Type',
611
- name: 'instagramPhotoMediaType',
421
+ displayName: 'Instagram Media Type',
422
+ name: 'instagramMediaType',
612
423
  type: 'options',
613
424
  options: [
614
- { name: 'Image (Feed)', value: 'IMAGE' },
615
- { name: 'Stories', value: 'STORIES' },
425
+ { name: 'Image (Feed - Photo)', value: 'IMAGE', displayOptions: { show: { operation: ['uploadPhotos'] } } },
426
+ { name: 'Stories (Photo/Video)', value: 'STORIES' },
427
+ { name: 'Reels (Video)', value: 'REELS', displayOptions: { show: { operation: ['uploadVideo'] } } },
616
428
  ],
617
429
  default: 'IMAGE',
618
- description: 'Type of media for Instagram photo upload',
430
+ description: 'Type of media for Instagram. IMAGE/STORIES for Photos. REELS/STORIES for Video.',
619
431
  displayOptions: {
620
432
  show: {
621
- operation: ['uploadPhotos'],
622
- platform: ['instagram']
623
- },
624
- },
625
- routing: {
626
- send: {
627
- type: 'body',
628
- property: 'media_type',
629
- }
630
- }
631
- },
632
- {
633
- displayName: 'Instagram Video Media Type',
634
- name: 'instagramVideoMediaType',
635
- type: 'options',
636
- options: [
637
- { name: 'Reels', value: 'REELS' },
638
- { name: 'Stories', value: 'STORIES' },
639
- ],
640
- default: 'REELS',
641
- description: 'Type of media for Instagram video upload',
642
- displayOptions: {
643
- show: {
644
- operation: ['uploadVideo'],
433
+ operation: ['uploadPhotos', 'uploadVideo'],
645
434
  platform: ['instagram']
646
435
  },
647
436
  },
648
- routing: {
649
- send: {
650
- type: 'body',
651
- property: 'media_type',
652
- }
653
- }
654
437
  },
655
438
  {
656
- displayName: 'Instagram Share to Feed',
439
+ displayName: 'Instagram Share to Feed (Video)',
657
440
  name: 'instagramShareToFeed',
658
441
  type: 'boolean',
659
442
  default: true,
660
- description: 'Whether to share the Instagram video (Reel/Story) to feed',
443
+ description: 'Whether to share Instagram video (Reel/Story) to feed. Only for Upload Video.',
661
444
  displayOptions: {
662
445
  show: {
663
446
  operation: ['uploadVideo'],
664
447
  platform: ['instagram']
665
448
  },
666
449
  },
667
- routing: {
668
- send: {
669
- type: 'body',
670
- property: 'share_to_feed',
671
- }
672
- }
673
450
  },
674
451
  {
675
- displayName: 'Instagram Collaborators',
452
+ displayName: 'Instagram Collaborators (Video)',
676
453
  name: 'instagramCollaborators',
677
454
  type: 'string',
678
455
  default: '',
679
- description: 'Comma-separated list of collaborator usernames for Instagram video',
456
+ description: 'Comma-separated collaborator usernames for Instagram video. Sent as a string. Only for Upload Video.',
680
457
  displayOptions: {
681
458
  show: {
682
459
  operation: ['uploadVideo'],
683
460
  platform: ['instagram']
684
461
  },
685
462
  },
686
- routing: {
687
- send: {
688
- type: 'body',
689
- property: 'collaborators',
690
- }
691
- }
692
463
  },
693
464
  {
694
- displayName: 'Instagram Cover URL',
465
+ displayName: 'Instagram Cover URL (Video)',
695
466
  name: 'instagramCoverUrl',
696
467
  type: 'string',
697
468
  default: '',
698
- description: 'URL for custom video cover on Instagram',
469
+ description: 'URL for custom video cover on Instagram. Only for Upload Video.',
699
470
  displayOptions: {
700
471
  show: {
701
472
  operation: ['uploadVideo'],
702
473
  platform: ['instagram']
703
474
  },
704
475
  },
705
- routing: {
706
- send: {
707
- type: 'body',
708
- property: 'cover_url',
709
- }
710
- }
711
476
  },
712
477
  {
713
- displayName: 'Instagram Audio Name',
478
+ displayName: 'Instagram Audio Name (Video)',
714
479
  name: 'instagramAudioName',
715
480
  type: 'string',
716
481
  default: '',
717
- description: 'Name of the audio track for Instagram video',
482
+ description: 'Name of the audio track for Instagram video. Only for Upload Video.',
718
483
  displayOptions: {
719
484
  show: {
720
485
  operation: ['uploadVideo'],
721
486
  platform: ['instagram']
722
487
  },
723
488
  },
724
- routing: {
725
- send: {
726
- type: 'body',
727
- property: 'audio_name',
728
- }
729
- }
730
489
  },
731
490
  {
732
- displayName: 'Instagram User Tags',
491
+ displayName: 'Instagram User Tags (Video)',
733
492
  name: 'instagramUserTags',
734
493
  type: 'string',
735
494
  default: '',
736
- description: 'Comma-separated list of user tags for Instagram video',
495
+ description: 'Comma-separated user tags for Instagram video. Sent as a string. Only for Upload Video.',
737
496
  displayOptions: {
738
497
  show: {
739
498
  operation: ['uploadVideo'],
740
499
  platform: ['instagram']
741
500
  },
742
501
  },
743
- routing: {
744
- send: {
745
- type: 'body',
746
- property: 'user_tags',
747
- }
748
- }
749
502
  },
750
503
  {
751
- displayName: 'Instagram Location ID',
504
+ displayName: 'Instagram Location ID (Video)',
752
505
  name: 'instagramLocationId',
753
506
  type: 'string',
754
507
  default: '',
755
- description: 'Instagram location ID for the video',
508
+ description: 'Instagram location ID for the video. Only for Upload Video.',
756
509
  displayOptions: {
757
510
  show: {
758
511
  operation: ['uploadVideo'],
759
512
  platform: ['instagram']
760
513
  },
761
514
  },
762
- routing: {
763
- send: {
764
- type: 'body',
765
- property: 'location_id',
766
- }
767
- }
768
515
  },
769
516
  {
770
- displayName: 'Instagram Thumb Offset',
517
+ displayName: 'Instagram Thumb Offset (Video)',
771
518
  name: 'instagramThumbOffset',
772
519
  type: 'string',
773
520
  default: '',
774
- description: 'Timestamp offset for video thumbnail on Instagram',
521
+ description: 'Timestamp offset for video thumbnail on Instagram. Only for Upload Video.',
775
522
  displayOptions: {
776
523
  show: {
777
524
  operation: ['uploadVideo'],
778
525
  platform: ['instagram']
779
526
  },
780
527
  },
781
- routing: {
782
- send: {
783
- type: 'body',
784
- property: 'thumb_offset',
785
- }
786
- }
787
528
  },
788
529
  {
789
- displayName: 'YouTube Description',
530
+ displayName: 'YouTube Video Description',
790
531
  name: 'youtubeDescription',
791
532
  type: 'string',
792
533
  default: '',
793
- description: 'Description of the video for YouTube. If not provided, title is used.',
534
+ description: 'Description of the video for YouTube. If not provided, Title is used. Only for Upload Video.',
794
535
  displayOptions: {
795
536
  show: {
796
537
  operation: ['uploadVideo'],
797
538
  platform: ['youtube']
798
539
  },
799
540
  },
800
- routing: {
801
- send: {
802
- type: 'body',
803
- property: 'description',
804
- }
805
- }
806
541
  },
807
542
  {
808
543
  displayName: 'YouTube Tags',
809
544
  name: 'youtubeTags',
810
545
  type: 'string',
811
546
  default: '',
812
- description: 'Comma-separated list of tags for YouTube video. These will be sent as an array.',
547
+ description: 'Comma-separated list of tags for YouTube video. Will be sent as an array. Only for Upload Video.',
813
548
  displayOptions: {
814
549
  show: {
815
550
  operation: ['uploadVideo'],
816
551
  platform: ['youtube']
817
552
  },
818
553
  },
819
- routing: {
820
- send: {
821
- type: 'body',
822
- property: 'tags',
823
- value: '={{ $value ? $value.split(",").map(tag => tag.trim()) : [] }}',
824
- }
825
- }
826
554
  },
827
555
  {
828
556
  displayName: 'YouTube Category ID',
829
557
  name: 'youtubeCategoryId',
830
558
  type: 'string',
831
559
  default: '22',
832
- description: 'Video category for YouTube',
560
+ description: 'Video category ID for YouTube (e.g., 22 for People & Blogs). Only for Upload Video.',
833
561
  displayOptions: {
834
562
  show: {
835
563
  operation: ['uploadVideo'],
836
564
  platform: ['youtube']
837
565
  },
838
566
  },
839
- routing: {
840
- send: {
841
- type: 'body',
842
- property: 'categoryId',
843
- }
844
- }
845
567
  },
846
568
  {
847
569
  displayName: 'YouTube Privacy Status',
@@ -853,38 +575,26 @@ class UploadPost {
853
575
  { name: 'Private', value: 'private' },
854
576
  ],
855
577
  default: 'public',
856
- description: 'Privacy setting for YouTube video',
578
+ description: 'Privacy setting for YouTube video (public, unlisted, private). Only for Upload Video.',
857
579
  displayOptions: {
858
580
  show: {
859
581
  operation: ['uploadVideo'],
860
582
  platform: ['youtube']
861
583
  },
862
584
  },
863
- routing: {
864
- send: {
865
- type: 'body',
866
- property: 'privacyStatus',
867
- }
868
- }
869
585
  },
870
586
  {
871
587
  displayName: 'YouTube Embeddable',
872
588
  name: 'youtubeEmbeddable',
873
589
  type: 'boolean',
874
590
  default: true,
875
- description: 'Whether the YouTube video is embeddable',
591
+ description: 'Whether the YouTube video is embeddable. Only for Upload Video.',
876
592
  displayOptions: {
877
593
  show: {
878
594
  operation: ['uploadVideo'],
879
595
  platform: ['youtube']
880
596
  },
881
597
  },
882
- routing: {
883
- send: {
884
- type: 'body',
885
- property: 'embeddable',
886
- }
887
- }
888
598
  },
889
599
  {
890
600
  displayName: 'YouTube License',
@@ -895,99 +605,68 @@ class UploadPost {
895
605
  { name: 'Creative Commons - Attribution', value: 'creativeCommon' },
896
606
  ],
897
607
  default: 'youtube',
898
- description: 'Video license for YouTube',
608
+ description: 'Video license for YouTube (youtube, creativeCommon). Only for Upload Video.',
899
609
  displayOptions: {
900
610
  show: {
901
611
  operation: ['uploadVideo'],
902
612
  platform: ['youtube']
903
613
  },
904
614
  },
905
- routing: {
906
- send: {
907
- type: 'body',
908
- property: 'license',
909
- }
910
- }
911
615
  },
912
616
  {
913
617
  displayName: 'YouTube Public Stats Viewable',
914
618
  name: 'youtubePublicStatsViewable',
915
619
  type: 'boolean',
916
620
  default: true,
917
- description: 'Whether public stats are viewable for the YouTube video',
621
+ description: 'Whether public stats are viewable for the YouTube video. Only for Upload Video.',
918
622
  displayOptions: {
919
623
  show: {
920
624
  operation: ['uploadVideo'],
921
625
  platform: ['youtube']
922
626
  },
923
627
  },
924
- routing: {
925
- send: {
926
- type: 'body',
927
- property: 'publicStatsViewable',
928
- }
929
- }
930
628
  },
931
629
  {
932
630
  displayName: 'YouTube Made For Kids',
933
631
  name: 'youtubeMadeForKids',
934
632
  type: 'boolean',
935
633
  default: false,
936
- description: 'Whether the YouTube video is made for kids',
634
+ description: 'Whether the YouTube video is made for kids. Only for Upload Video.',
937
635
  displayOptions: {
938
636
  show: {
939
637
  operation: ['uploadVideo'],
940
638
  platform: ['youtube']
941
639
  },
942
640
  },
943
- routing: {
944
- send: {
945
- type: 'body',
946
- property: 'madeForKids',
947
- }
948
- }
949
641
  },
950
642
  {
951
- displayName: 'Threads Description',
643
+ displayName: 'Threads Video Description',
952
644
  name: 'threadsDescription',
953
645
  type: 'string',
954
646
  default: '',
955
- description: 'The user generated commentary for the post on Threads. If not provided, title is used.',
647
+ description: 'User commentary for Threads video. If not provided, Title is used. Not for Photos/Text.',
956
648
  displayOptions: {
957
649
  show: {
958
- operation: ['uploadVideo', 'uploadText'],
650
+ operation: ['uploadVideo'],
959
651
  platform: ['threads']
960
652
  },
961
653
  },
962
- routing: {
963
- send: {
964
- type: 'body',
965
- property: 'description',
966
- }
967
- }
968
654
  },
969
655
  {
970
- displayName: 'X Tagged User IDs',
656
+ displayName: 'X Tagged User IDs (Video/Text)',
971
657
  name: 'xTaggedUserIds',
972
658
  type: 'string',
973
659
  default: '',
974
- description: 'Comma-separated list of user IDs to tag for X (Twitter) video/text. These will be sent as an array.',
660
+ description: 'Comma-separated list of user IDs to tag for X (Twitter). Not for Photos.',
975
661
  displayOptions: {
976
662
  show: {
977
663
  operation: ['uploadVideo', 'uploadText'],
978
664
  platform: ['x']
979
665
  },
980
666
  },
981
- routing: {
982
- send: {
983
- type: 'body',
984
- property: 'tagged_user_ids',
985
- value: '={{ $value ? $value.split(",").map(id => id.trim()) : [] }}',
986
- }
987
- }
988
667
  },
989
668
  {
990
- displayName: 'X Reply Settings',
669
+ displayName: 'X Reply Settings (Video/Text)',
991
670
  name: 'xReplySettings',
992
671
  type: 'options',
993
672
  options: [
@@ -996,96 +675,65 @@ class UploadPost {
996
675
  { name: 'Everyone', value: 'everyone' },
997
676
  ],
998
677
  default: 'following',
999
- description: 'Who can reply to the X (Twitter) video/text post',
678
+ description: 'Who can reply to the post on X (Twitter) (following, mentionedUsers, everyone). Not for Photos.',
1000
679
  displayOptions: {
1001
680
  show: {
1002
681
  operation: ['uploadVideo', 'uploadText'],
1003
682
  platform: ['x']
1004
683
  },
1005
684
  },
1006
- routing: {
1007
- send: {
1008
- type: 'body',
1009
- property: 'reply_settings',
1010
- }
1011
- }
1012
685
  },
1013
686
  {
1014
687
  displayName: 'X Nullcast (Video)',
1015
688
  name: 'xNullcastVideo',
1016
689
  type: 'boolean',
1017
690
  default: false,
1018
- description: 'Whether to publish X (Twitter) video without broadcasting',
691
+ description: 'Whether to publish X (Twitter) video without broadcasting. Not for Text/Photos.',
1019
692
  displayOptions: {
1020
693
  show: {
1021
694
  operation: ['uploadVideo'],
1022
695
  platform: ['x']
1023
696
  },
1024
697
  },
1025
- routing: {
1026
- send: {
1027
- type: 'body',
1028
- property: 'nullcast',
1029
- }
1030
- }
1031
698
  },
1032
699
  {
1033
700
  displayName: 'X Place ID (Video)',
1034
701
  name: 'xPlaceIdVideo',
1035
702
  type: 'string',
1036
703
  default: '',
1037
- description: 'Location place ID for X (Twitter) video',
704
+ description: 'Location place ID for X (Twitter) video. Not for Text/Photos.',
1038
705
  displayOptions: {
1039
706
  show: {
1040
707
  operation: ['uploadVideo'],
1041
708
  platform: ['x']
1042
709
  },
1043
710
  },
1044
- routing: {
1045
- send: {
1046
- type: 'body',
1047
- property: 'place_id',
1048
- }
1049
- }
1050
711
  },
1051
712
  {
1052
713
  displayName: 'X Poll Duration (Minutes, Video)',
1053
714
  name: 'xPollDurationVideo',
1054
715
  type: 'number',
1055
716
  default: 1440,
1056
- description: 'Poll duration in minutes for X (Twitter) video post. Requires Poll Options.',
717
+ description: 'Poll duration in minutes for X (Twitter) video post (requires Poll Options). Not for Text/Photos.',
1057
718
  displayOptions: {
1058
719
  show: {
1059
720
  operation: ['uploadVideo'],
1060
721
  platform: ['x']
1061
722
  },
1062
723
  },
1063
- routing: {
1064
- send: {
1065
- type: 'body',
1066
- property: 'poll_duration',
1067
- }
1068
- }
1069
724
  },
1070
725
  {
1071
726
  displayName: 'X Poll Options (Video)',
1072
727
  name: 'xPollOptionsVideo',
1073
728
  type: 'string',
1074
729
  default: '',
1075
- description: 'Comma-separated list of poll options for X (Twitter) video post. These will be sent as an array.',
730
+ description: 'Comma-separated list of poll options for X (Twitter) video post. Will be sent as an array. Not for Text/Photos.',
1076
731
  displayOptions: {
1077
732
  show: {
1078
733
  operation: ['uploadVideo'],
1079
734
  platform: ['x']
1080
735
  },
1081
736
  },
1082
- routing: {
1083
- send: {
1084
- type: 'body',
1085
- property: 'poll_options',
1086
- value: '={{ $value ? $value.split(",").map(opt => opt.trim()) : [] }}',
1087
- }
1088
- }
1089
737
  },
1090
738
  {
1091
739
  displayName: 'X Poll Reply Settings (Video)',
@@ -1097,38 +745,26 @@ class UploadPost {
1097
745
  { name: 'Everyone', value: 'everyone' },
1098
746
  ],
1099
747
  default: 'following',
1100
- description: 'Who can reply to the poll in X (Twitter) video post',
748
+ description: 'Who can reply to the poll in X (Twitter) video post (following, mentionedUsers, everyone). Not for Text/Photos.',
1101
749
  displayOptions: {
1102
750
  show: {
1103
751
  operation: ['uploadVideo'],
1104
752
  platform: ['x']
1105
753
  },
1106
754
  },
1107
- routing: {
1108
- send: {
1109
- type: 'body',
1110
- property: 'poll_reply_settings',
1111
- }
1112
- }
1113
755
  },
1114
756
  {
1115
757
  displayName: 'X Post URL (Text)',
1116
758
  name: 'xPostUrlText',
1117
759
  type: 'string',
1118
760
  default: '',
1119
- description: 'URL to attach to the X (Twitter) text post',
761
+ description: 'URL to attach to the X (Twitter) text post. Only for Upload Text.',
1120
762
  displayOptions: {
1121
763
  show: {
1122
764
  operation: ['uploadText'],
1123
765
  platform: ['x']
1124
766
  },
1125
767
  },
1126
- routing: {
1127
- send: {
1128
- type: 'body',
1129
- property: 'post_url',
1130
- }
1131
- }
1132
768
  },
1133
769
  ],
1134
770
  };
@@ -1136,67 +772,291 @@ class UploadPost {
1136
772
  async execute() {
1137
773
  const items = this.getInputData();
1138
774
  const returnData = [];
1139
- const length = items.length;
1140
- const baseApiUrl = 'https://api.upload-post.com/api';
1141
- const nodeDescription = this.description;
1142
- for (let i = 0; i < length; i++) {
1143
- try {
1144
- const credentials = await this.getCredentials('uploadPostApi', i);
1145
- if (!credentials || !credentials.apiKey) {
1146
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'API key is missing from UploadPostApi credentials.', { itemIndex: i });
775
+ for (let i = 0; i < items.length; i++) {
776
+ const operation = this.getNodeParameter('operation', i);
777
+ const user = this.getNodeParameter('user', i);
778
+ let platforms = this.getNodeParameter('platform', i);
779
+ const title = this.getNodeParameter('title', i);
780
+ let endpoint = '';
781
+ const formData = {};
782
+ formData.user = user;
783
+ formData.title = title;
784
+ switch (operation) {
785
+ case 'uploadPhotos':
786
+ endpoint = '/upload_photos';
787
+ const photoCaption = this.getNodeParameter('caption', i);
788
+ let photosInput = this.getNodeParameter('photos', i, []);
789
+ let photosToProcess;
790
+ if (typeof photosInput === 'string') {
791
+ photosToProcess = photosInput ? [photosInput] : [];
792
+ }
793
+ else {
794
+ photosToProcess = photosInput;
795
+ }
796
+ const allowedPhotoPlatforms = ['tiktok', 'instagram', 'linkedin', 'facebook', 'x', 'threads'];
797
+ platforms = platforms.filter(p => allowedPhotoPlatforms.includes(p));
798
+ formData['platform[]'] = platforms;
799
+ if (photosToProcess.length > 0) {
800
+ const photoArray = [];
801
+ for (const photoItem of photosToProcess) {
802
+ if (typeof photoItem === 'string' && photoItem.startsWith('{{$binary')) {
803
+ const binaryPropertyName = photoItem.substring('{{$binary.'.length, photoItem.length - 2);
804
+ const binaryData = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
805
+ photoArray.push(binaryData);
806
+ }
807
+ else if (typeof photoItem === 'string' && photoItem) {
808
+ photoArray.push(photoItem);
809
+ }
810
+ }
811
+ if (photoArray.length > 0) {
812
+ formData['photos[]'] = photoArray;
813
+ }
814
+ }
815
+ if (photoCaption)
816
+ formData.caption = photoCaption;
817
+ break;
818
+ case 'uploadVideo':
819
+ endpoint = '/upload';
820
+ const video = this.getNodeParameter('video', i);
821
+ const allowedVideoPlatforms = ['tiktok', 'instagram', 'linkedin', 'youtube', 'facebook', 'x', 'threads'];
822
+ platforms = platforms.filter(p => allowedVideoPlatforms.includes(p));
823
+ formData['platform[]'] = platforms;
824
+ if (video) {
825
+ if (video.startsWith('{{$binary')) {
826
+ const binaryPropertyName = video.substring('{{$binary.'.length, video.length - 2);
827
+ const binaryData = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
828
+ formData.video = binaryData;
829
+ }
830
+ else {
831
+ formData.video = video;
832
+ }
833
+ }
834
+ break;
835
+ case 'uploadText':
836
+ endpoint = '/upload_text';
837
+ const allowedTextPlatforms = ['x', 'linkedin', 'facebook', 'threads'];
838
+ platforms = platforms.filter(p => allowedTextPlatforms.includes(p));
839
+ formData['platform[]'] = platforms;
840
+ break;
841
+ }
842
+ if (platforms.includes('linkedin')) {
843
+ const targetLinkedinPageId = this.getNodeParameter('targetLinkedinPageId', i);
844
+ if (targetLinkedinPageId)
845
+ formData.target_linkedin_page_id = targetLinkedinPageId;
846
+ if (operation === 'uploadPhotos') {
847
+ const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
848
+ if (linkedinVisibility === 'PUBLIC') {
849
+ formData.visibility = 'PUBLIC';
850
+ }
1147
851
  }
1148
- const apiKey = credentials.apiKey;
1149
- const authorizationHeader = `Apikey ${apiKey}`;
1150
- const operation = this.getNodeParameter('operation', i);
1151
- const operationProperty = nodeDescription.properties.find((prop) => prop.name === 'operation');
1152
- const operationOptions = operationProperty === null || operationProperty === void 0 ? void 0 : operationProperty.options;
1153
- const operationConfig = operationOptions === null || operationOptions === void 0 ? void 0 : operationOptions.find(opt => opt.value === operation);
1154
- if (!operationConfig || !operationConfig.routing || !operationConfig.routing.request) {
1155
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Routing information not found for operation: ${operation}`, { itemIndex: i });
852
+ else if (operation === 'uploadVideo') {
853
+ const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
854
+ const linkedinDescription = this.getNodeParameter('linkedinDescription', i);
855
+ formData.visibility = linkedinVisibility;
856
+ if (linkedinDescription)
857
+ formData.description = linkedinDescription;
1156
858
  }
1157
- const requestDetails = operationConfig.routing.request;
1158
- const relativeUrl = requestDetails.url;
1159
- const httpMethod = requestDetails.method;
1160
- if (!relativeUrl || !httpMethod) {
1161
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Incomplete routing details (URL or Method missing) for operation: ${operation}`, { itemIndex: i });
859
+ }
860
+ if (platforms.includes('facebook')) {
861
+ const facebookPageId = this.getNodeParameter('facebookPageId', i);
862
+ formData.facebook_page_id = facebookPageId;
863
+ if (operation === 'uploadVideo') {
864
+ const facebookVideoDescription = this.getNodeParameter('facebookVideoDescription', i);
865
+ const facebookVideoState = this.getNodeParameter('facebookVideoState', i);
866
+ if (facebookVideoDescription)
867
+ formData.description = facebookVideoDescription;
868
+ if (facebookVideoState)
869
+ formData.video_state = facebookVideoState;
1162
870
  }
1163
- let fullUrl;
1164
- if (baseApiUrl.endsWith('/') && relativeUrl.startsWith('/')) {
1165
- fullUrl = baseApiUrl + relativeUrl.substring(1);
871
+ }
872
+ if (platforms.includes('tiktok')) {
873
+ if (operation === 'uploadPhotos') {
874
+ const tiktokAutoAddMusic = this.getNodeParameter('tiktokAutoAddMusic', i);
875
+ const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
876
+ const tiktokBrandedContentPhoto = this.getNodeParameter('tiktokBrandedContentPhoto', i);
877
+ const tiktokDiscloseCommercialPhoto = this.getNodeParameter('tiktokDiscloseCommercialPhoto', i);
878
+ const tiktokPhotoCoverIndex = this.getNodeParameter('tiktokPhotoCoverIndex', i);
879
+ const tiktokPhotoDescription = this.getNodeParameter('tiktokPhotoDescription', i);
880
+ if (tiktokAutoAddMusic !== undefined)
881
+ formData.auto_add_music = String(tiktokAutoAddMusic);
882
+ if (tiktokDisableComment !== undefined)
883
+ formData.disable_comment = String(tiktokDisableComment);
884
+ if (tiktokBrandedContentPhoto !== undefined)
885
+ formData.branded_content = String(tiktokBrandedContentPhoto);
886
+ if (tiktokDiscloseCommercialPhoto !== undefined)
887
+ formData.disclose_commercial = String(tiktokDiscloseCommercialPhoto);
888
+ if (tiktokPhotoCoverIndex !== undefined)
889
+ formData.photo_cover_index = tiktokPhotoCoverIndex;
890
+ if (tiktokPhotoDescription)
891
+ formData.description = tiktokPhotoDescription;
1166
892
  }
1167
- else if (!baseApiUrl.endsWith('/') && !relativeUrl.startsWith('/')) {
1168
- fullUrl = `${baseApiUrl}/${relativeUrl}`;
893
+ else if (operation === 'uploadVideo') {
894
+ const tiktokPrivacyLevel = this.getNodeParameter('tiktokPrivacyLevel', i);
895
+ const tiktokDisableDuet = this.getNodeParameter('tiktokDisableDuet', i);
896
+ const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
897
+ const tiktokDisableStitch = this.getNodeParameter('tiktokDisableStitch', i);
898
+ const tiktokCoverTimestamp = this.getNodeParameter('tiktokCoverTimestamp', i);
899
+ const tiktokBrandContentToggle = this.getNodeParameter('tiktokBrandContentToggle', i);
900
+ const tiktokBrandOrganic = this.getNodeParameter('tiktokBrandOrganic', i);
901
+ const tiktokBrandedContentVideo = this.getNodeParameter('tiktokBrandedContentVideo', i);
902
+ const tiktokBrandOrganicToggle = this.getNodeParameter('tiktokBrandOrganicToggle', i);
903
+ const tiktokIsAigc = this.getNodeParameter('tiktokIsAigc', i);
904
+ if (tiktokPrivacyLevel)
905
+ formData.privacy_level = tiktokPrivacyLevel;
906
+ if (tiktokDisableDuet !== undefined)
907
+ formData.disable_duet = String(tiktokDisableDuet);
908
+ if (tiktokDisableComment !== undefined)
909
+ formData.disable_comment = String(tiktokDisableComment);
910
+ if (tiktokDisableStitch !== undefined)
911
+ formData.disable_stitch = String(tiktokDisableStitch);
912
+ if (tiktokCoverTimestamp !== undefined)
913
+ formData.cover_timestamp = tiktokCoverTimestamp;
914
+ if (tiktokBrandContentToggle !== undefined)
915
+ formData.brand_content_toggle = String(tiktokBrandContentToggle);
916
+ if (tiktokBrandOrganic !== undefined)
917
+ formData.brand_organic = String(tiktokBrandOrganic);
918
+ if (tiktokBrandedContentVideo !== undefined)
919
+ formData.branded_content = String(tiktokBrandedContentVideo);
920
+ if (tiktokBrandOrganicToggle !== undefined)
921
+ formData.brand_organic_toggle = String(tiktokBrandOrganicToggle);
922
+ if (tiktokIsAigc !== undefined)
923
+ formData.is_aigc = String(tiktokIsAigc);
1169
924
  }
1170
- else {
1171
- fullUrl = baseApiUrl + relativeUrl;
925
+ }
926
+ if (platforms.includes('instagram')) {
927
+ const instagramMediaTypeInput = this.getNodeParameter('instagramMediaType', i);
928
+ let finalInstagramMediaType = instagramMediaTypeInput;
929
+ if (operation === 'uploadPhotos') {
930
+ if (!instagramMediaTypeInput || !['IMAGE', 'STORIES'].includes(instagramMediaTypeInput)) {
931
+ finalInstagramMediaType = 'IMAGE';
932
+ }
1172
933
  }
1173
- const requestOptions = {
1174
- method: httpMethod,
1175
- uri: fullUrl,
1176
- headers: {
1177
- 'Accept': 'application/json',
1178
- 'Authorization': authorizationHeader,
1179
- },
1180
- json: true,
1181
- };
1182
- if (httpMethod === 'POST' || httpMethod === 'PUT' || httpMethod === 'PATCH') {
1183
- requestOptions.headers['Content-Type'] = 'application/json';
934
+ else if (operation === 'uploadVideo') {
935
+ if (!instagramMediaTypeInput || !['REELS', 'STORIES'].includes(instagramMediaTypeInput)) {
936
+ finalInstagramMediaType = 'REELS';
937
+ }
938
+ }
939
+ if (finalInstagramMediaType)
940
+ formData.media_type = finalInstagramMediaType;
941
+ if (operation === 'uploadVideo') {
942
+ const instagramShareToFeed = this.getNodeParameter('instagramShareToFeed', i);
943
+ const instagramCollaborators = this.getNodeParameter('instagramCollaborators', i);
944
+ const instagramCoverUrl = this.getNodeParameter('instagramCoverUrl', i);
945
+ const instagramAudioName = this.getNodeParameter('instagramAudioName', i);
946
+ const instagramUserTags = this.getNodeParameter('instagramUserTags', i);
947
+ const instagramLocationId = this.getNodeParameter('instagramLocationId', i);
948
+ const instagramThumbOffset = this.getNodeParameter('instagramThumbOffset', i);
949
+ if (instagramShareToFeed !== undefined)
950
+ formData.share_to_feed = String(instagramShareToFeed);
951
+ if (instagramCollaborators)
952
+ formData.collaborators = instagramCollaborators;
953
+ if (instagramCoverUrl)
954
+ formData.cover_url = instagramCoverUrl;
955
+ if (instagramAudioName)
956
+ formData.audio_name = instagramAudioName;
957
+ if (instagramUserTags)
958
+ formData.user_tags = instagramUserTags;
959
+ if (instagramLocationId)
960
+ formData.location_id = instagramLocationId;
961
+ if (instagramThumbOffset)
962
+ formData.thumb_offset = instagramThumbOffset;
1184
963
  }
1185
- this.logger.debug(`[UploadPost Node] Executing direct request: ${httpMethod} ${fullUrl} with API Key auth.`);
1186
- const responseData = await this.helpers.request.call(this, requestOptions);
1187
- returnData.push({ json: responseData, pairedItem: i });
1188
964
  }
1189
- catch (error) {
1190
- if (this.continueOnFail()) {
1191
- returnData.push({ json: { error: error.message }, pairedItem: i });
1192
- continue;
965
+ if (platforms.includes('youtube') && operation === 'uploadVideo') {
966
+ const youtubeDescription = this.getNodeParameter('youtubeDescription', i);
967
+ const youtubeTagsRaw = this.getNodeParameter('youtubeTags', i);
968
+ const youtubeCategoryId = this.getNodeParameter('youtubeCategoryId', i);
969
+ const youtubePrivacyStatus = this.getNodeParameter('youtubePrivacyStatus', i);
970
+ const youtubeEmbeddable = this.getNodeParameter('youtubeEmbeddable', i);
971
+ const youtubeLicense = this.getNodeParameter('youtubeLicense', i);
972
+ const youtubePublicStatsViewable = this.getNodeParameter('youtubePublicStatsViewable', i);
973
+ const youtubeMadeForKids = this.getNodeParameter('youtubeMadeForKids', i);
974
+ if (youtubeDescription)
975
+ formData.description = youtubeDescription;
976
+ if (youtubeTagsRaw)
977
+ formData.tags = youtubeTagsRaw.split(',').map(tag => tag.trim());
978
+ if (youtubeCategoryId)
979
+ formData.categoryId = youtubeCategoryId;
980
+ if (youtubePrivacyStatus)
981
+ formData.privacyStatus = youtubePrivacyStatus;
982
+ if (youtubeEmbeddable !== undefined)
983
+ formData.embeddable = String(youtubeEmbeddable);
984
+ if (youtubeLicense)
985
+ formData.license = youtubeLicense;
986
+ if (youtubePublicStatsViewable !== undefined)
987
+ formData.publicStatsViewable = String(youtubePublicStatsViewable);
988
+ if (youtubeMadeForKids !== undefined)
989
+ formData.madeForKids = String(youtubeMadeForKids);
990
+ }
991
+ if (platforms.includes('threads')) {
992
+ if (operation === 'uploadVideo') {
993
+ const threadsDescription = this.getNodeParameter('threadsDescription', i);
994
+ if (threadsDescription)
995
+ formData.description = threadsDescription;
1193
996
  }
1194
- if (error.context) {
1195
- error.context.itemIndex = i;
1196
- throw error;
997
+ }
998
+ if (platforms.includes('x')) {
999
+ if (operation === 'uploadText') {
1000
+ const xPostUrlText = this.getNodeParameter('xPostUrlText', i);
1001
+ if (xPostUrlText)
1002
+ formData.post_url = xPostUrlText;
1003
+ const xTaggedUserIdsText = this.getNodeParameter('xTaggedUserIds', i);
1004
+ const xReplySettingsText = this.getNodeParameter('xReplySettings', i);
1005
+ if (xTaggedUserIdsText)
1006
+ formData.tagged_user_ids = xTaggedUserIdsText.split(',').map(id => id.trim());
1007
+ if (xReplySettingsText)
1008
+ formData.reply_settings = xReplySettingsText;
1009
+ delete formData.nullcast;
1010
+ delete formData.place_id;
1011
+ delete formData.poll_duration;
1012
+ delete formData.poll_options;
1013
+ delete formData.poll_reply_settings;
1014
+ }
1015
+ else if (operation === 'uploadVideo') {
1016
+ const xTaggedUserIds = this.getNodeParameter('xTaggedUserIds', i);
1017
+ const xReplySettings = this.getNodeParameter('xReplySettings', i);
1018
+ const xNullcastVideo = this.getNodeParameter('xNullcastVideo', i);
1019
+ const xPlaceIdVideo = this.getNodeParameter('xPlaceIdVideo', i);
1020
+ const xPollDurationVideo = this.getNodeParameter('xPollDurationVideo', i);
1021
+ const xPollOptionsVideoRaw = this.getNodeParameter('xPollOptionsVideo', i);
1022
+ const xPollReplySettingsVideo = this.getNodeParameter('xPollReplySettingsVideo', i);
1023
+ if (xTaggedUserIds)
1024
+ formData.tagged_user_ids = xTaggedUserIds.split(',').map(id => id.trim());
1025
+ if (xReplySettings)
1026
+ formData.reply_settings = xReplySettings;
1027
+ if (xNullcastVideo !== undefined)
1028
+ formData.nullcast = String(xNullcastVideo);
1029
+ if (xPlaceIdVideo)
1030
+ formData.place_id = xPlaceIdVideo;
1031
+ if (xPollDurationVideo !== undefined)
1032
+ formData.poll_duration = xPollDurationVideo;
1033
+ if (xPollOptionsVideoRaw)
1034
+ formData.poll_options = xPollOptionsVideoRaw.split(',').map(opt => opt.trim());
1035
+ if (xPollReplySettingsVideo)
1036
+ formData.poll_reply_settings = xPollReplySettingsVideo;
1197
1037
  }
1198
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i });
1199
1038
  }
1039
+ const credentials = await this.getCredentials('uploadPostApi');
1040
+ const apiKey = credentials.apiKey;
1041
+ const options = {
1042
+ uri: `https://api.upload-post.com/api${endpoint}`,
1043
+ method: 'POST',
1044
+ headers: {
1045
+ 'Authorization': `Apikey ${apiKey}`,
1046
+ },
1047
+ formData,
1048
+ json: true,
1049
+ };
1050
+ this.logger.info(`[UploadPost] Request: ${options.method} ${options.uri}`);
1051
+ this.logger.info(`[UploadPost] Request Headers: ${JSON.stringify(options.headers)}`);
1052
+ this.logger.info(`[UploadPost] Request FormData: ${JSON.stringify(formData)}`);
1053
+ const responseData = await this.helpers.request(options);
1054
+ returnData.push({
1055
+ json: responseData,
1056
+ pairedItem: {
1057
+ item: i,
1058
+ },
1059
+ });
1200
1060
  }
1201
1061
  return [returnData];
1202
1062
  }