n8n-nodes-tornado-api 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TornadoApi = void 0;
4
- const n8n_workflow_1 = require("n8n-workflow");
5
4
  class TornadoApi {
6
5
  constructor() {
7
6
  this.description = {
@@ -39,6 +38,10 @@ class TornadoApi {
39
38
  name: 'Batch',
40
39
  value: 'batch',
41
40
  },
41
+ {
42
+ name: 'Dashboard',
43
+ value: 'dashboard',
44
+ },
42
45
  {
43
46
  name: 'Storage',
44
47
  value: 'storage',
@@ -68,6 +71,12 @@ class TornadoApi {
68
71
  description: 'Create a new download job',
69
72
  action: 'Create a download job',
70
73
  },
74
+ {
75
+ name: 'Create Bulk',
76
+ value: 'createBulk',
77
+ description: 'Create multiple download jobs at once',
78
+ action: 'Create bulk jobs',
79
+ },
71
80
  {
72
81
  name: 'Get Status',
73
82
  value: 'getStatus',
@@ -75,10 +84,34 @@ class TornadoApi {
75
84
  action: 'Get job status',
76
85
  },
77
86
  {
78
- name: 'Wait for Completion',
79
- value: 'waitForCompletion',
80
- description: 'Wait for a job to complete',
81
- action: 'Wait for job completion',
87
+ name: 'List',
88
+ value: 'list',
89
+ description: 'List all jobs',
90
+ action: 'List jobs',
91
+ },
92
+ {
93
+ name: 'Cancel',
94
+ value: 'cancel',
95
+ description: 'Cancel a pending job',
96
+ action: 'Cancel a job',
97
+ },
98
+ {
99
+ name: 'Retry',
100
+ value: 'retry',
101
+ description: 'Retry a failed job',
102
+ action: 'Retry a job',
103
+ },
104
+ {
105
+ name: 'Delete File',
106
+ value: 'deleteFile',
107
+ description: 'Delete a job file from storage',
108
+ action: 'Delete a job file',
109
+ },
110
+ {
111
+ name: 'Get Metadata',
112
+ value: 'getMetadata',
113
+ description: 'Get video metadata without downloading',
114
+ action: 'Get video metadata',
82
115
  },
83
116
  ],
84
117
  default: 'create',
@@ -197,6 +230,112 @@ class TornadoApi {
197
230
  default: '',
198
231
  description: 'URL to receive completion notification',
199
232
  },
233
+ {
234
+ displayName: 'Audio Only',
235
+ name: 'audio_only',
236
+ type: 'boolean',
237
+ default: false,
238
+ description: 'Extract audio track only (outputs mp3/aac)',
239
+ },
240
+ {
241
+ displayName: 'Download Subtitles',
242
+ name: 'download_subtitles',
243
+ type: 'boolean',
244
+ default: false,
245
+ description: 'Download subtitles if available',
246
+ },
247
+ {
248
+ displayName: 'Download Thumbnail',
249
+ name: 'download_thumbnail',
250
+ type: 'boolean',
251
+ default: false,
252
+ description: 'Download video thumbnail',
253
+ },
254
+ {
255
+ displayName: 'Quality Preset',
256
+ name: 'quality_preset',
257
+ type: 'options',
258
+ options: [
259
+ { name: 'Default', value: '' },
260
+ { name: 'Highest', value: 'highest' },
261
+ { name: 'High', value: 'high' },
262
+ { name: 'Medium', value: 'medium' },
263
+ { name: 'Low', value: 'low' },
264
+ { name: 'Lowest', value: 'lowest' },
265
+ ],
266
+ default: '',
267
+ description: 'Quality preset (overrides video_quality)',
268
+ },
269
+ {
270
+ displayName: 'Max Resolution',
271
+ name: 'max_resolution',
272
+ type: 'options',
273
+ options: [
274
+ { name: 'Best Available', value: 'best' },
275
+ { name: '4K (2160p)', value: '2160' },
276
+ { name: '2K (1440p)', value: '1440' },
277
+ { name: 'Full HD (1080p)', value: '1080' },
278
+ { name: 'HD (720p)', value: '720' },
279
+ { name: 'SD (480p)', value: '480' },
280
+ { name: 'Low (360p)', value: '360' },
281
+ ],
282
+ default: 'best',
283
+ description: 'Maximum video resolution to download',
284
+ },
285
+ {
286
+ displayName: 'Clip Start',
287
+ name: 'clip_start',
288
+ type: 'string',
289
+ default: '',
290
+ placeholder: '00:01:30 or 90',
291
+ description: 'Start timestamp for video clipping (HH:MM:SS or seconds)',
292
+ },
293
+ {
294
+ displayName: 'Clip End',
295
+ name: 'clip_end',
296
+ type: 'string',
297
+ default: '',
298
+ placeholder: '00:05:00 or 300',
299
+ description: 'End timestamp for video clipping (HH:MM:SS or seconds)',
300
+ },
301
+ {
302
+ displayName: 'Live Recording',
303
+ name: 'live_recording',
304
+ type: 'boolean',
305
+ default: false,
306
+ description: 'Whether to enable live stream recording mode',
307
+ },
308
+ {
309
+ displayName: 'Live From Start',
310
+ name: 'live_from_start',
311
+ type: 'boolean',
312
+ default: false,
313
+ description: 'Whether to record from the beginning of the live stream (VOD mode)',
314
+ },
315
+ {
316
+ displayName: 'Max Duration (Seconds)',
317
+ name: 'max_duration',
318
+ type: 'number',
319
+ typeOptions: {
320
+ minValue: 1,
321
+ },
322
+ default: 0,
323
+ description: 'Maximum recording duration in seconds (recommended for live streams)',
324
+ },
325
+ {
326
+ displayName: 'Wait for Video',
327
+ name: 'wait_for_video',
328
+ type: 'boolean',
329
+ default: false,
330
+ description: 'Whether to wait for scheduled/upcoming streams to start',
331
+ },
332
+ {
333
+ displayName: 'Enable Progress Webhook',
334
+ name: 'enable_progress_webhook',
335
+ type: 'boolean',
336
+ default: false,
337
+ description: 'Whether to receive progress webhooks during processing (downloading, muxing, uploading stages)',
338
+ },
200
339
  ],
201
340
  },
202
341
  // Job Get Status Fields
@@ -208,38 +347,297 @@ class TornadoApi {
208
347
  displayOptions: {
209
348
  show: {
210
349
  resource: ['job'],
211
- operation: ['getStatus', 'waitForCompletion'],
350
+ operation: ['getStatus', 'cancel', 'retry', 'deleteFile'],
212
351
  },
213
352
  },
214
353
  default: '',
215
354
  description: 'The UUID of the job',
216
355
  },
217
- // Wait for Completion Options
356
+ // Job List Options
357
+ {
358
+ displayName: 'List Options',
359
+ name: 'listOptions',
360
+ type: 'collection',
361
+ placeholder: 'Add Option',
362
+ default: {},
363
+ displayOptions: {
364
+ show: {
365
+ resource: ['job'],
366
+ operation: ['list'],
367
+ },
368
+ },
369
+ options: [
370
+ {
371
+ displayName: 'Limit',
372
+ name: 'limit',
373
+ type: 'number',
374
+ typeOptions: { minValue: 1, maxValue: 100 },
375
+ default: 20,
376
+ description: 'Number of jobs to return (max 100)',
377
+ },
378
+ {
379
+ displayName: 'Offset',
380
+ name: 'offset',
381
+ type: 'number',
382
+ typeOptions: { minValue: 0 },
383
+ default: 0,
384
+ description: 'Number of jobs to skip',
385
+ },
386
+ {
387
+ displayName: 'Status Filter',
388
+ name: 'status',
389
+ type: 'options',
390
+ options: [
391
+ { name: 'All', value: '' },
392
+ { name: 'Pending', value: 'pending' },
393
+ { name: 'Processing', value: 'processing' },
394
+ { name: 'Completed', value: 'completed' },
395
+ { name: 'Failed', value: 'failed' },
396
+ ],
397
+ default: '',
398
+ description: 'Filter by job status',
399
+ },
400
+ ],
401
+ },
402
+ // Get Metadata URL
403
+ {
404
+ displayName: 'URL',
405
+ name: 'metadataUrl',
406
+ type: 'string',
407
+ required: true,
408
+ displayOptions: {
409
+ show: {
410
+ resource: ['job'],
411
+ operation: ['getMetadata'],
412
+ },
413
+ },
414
+ default: '',
415
+ placeholder: 'https://www.youtube.com/watch?v=...',
416
+ description: 'The video URL to get metadata from',
417
+ },
418
+ // Bulk Create URLs
218
419
  {
219
- displayName: 'Timeout (Seconds)',
220
- name: 'timeout',
221
- type: 'number',
420
+ displayName: 'URLs',
421
+ name: 'bulkUrls',
422
+ type: 'fixedCollection',
423
+ typeOptions: { multipleValues: true },
424
+ required: true,
222
425
  displayOptions: {
223
426
  show: {
224
427
  resource: ['job'],
225
- operation: ['waitForCompletion'],
428
+ operation: ['createBulk'],
226
429
  },
227
430
  },
228
- default: 600,
229
- description: 'Maximum time to wait for completion',
431
+ default: {},
432
+ options: [
433
+ {
434
+ name: 'urlItems',
435
+ displayName: 'URLs',
436
+ values: [
437
+ {
438
+ displayName: 'URL',
439
+ name: 'url',
440
+ type: 'string',
441
+ default: '',
442
+ description: 'Video URL to download',
443
+ },
444
+ {
445
+ displayName: 'Filename',
446
+ name: 'filename',
447
+ type: 'string',
448
+ default: '',
449
+ description: 'Optional custom filename',
450
+ },
451
+ ],
452
+ },
453
+ ],
454
+ description: 'List of URLs to download (max 100)',
230
455
  },
456
+ // Bulk Create Options
231
457
  {
232
- displayName: 'Poll Interval (Seconds)',
233
- name: 'pollInterval',
234
- type: 'number',
458
+ displayName: 'Bulk Options',
459
+ name: 'bulkOptions',
460
+ type: 'collection',
461
+ placeholder: 'Add Option',
462
+ default: {},
235
463
  displayOptions: {
236
464
  show: {
237
465
  resource: ['job'],
238
- operation: ['waitForCompletion'],
466
+ operation: ['createBulk'],
239
467
  },
240
468
  },
241
- default: 5,
242
- description: 'Time between status checks',
469
+ options: [
470
+ {
471
+ displayName: 'Folder',
472
+ name: 'folder',
473
+ type: 'string',
474
+ default: '',
475
+ description: 'S3 folder prefix for all files',
476
+ },
477
+ {
478
+ displayName: 'Format',
479
+ name: 'format',
480
+ type: 'options',
481
+ options: [
482
+ { name: 'MP4', value: 'mp4' },
483
+ { name: 'MKV', value: 'mkv' },
484
+ { name: 'WebM', value: 'webm' },
485
+ { name: 'MOV', value: 'mov' },
486
+ ],
487
+ default: 'mp4',
488
+ description: 'Output format for all jobs',
489
+ },
490
+ {
491
+ displayName: 'Video Codec',
492
+ name: 'video_codec',
493
+ type: 'options',
494
+ options: [
495
+ { name: 'Copy (No Re-encode)', value: 'copy' },
496
+ { name: 'H.264', value: 'h264' },
497
+ { name: 'H.265 (HEVC)', value: 'h265' },
498
+ { name: 'VP9', value: 'vp9' },
499
+ ],
500
+ default: 'copy',
501
+ description: 'Video codec for all jobs',
502
+ },
503
+ {
504
+ displayName: 'Audio Codec',
505
+ name: 'audio_codec',
506
+ type: 'options',
507
+ options: [
508
+ { name: 'Copy (No Re-encode)', value: 'copy' },
509
+ { name: 'AAC', value: 'aac' },
510
+ { name: 'Opus', value: 'opus' },
511
+ { name: 'MP3', value: 'mp3' },
512
+ ],
513
+ default: 'copy',
514
+ description: 'Audio codec for all jobs',
515
+ },
516
+ {
517
+ displayName: 'Audio Bitrate',
518
+ name: 'audio_bitrate',
519
+ type: 'options',
520
+ options: [
521
+ { name: '64 kbps', value: '64k' },
522
+ { name: '128 kbps', value: '128k' },
523
+ { name: '192 kbps', value: '192k' },
524
+ { name: '256 kbps', value: '256k' },
525
+ { name: '320 kbps', value: '320k' },
526
+ ],
527
+ default: '192k',
528
+ description: 'Audio bitrate for all jobs',
529
+ },
530
+ {
531
+ displayName: 'Video Quality (CRF)',
532
+ name: 'video_quality',
533
+ type: 'number',
534
+ typeOptions: {
535
+ minValue: 0,
536
+ maxValue: 51,
537
+ },
538
+ default: 23,
539
+ description: 'Video quality CRF for all jobs (0-51, lower = better)',
540
+ },
541
+ {
542
+ displayName: 'Audio Only',
543
+ name: 'audio_only',
544
+ type: 'boolean',
545
+ default: false,
546
+ description: 'Extract audio only for all jobs',
547
+ },
548
+ {
549
+ displayName: 'Download Subtitles',
550
+ name: 'download_subtitles',
551
+ type: 'boolean',
552
+ default: false,
553
+ description: 'Download subtitles for all jobs',
554
+ },
555
+ {
556
+ displayName: 'Download Thumbnail',
557
+ name: 'download_thumbnail',
558
+ type: 'boolean',
559
+ default: false,
560
+ description: 'Download thumbnails for all jobs',
561
+ },
562
+ {
563
+ displayName: 'Quality Preset',
564
+ name: 'quality_preset',
565
+ type: 'options',
566
+ options: [
567
+ { name: 'Default', value: '' },
568
+ { name: 'Highest', value: 'highest' },
569
+ { name: 'High', value: 'high' },
570
+ { name: 'Medium', value: 'medium' },
571
+ { name: 'Low', value: 'low' },
572
+ { name: 'Lowest', value: 'lowest' },
573
+ ],
574
+ default: '',
575
+ description: 'Quality preset for all jobs',
576
+ },
577
+ {
578
+ displayName: 'Max Resolution',
579
+ name: 'max_resolution',
580
+ type: 'options',
581
+ options: [
582
+ { name: 'Best Available', value: 'best' },
583
+ { name: '4K (2160p)', value: '2160' },
584
+ { name: '2K (1440p)', value: '1440' },
585
+ { name: 'Full HD (1080p)', value: '1080' },
586
+ { name: 'HD (720p)', value: '720' },
587
+ { name: 'SD (480p)', value: '480' },
588
+ { name: 'Low (360p)', value: '360' },
589
+ ],
590
+ default: 'best',
591
+ description: 'Maximum video resolution for all jobs',
592
+ },
593
+ {
594
+ displayName: 'Clip Start',
595
+ name: 'clip_start',
596
+ type: 'string',
597
+ default: '',
598
+ placeholder: '00:01:30 or 90',
599
+ description: 'Start timestamp for video clipping (all jobs)',
600
+ },
601
+ {
602
+ displayName: 'Clip End',
603
+ name: 'clip_end',
604
+ type: 'string',
605
+ default: '',
606
+ placeholder: '00:05:00 or 300',
607
+ description: 'End timestamp for video clipping (all jobs)',
608
+ },
609
+ {
610
+ displayName: 'Live Recording',
611
+ name: 'live_recording',
612
+ type: 'boolean',
613
+ default: false,
614
+ description: 'Whether to enable live stream recording mode for all jobs',
615
+ },
616
+ {
617
+ displayName: 'Live From Start',
618
+ name: 'live_from_start',
619
+ type: 'boolean',
620
+ default: false,
621
+ description: 'Whether to record from the beginning of live streams',
622
+ },
623
+ {
624
+ displayName: 'Max Duration (Seconds)',
625
+ name: 'max_duration',
626
+ type: 'number',
627
+ typeOptions: {
628
+ minValue: 1,
629
+ },
630
+ default: 0,
631
+ description: 'Maximum recording duration in seconds for all jobs',
632
+ },
633
+ {
634
+ displayName: 'Wait for Video',
635
+ name: 'wait_for_video',
636
+ type: 'boolean',
637
+ default: false,
638
+ description: 'Whether to wait for scheduled streams to start',
639
+ },
640
+ ],
243
641
  },
244
642
  // ==================== BATCH OPERATIONS ====================
245
643
  {
@@ -277,6 +675,103 @@ class TornadoApi {
277
675
  default: '',
278
676
  description: 'The UUID of the batch',
279
677
  },
678
+ // ==================== DASHBOARD OPERATIONS ====================
679
+ {
680
+ displayName: 'Operation',
681
+ name: 'operation',
682
+ type: 'options',
683
+ noDataExpression: true,
684
+ displayOptions: {
685
+ show: {
686
+ resource: ['dashboard'],
687
+ },
688
+ },
689
+ options: [
690
+ {
691
+ name: 'Get Stats',
692
+ value: 'getStats',
693
+ description: 'Get aggregated statistics for your API key',
694
+ action: 'Get dashboard stats',
695
+ },
696
+ {
697
+ name: 'Get Jobs',
698
+ value: 'getJobs',
699
+ description: 'Get paginated list of jobs for the dashboard',
700
+ action: 'Get dashboard jobs',
701
+ },
702
+ {
703
+ name: 'Get Batches',
704
+ value: 'getBatches',
705
+ description: 'Get list of batch operations',
706
+ action: 'Get dashboard batches',
707
+ },
708
+ {
709
+ name: 'Get Daily Stats',
710
+ value: 'getDaily',
711
+ description: 'Get daily job statistics for the last 7 days',
712
+ action: 'Get daily stats',
713
+ },
714
+ {
715
+ name: 'Get Cluster Stats',
716
+ value: 'getCluster',
717
+ description: 'Get real-time cluster activity statistics',
718
+ action: 'Get cluster stats',
719
+ },
720
+ {
721
+ name: 'Get Billing',
722
+ value: 'getBilling',
723
+ description: 'Get current billing period usage from Stripe',
724
+ action: 'Get billing info',
725
+ },
726
+ ],
727
+ default: 'getStats',
728
+ },
729
+ // Dashboard Get Jobs Options
730
+ {
731
+ displayName: 'Options',
732
+ name: 'dashboardJobsOptions',
733
+ type: 'collection',
734
+ placeholder: 'Add Option',
735
+ default: {},
736
+ displayOptions: {
737
+ show: {
738
+ resource: ['dashboard'],
739
+ operation: ['getJobs'],
740
+ },
741
+ },
742
+ options: [
743
+ {
744
+ displayName: 'Limit',
745
+ name: 'limit',
746
+ type: 'number',
747
+ typeOptions: { minValue: 1, maxValue: 100 },
748
+ default: 50,
749
+ description: 'Number of jobs to return (max 100)',
750
+ },
751
+ {
752
+ displayName: 'Offset',
753
+ name: 'offset',
754
+ type: 'number',
755
+ typeOptions: { minValue: 0 },
756
+ default: 0,
757
+ description: 'Number of jobs to skip for pagination',
758
+ },
759
+ {
760
+ displayName: 'Status Filter',
761
+ name: 'status',
762
+ type: 'options',
763
+ options: [
764
+ { name: 'All', value: '' },
765
+ { name: 'Pending', value: 'pending' },
766
+ { name: 'Processing', value: 'processing' },
767
+ { name: 'Completed', value: 'completed' },
768
+ { name: 'Failed', value: 'failed' },
769
+ ],
770
+ default: '',
771
+ description: 'Filter by job status',
772
+ },
773
+ ],
774
+ },
280
775
  // ==================== STORAGE OPERATIONS ====================
281
776
  {
282
777
  displayName: 'Operation',
@@ -460,6 +955,30 @@ class TornadoApi {
460
955
  body.folder = additionalOptions.folder;
461
956
  if (additionalOptions.webhook_url)
462
957
  body.webhook_url = additionalOptions.webhook_url;
958
+ if (additionalOptions.audio_only)
959
+ body.audio_only = additionalOptions.audio_only;
960
+ if (additionalOptions.download_subtitles)
961
+ body.download_subtitles = additionalOptions.download_subtitles;
962
+ if (additionalOptions.download_thumbnail)
963
+ body.download_thumbnail = additionalOptions.download_thumbnail;
964
+ if (additionalOptions.quality_preset)
965
+ body.quality_preset = additionalOptions.quality_preset;
966
+ if (additionalOptions.max_resolution && additionalOptions.max_resolution !== 'best')
967
+ body.max_resolution = additionalOptions.max_resolution;
968
+ if (additionalOptions.clip_start)
969
+ body.clip_start = additionalOptions.clip_start;
970
+ if (additionalOptions.clip_end)
971
+ body.clip_end = additionalOptions.clip_end;
972
+ if (additionalOptions.live_recording)
973
+ body.live_recording = additionalOptions.live_recording;
974
+ if (additionalOptions.live_from_start)
975
+ body.live_from_start = additionalOptions.live_from_start;
976
+ if (additionalOptions.max_duration && additionalOptions.max_duration > 0)
977
+ body.max_duration = additionalOptions.max_duration;
978
+ if (additionalOptions.wait_for_video)
979
+ body.wait_for_video = additionalOptions.wait_for_video;
980
+ if (additionalOptions.enable_progress_webhook)
981
+ body.enable_progress_webhook = additionalOptions.enable_progress_webhook;
463
982
  responseData = await this.helpers.httpRequest({
464
983
  method: 'POST',
465
984
  url: `${baseUrl}/jobs`,
@@ -482,33 +1001,123 @@ class TornadoApi {
482
1001
  },
483
1002
  });
484
1003
  }
485
- if (operation === 'waitForCompletion') {
1004
+ if (operation === 'list') {
1005
+ const listOptions = this.getNodeParameter('listOptions', i);
1006
+ const qs = {};
1007
+ if (listOptions.limit)
1008
+ qs.limit = listOptions.limit;
1009
+ if (listOptions.offset)
1010
+ qs.offset = listOptions.offset;
1011
+ if (listOptions.status)
1012
+ qs.status = listOptions.status;
1013
+ responseData = await this.helpers.httpRequest({
1014
+ method: 'GET',
1015
+ url: `${baseUrl}/jobs`,
1016
+ qs,
1017
+ json: true,
1018
+ headers: {
1019
+ 'x-api-key': credentials.apiKey,
1020
+ },
1021
+ });
1022
+ }
1023
+ if (operation === 'cancel') {
486
1024
  const jobId = this.getNodeParameter('jobId', i);
487
- const timeout = this.getNodeParameter('timeout', i);
488
- const pollInterval = this.getNodeParameter('pollInterval', i);
489
- const startTime = Date.now();
490
- const timeoutMs = timeout * 1000;
491
- while (Date.now() - startTime < timeoutMs) {
492
- responseData = await this.helpers.httpRequest({
493
- method: 'GET',
494
- url: `${baseUrl}/jobs/${jobId}`,
495
- json: true,
496
- headers: {
497
- 'x-api-key': credentials.apiKey,
498
- },
499
- });
500
- if (responseData.status === 'Completed') {
501
- break;
502
- }
503
- if (responseData.status === 'Failed') {
504
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Job failed: ${responseData.error || 'Unknown error'}`, { itemIndex: i });
505
- }
506
- // Wait before next poll
507
- await new Promise((resolve) => setTimeout(resolve, pollInterval * 1000));
508
- }
509
- if (responseData.status !== 'Completed' && responseData.status !== 'Failed') {
510
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Timeout waiting for job completion. Last status: ${responseData.status}`, { itemIndex: i });
511
- }
1025
+ responseData = await this.helpers.httpRequest({
1026
+ method: 'DELETE',
1027
+ url: `${baseUrl}/jobs/${jobId}`,
1028
+ json: true,
1029
+ headers: {
1030
+ 'x-api-key': credentials.apiKey,
1031
+ },
1032
+ });
1033
+ }
1034
+ if (operation === 'retry') {
1035
+ const jobId = this.getNodeParameter('jobId', i);
1036
+ responseData = await this.helpers.httpRequest({
1037
+ method: 'POST',
1038
+ url: `${baseUrl}/jobs/${jobId}/retry`,
1039
+ json: true,
1040
+ headers: {
1041
+ 'x-api-key': credentials.apiKey,
1042
+ },
1043
+ });
1044
+ }
1045
+ if (operation === 'deleteFile') {
1046
+ const jobId = this.getNodeParameter('jobId', i);
1047
+ responseData = await this.helpers.httpRequest({
1048
+ method: 'DELETE',
1049
+ url: `${baseUrl}/jobs/${jobId}/file`,
1050
+ json: true,
1051
+ headers: {
1052
+ 'x-api-key': credentials.apiKey,
1053
+ },
1054
+ });
1055
+ }
1056
+ if (operation === 'getMetadata') {
1057
+ const url = this.getNodeParameter('metadataUrl', i);
1058
+ responseData = await this.helpers.httpRequest({
1059
+ method: 'POST',
1060
+ url: `${baseUrl}/metadata`,
1061
+ body: { url },
1062
+ json: true,
1063
+ headers: {
1064
+ 'x-api-key': credentials.apiKey,
1065
+ 'Content-Type': 'application/json',
1066
+ },
1067
+ });
1068
+ }
1069
+ if (operation === 'createBulk') {
1070
+ const bulkUrls = this.getNodeParameter('bulkUrls', i);
1071
+ const bulkOptions = this.getNodeParameter('bulkOptions', i);
1072
+ const jobs = (bulkUrls.urlItems || []).map((item) => ({
1073
+ url: item.url,
1074
+ filename: item.filename || undefined,
1075
+ }));
1076
+ const body = { jobs };
1077
+ if (bulkOptions.folder)
1078
+ body.folder = bulkOptions.folder;
1079
+ if (bulkOptions.format)
1080
+ body.format = bulkOptions.format;
1081
+ if (bulkOptions.video_codec)
1082
+ body.video_codec = bulkOptions.video_codec;
1083
+ if (bulkOptions.audio_codec)
1084
+ body.audio_codec = bulkOptions.audio_codec;
1085
+ if (bulkOptions.audio_bitrate)
1086
+ body.audio_bitrate = bulkOptions.audio_bitrate;
1087
+ if (bulkOptions.video_quality !== undefined)
1088
+ body.video_quality = bulkOptions.video_quality;
1089
+ if (bulkOptions.audio_only)
1090
+ body.audio_only = bulkOptions.audio_only;
1091
+ if (bulkOptions.download_subtitles)
1092
+ body.download_subtitles = bulkOptions.download_subtitles;
1093
+ if (bulkOptions.download_thumbnail)
1094
+ body.download_thumbnail = bulkOptions.download_thumbnail;
1095
+ if (bulkOptions.quality_preset)
1096
+ body.quality_preset = bulkOptions.quality_preset;
1097
+ if (bulkOptions.max_resolution && bulkOptions.max_resolution !== 'best')
1098
+ body.max_resolution = bulkOptions.max_resolution;
1099
+ if (bulkOptions.clip_start)
1100
+ body.clip_start = bulkOptions.clip_start;
1101
+ if (bulkOptions.clip_end)
1102
+ body.clip_end = bulkOptions.clip_end;
1103
+ if (bulkOptions.live_recording)
1104
+ body.live_recording = bulkOptions.live_recording;
1105
+ if (bulkOptions.live_from_start)
1106
+ body.live_from_start = bulkOptions.live_from_start;
1107
+ if (bulkOptions.max_duration && bulkOptions.max_duration > 0)
1108
+ body.max_duration = bulkOptions.max_duration;
1109
+ if (bulkOptions.wait_for_video)
1110
+ body.wait_for_video = bulkOptions.wait_for_video;
1111
+ responseData = await this.helpers.httpRequest({
1112
+ method: 'POST',
1113
+ url: `${baseUrl}/jobs/bulk`,
1114
+ body,
1115
+ json: true,
1116
+ headers: {
1117
+ 'x-api-key': credentials.apiKey,
1118
+ 'Content-Type': 'application/json',
1119
+ },
1120
+ });
512
1121
  }
513
1122
  }
514
1123
  // ==================== BATCH ====================
@@ -525,6 +1134,78 @@ class TornadoApi {
525
1134
  });
526
1135
  }
527
1136
  }
1137
+ // ==================== DASHBOARD ====================
1138
+ if (resource === 'dashboard') {
1139
+ if (operation === 'getStats') {
1140
+ responseData = await this.helpers.httpRequest({
1141
+ method: 'GET',
1142
+ url: `${baseUrl}/dashboard/stats`,
1143
+ json: true,
1144
+ headers: {
1145
+ 'x-api-key': credentials.apiKey,
1146
+ },
1147
+ });
1148
+ }
1149
+ if (operation === 'getJobs') {
1150
+ const options = this.getNodeParameter('dashboardJobsOptions', i);
1151
+ const qs = {};
1152
+ if (options.limit)
1153
+ qs.limit = options.limit;
1154
+ if (options.offset)
1155
+ qs.offset = options.offset;
1156
+ if (options.status)
1157
+ qs.status = options.status;
1158
+ responseData = await this.helpers.httpRequest({
1159
+ method: 'GET',
1160
+ url: `${baseUrl}/dashboard/jobs`,
1161
+ qs,
1162
+ json: true,
1163
+ headers: {
1164
+ 'x-api-key': credentials.apiKey,
1165
+ },
1166
+ });
1167
+ }
1168
+ if (operation === 'getBatches') {
1169
+ responseData = await this.helpers.httpRequest({
1170
+ method: 'GET',
1171
+ url: `${baseUrl}/dashboard/batches`,
1172
+ json: true,
1173
+ headers: {
1174
+ 'x-api-key': credentials.apiKey,
1175
+ },
1176
+ });
1177
+ }
1178
+ if (operation === 'getDaily') {
1179
+ responseData = await this.helpers.httpRequest({
1180
+ method: 'GET',
1181
+ url: `${baseUrl}/dashboard/daily`,
1182
+ json: true,
1183
+ headers: {
1184
+ 'x-api-key': credentials.apiKey,
1185
+ },
1186
+ });
1187
+ }
1188
+ if (operation === 'getCluster') {
1189
+ responseData = await this.helpers.httpRequest({
1190
+ method: 'GET',
1191
+ url: `${baseUrl}/dashboard/cluster`,
1192
+ json: true,
1193
+ headers: {
1194
+ 'x-api-key': credentials.apiKey,
1195
+ },
1196
+ });
1197
+ }
1198
+ if (operation === 'getBilling') {
1199
+ responseData = await this.helpers.httpRequest({
1200
+ method: 'GET',
1201
+ url: `${baseUrl}/dashboard/billing`,
1202
+ json: true,
1203
+ headers: {
1204
+ 'x-api-key': credentials.apiKey,
1205
+ },
1206
+ });
1207
+ }
1208
+ }
528
1209
  // ==================== STORAGE ====================
529
1210
  if (resource === 'storage') {
530
1211
  if (operation === 'configureBucket') {