@nomad-media/public 1.1.12 → 1.1.13

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.
@@ -0,0 +1,1437 @@
1
+ // account
2
+
3
+
4
+
5
+
6
+
7
+
8
+ // admin
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+ // common
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+ // portal
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+
261
+ // helpers
262
+
263
+
264
+
265
+
266
+ import { promises as fs } from 'fs';
267
+ import path from 'path';
268
+
269
+ /**
270
+ * @class NomadSDK
271
+ * @classdesc This class is used to interact with the Nomad API.
272
+ */
273
+
274
+ class NomadMediaSDK {
275
+ constructor(config = {}) {
276
+ if (NomadMediaSDK.instance)
277
+ {
278
+ return NomadMediaSDK.instance;
279
+ }
280
+
281
+ this.config = config;
282
+ this.token = null;
283
+ this.refreshTokenVal = null;
284
+ this.expirationSeconds = null;
285
+ this.userSessionId = null;
286
+ this.id = null
287
+ this.debugMode = config.debugMode || false;
288
+
289
+ if (this.config.serviceApiUrl[this.config.serviceApiUrl.length - 1] === "/")
290
+ {
291
+ this.config.serviceApiUrl = this.config.serviceApiUrl.slice(0, -1);
292
+ }
293
+
294
+ NomadMediaSDK.instance = this;
295
+
296
+ return this;
297
+ }
298
+
299
+ /**
300
+ * @function init
301
+ * @async
302
+ * @private
303
+ * @description Initializes the SDK. Logs in using the username and password from the config.
304
+ * Then schedules a token refresh for the duration set by the value returned in the login.
305
+ * @returns {Promise<void>} - A promise that resolves when the SDK is initialized.
306
+ * @throws {Error} - An error is thrown if the SDK fails to initialize.
307
+ */
308
+ async _init()
309
+ {
310
+ await this.login();
311
+ }
312
+
313
+ // account functions
314
+ /**
315
+ * @function login
316
+ * @async
317
+ * @description Logs in using the username and password from the config.
318
+ * @returns {Promise<void>} - A promise that resolves when the login is successful.
319
+ * Updates the token, refresh token, expiration seconds, and user session ID class varibles.
320
+ * @throws {Error} - An error is thrown if the login fails.
321
+ */
322
+ async login()
323
+ {
324
+
325
+ _printDatetime(`Logging in as ${this.config.username}`);
326
+
327
+ try
328
+ {
329
+ const LOGIN_INFO = await _login(this, this.config.username, this.config.password,
330
+ this.config.serviceApiUrl, this.debugMode);
331
+ this.token = LOGIN_INFO["token"];
332
+ this.refreshTokenVal = LOGIN_INFO["refreshToken"];
333
+ this.expirationSeconds = LOGIN_INFO["expirationSeconds"];
334
+ this.userSessionId = LOGIN_INFO["userSessionId"];
335
+ this.id = LOGIN_INFO["id"];
336
+ _printDatetime(`Login successful`);
337
+ }
338
+ catch (error)
339
+ {
340
+ _printDatetime(`Login failed`);
341
+ throw error;
342
+ }
343
+ }
344
+
345
+ /**
346
+ * @function logout
347
+ * @async
348
+ * @description Logs out the current user.
349
+ * @returns {Promise<null>} - A promise that resolves when the logout is successful.
350
+ * @throws {Error} - An error is thrown if the logout fails.
351
+ */
352
+ async logout()
353
+ {
354
+ if (this.token === null && this.config.username)
355
+ {
356
+ await this._init();
357
+ }
358
+
359
+ _printDatetime(`Logging out`);
360
+
361
+ try
362
+ {
363
+ await _logout(this, this.token, this.config.serviceApiUrl, this.debugMode);
364
+ this.token = null;
365
+ this.refreshTokenVal = null;
366
+ this.expirationSeconds = null;
367
+ this.userSessionId = null;
368
+ this.id = null;
369
+
370
+ _printDatetime(`Logout successful`);
371
+ }
372
+ catch (error)
373
+ {
374
+ _printDatetime("Loggout failed");
375
+ throw error;
376
+ }
377
+ }
378
+
379
+ /**
380
+ * @function refreshToken
381
+ * @async
382
+ * @description Refreshes the current token.
383
+ * @returns {Promise<void>} - A promise that resolves when the token is refreshed.
384
+ * Updates the token class variable.
385
+ * @throws {Error} - An error is thrown if the token refresh fails.
386
+ */
387
+ async refreshToken()
388
+ {
389
+ _printDatetime(`Refreshing token`);
390
+
391
+ try
392
+ {
393
+ const REFRESHED = await _refreshToken(this, this.token, this.config.serviceApiUrl,
394
+ this.refreshTokenVal, this.debugMode);
395
+ if (REFRESHED) _printDatetime(`Token refresh successful`);
396
+ }
397
+ catch (error)
398
+ {
399
+ _printDatetime(`Token refresh failed`);
400
+ throw error;
401
+ }
402
+ }
403
+
404
+ /**
405
+ * @function forgotPassword
406
+ * @async
407
+ * @description Sends a code to the email to the user to be used
408
+ * be used to reset the password.
409
+ * @returns {Promise<void>}
410
+ * Sends email with code to reset password.
411
+ * @throws {Error} - An error is thrown if the code fails to send.
412
+ */
413
+ async forgotPassword()
414
+ {
415
+ const USERNAME = this.config.username;
416
+
417
+ _printDatetime(`Sending code to ${USERNAME}`);
418
+
419
+ try
420
+ {
421
+ await _forgotPassword(this, this.config.serviceApiUrl, USERNAME, this.debugMode);
422
+ _printDatetime(`Code sent to ${USERNAME}`);
423
+ }
424
+ catch (error)
425
+ {
426
+ _printDatetime(`Code failed to send to ${USERNAME}`);
427
+ throw error;
428
+ }
429
+ }
430
+
431
+ /**
432
+ * @function resetPassword
433
+ * @async
434
+ * @description Resets the password for the specified username.
435
+ * @param {string} CODE - The code to use to reset the password. Sent to the user's email
436
+ * by calling forgotPassword().
437
+ * @param {string} NEW_PASSWORD - The new password to set.
438
+ * @returns {Promise<void>}
439
+ * Resets the password for the specified username.
440
+ * @throws {Error} - An error is thrown if the password fails to reset.
441
+ */
442
+ async resetPassword(CODE, NEW_PASSWORD)
443
+ {
444
+ const USERNAME = this.config.username;
445
+
446
+ _printDatetime(`Resetting password for ${USERNAME}`);
447
+
448
+ try
449
+ {
450
+ await _resetPassword(this, this.config.serviceApiUrl, USERNAME, CODE, NEW_PASSWORD,
451
+ this.debugMode);
452
+ _printDatetime(`Password reset for ${USERNAME}`);
453
+ }
454
+ catch (error)
455
+ {
456
+ _printDatetime(`Password failed to reset for ${USERNAME}`);
457
+ throw error;
458
+ }
459
+ }
460
+
461
+ // media functions
462
+ /**
463
+ * @function clearContinueWatching
464
+ * @async
465
+ * @description Delete continue watching markers.
466
+ * @param {string | null} USER_ID - The user ID of the user to clear the continue watching list.
467
+ * If not user Id is passed it clears the markers of the logged in user.
468
+ * @param {string | null} ASSET_ID - The asset ID of the asset to clear the continue watching
469
+ * list. If not asset Id is passed it clears the markers of all assets.
470
+ * @returns {Promise<void>} - A promise that resolves when the continue watching list is cleared.
471
+ * @throws {Error} - An error is thrown if the continue watching list fails to clear.
472
+ * @throws {Error} - An error is thrown if the API type is not portal.
473
+ */
474
+ async clearContinueWatching(USER_ID, ASSET_ID)
475
+ {
476
+ if (this.token === null && this.config.username)
477
+ {
478
+ await this._init();
479
+ }
480
+
481
+ if (this.config.apiType !== "portal")
482
+ {
483
+ throw new Error("This function is only available for portal API type.");
484
+ }
485
+
486
+ _printDatetime(`Clearing continue watching`);
487
+
488
+ try
489
+ {
490
+ await _clearContinueWatching(this, this.token, this.config.serviceApiUrl, USER_ID, ASSET_ID,
491
+ this.debugMode);
492
+ _printDatetime(`Continue watching cleared`);
493
+ }
494
+ catch (error)
495
+ {
496
+ _printDatetime(`Continue watching failed to clear`);
497
+ throw error;
498
+ }
499
+ }
500
+
501
+ /**
502
+ * @function clearWatchlist
503
+ * @async
504
+ * @description Clears the watchlist.
505
+ * @param {string | null} USER_ID - The user ID of the user to clear the watchlist.
506
+ * If not user Id is passed it clears the watchlist of the logged in user.
507
+ * @returns {Promise<void>} - A promise that resolves when the watchlist is cleared.
508
+ * @throws {Error} - An error is thrown if the watchlist fails to clear.
509
+ * @throws {Error} - An error is thrown if the API type is not portal.
510
+ */
511
+ async clearWatchlist(USER_ID)
512
+ {
513
+ if (this.token === null && this.config.username)
514
+ {
515
+ await this._init();
516
+ }
517
+
518
+ if (this.config.apiType !== "portal")
519
+ {
520
+ throw new Error("This function is only available for portal API type.");
521
+ }
522
+
523
+ _printDatetime(`Clearing watchlist`);
524
+
525
+ try
526
+ {
527
+ USER_ID = USER_ID || this.id;
528
+
529
+ await _clearWatchlist(this, this.token, this.config.serviceApiUrl, USER_ID, this.debugMode);
530
+ _printDatetime(`Watchlist cleared`);
531
+ }
532
+ catch (error)
533
+ {
534
+ _printDatetime(`Watchlist failed to clear`);
535
+ throw error;
536
+ }
537
+ }
538
+
539
+ /**
540
+ * @function createForm
541
+ * @async
542
+ * @description Gets media.
543
+ * @param {string} CONTENT_DEFINITION_ID - The ID of the content definition the form
544
+ * is going in.
545
+ * @param {JSON} FORM_INFO - The information of the form.
546
+ * JSON format: whatever key value pairs you want to add to the form.
547
+ * @returns {Promise<JSON>} - A promise that resolves when the from is created.
548
+ * Returns the id of the form.
549
+ * @throws {Error} - An error is thrown if the media fails to get.
550
+ * @throws {Error} - An error is thrown if the API type is not portal.
551
+ */
552
+ async createForm(CONTENT_DEFINITION_ID, FORM_INFO)
553
+ {
554
+ if (this.token === null && this.config.username)
555
+ {
556
+ await this._init();
557
+ }
558
+
559
+ if (this.config.apiType !== "portal")
560
+ {
561
+ throw new Error("This function is only available for portal API type.");
562
+ }
563
+
564
+ _printDatetime(`Creating form`);
565
+
566
+ try
567
+ {
568
+ const GET_FORMS_INFO = await _createForm(this, this.token, this.config.serviceApiUrl,
569
+ CONTENT_DEFINITION_ID, FORM_INFO, this.debugMode);
570
+ if (GET_FORMS_INFO) _printDatetime(`Form created`);
571
+ return GET_FORMS_INFO;
572
+ }
573
+ catch (error)
574
+ {
575
+ _printDatetime(`Form failed to create`);
576
+ throw error;
577
+ }
578
+ }
579
+
580
+ /**
581
+ * @function getContentCookies
582
+ * @async
583
+ * @description Gets content cookies.
584
+ * @param {string} CONTENT_ID - The Id of the content to retrieve the cookies for.
585
+ * This can be the ID for the content definition of the LiveChannel, or a folder asset
586
+ * ID or a specific Asset ID.
587
+ * @returns {Promise<JSON>} - A promise that resolves when the content cookies are gotten.
588
+ * Returns the information of the gotten content cookies.
589
+ * @throws {Error} - An error is thrown if the content cookies fail to get.
590
+ * @throws {Error} - An error is thrown if the API type is not portal.
591
+ */
592
+ async getContentCookies(CONTENT_ID)
593
+ {
594
+ if (this.token === null && this.config.username)
595
+ {
596
+ await this._init();
597
+ }
598
+
599
+ if (this.config.apiType !== "portal")
600
+ {
601
+ throw new Error("This function is only available for portal API type.");
602
+ }
603
+
604
+ _printDatetime(`Getting content cookies`);
605
+
606
+ try
607
+ {
608
+ const GET_CONTENT_COOKIES_INFO = await _getContentCookies(this, this.token,
609
+ this.config.serviceApiUrl, CONTENT_ID, this.debugMode);
610
+ if (GET_CONTENT_COOKIES_INFO) _printDatetime(`Content cookies gotten`);
611
+ return GET_CONTENT_COOKIES_INFO;
612
+ }
613
+ catch (error)
614
+ {
615
+ _printDatetime(`Content cookies failed to get`);
616
+ throw error;
617
+ }
618
+ }
619
+
620
+ /**
621
+ * @function getDefaultSiteConfig
622
+ * @async
623
+ * @description Gets default site config.
624
+ * @returns {Promise<Array<JSON>>} - A promise that resolves when the default site config is gotten.
625
+ * Returns the information of the gotten dynamic content.
626
+ * @throws {Error} - An error is thrown if the dynamic content fails to get.
627
+ * @throws {Error} - An error is thrown if the API type is not portal.
628
+ */
629
+ async getDefaultSiteConfig()
630
+ {
631
+ if (this.token === null && this.config.username)
632
+ {
633
+ await this._init();
634
+ }
635
+
636
+ if (this.config.apiType !== "portal")
637
+ {
638
+ throw new Error("This function is only available for portal API type.");
639
+ }
640
+
641
+ _printDatetime(`Getting default site config`);
642
+
643
+ try
644
+ {
645
+ const GET_DYNAMIC_CONTENTS_INFO = await _getDefaultSiteConfig(this, this.token,
646
+ this.config.serviceApiUrl, this.debugMode);
647
+ if (GET_DYNAMIC_CONTENTS_INFO) _printDatetime(`Default site config gotten`);
648
+ return GET_DYNAMIC_CONTENTS_INFO;
649
+ }
650
+ catch (error)
651
+ {
652
+ _printDatetime(`Default site config failed to get`);
653
+ throw error;
654
+ }
655
+ }
656
+
657
+ /**
658
+ * @function getDynamicContent
659
+ * @async
660
+ * @description Gets dynamic content.
661
+ * @param {string} DYNAMIC_CONTENT_RECORD_ID - The dynamic content record ID.
662
+ * @returns {Promise<JSON>} - A promise that resolves when the dynamic content is gotten.
663
+ * Returns the information of the gotten dynamic content.
664
+ * @throws {Error} - An error is thrown if the dynamic content fails to get.
665
+ * @throws {Error} - An error is thrown if the API type is not portal.
666
+ */
667
+ async getDynamicContent(DYNAMIC_CONTENT_RECORD_ID)
668
+ {
669
+ if (this.token === null && this.config.username)
670
+ {
671
+ await this._init();
672
+ }
673
+
674
+ _printDatetime(`Getting dynamic content: ${DYNAMIC_CONTENT_RECORD_ID}`);
675
+
676
+ try
677
+ {
678
+ const GET_DYNAMIC_CONTENT_INFO = await _getDynamicContent(this, this.token,
679
+ this.config.serviceApiUrl, DYNAMIC_CONTENT_RECORD_ID, this.debugMode);
680
+ if (GET_DYNAMIC_CONTENT_INFO) _printDatetime(`Dynamic content gotten: ${DYNAMIC_CONTENT_RECORD_ID}`);
681
+ return GET_DYNAMIC_CONTENT_INFO;
682
+ }
683
+ catch (error)
684
+ {
685
+ _printDatetime(`Dynamic content failed to get: ${DYNAMIC_CONTENT_RECORD_ID}`);
686
+ throw error;
687
+ }
688
+ }
689
+
690
+ /**
691
+ * @function getDynamicContents
692
+ * @async
693
+ * @description Gets dynamic contents.
694
+ * @returns {Promise<Array<JSON>>} - A promise that resolves when the dynamic contents is gotten.
695
+ * Returns the information of the gotten dynamic content.
696
+ * @throws {Error} - An error is thrown if the dynamic content fails to get.
697
+ * @throws {Error} - An error is thrown if the API type is not portal.
698
+ */
699
+ async getDynamicContents()
700
+ {
701
+ if (this.token === null && this.config.username)
702
+ {
703
+ await this._init();
704
+ }
705
+
706
+ if (this.config.apiType !== "portal")
707
+ {
708
+ throw new Error("This function is only available for portal API type.");
709
+ }
710
+
711
+ _printDatetime(`Getting dynamic contents`);
712
+
713
+ try
714
+ {
715
+ const GET_DYNAMIC_CONTENTS_INFO = await _getDynamicContents(this, this.token,
716
+ this.config.serviceApiUrl, this.debugMode);
717
+ if (GET_DYNAMIC_CONTENTS_INFO) _printDatetime(`Dynamic contents gotten`);
718
+ return GET_DYNAMIC_CONTENTS_INFO;
719
+ }
720
+ catch (error)
721
+ {
722
+ _printDatetime(`Dynamic contents failed to get`);
723
+ throw error;
724
+ }
725
+ }
726
+
727
+ /**
728
+ * @function getMediaGroup
729
+ * @async
730
+ * @description Gets media group.
731
+ * @param {string} MEDIA_GROUP_ID - The ID of the media group.
732
+ * @returns {Promise<JSON>} - A promise that resolves when the media group is gotten.
733
+ * Returns the information of the gotten media group.
734
+ * @throws {Error} - An error is thrown if the media group fails to get.
735
+ * @throws {Error} - An error is thrown if the API type is not portal.
736
+ */
737
+ async getMediaGroup(MEDIA_GROUP_ID)
738
+ {
739
+ if (this.token === null && this.config.username)
740
+ {
741
+ await this._init();
742
+ }
743
+
744
+ if (this.config.apiType !== "portal")
745
+ {
746
+ throw new Error("This function is only available for portal API type.");
747
+ }
748
+
749
+ _printDatetime(`Getting media group: ${MEDIA_GROUP_ID}`);
750
+
751
+ try
752
+ {
753
+ const GET_MEDIA_GROUP_INFO = await _getMediaGroup(this, this.token, this.config.serviceApiUrl,
754
+ MEDIA_GROUP_ID, this.debugMode);
755
+ if (GET_MEDIA_GROUP_INFO) _printDatetime(`Media group gotten: ${MEDIA_GROUP_ID}`);
756
+ return GET_MEDIA_GROUP_INFO;
757
+ }
758
+ catch (error)
759
+ {
760
+ _printDatetime(`Media group failed to get: ${MEDIA_GROUP_ID}`);
761
+ throw error;
762
+ }
763
+ }
764
+
765
+ /**
766
+ * @function getMediaItem
767
+ * @async
768
+ * @description Gets media item.
769
+ * @param {string} MEDIA_ITEM_ID - The ID of the media item.
770
+ * @returns {Promise<JSON>} - A promise that resolves when the media item is gotten.
771
+ * Returns the information of the gotten media item.
772
+ * @throws {Error} - An error is thrown if the media item fails to get.
773
+ * @throws {Error} - An error is thrown if the API type is not portal.
774
+ */
775
+ async getMediaItem(MEDIA_ITEM_ID)
776
+ {
777
+ if (this.token === null && this.config.username)
778
+ {
779
+ await this._init();
780
+ }
781
+
782
+ if (this.config.apiType !== "portal")
783
+ {
784
+ throw new Error("This function is only available for portal API type.");
785
+ }
786
+
787
+ _printDatetime(`Getting media item: ${MEDIA_ITEM_ID}`);
788
+
789
+ try
790
+ {
791
+ const GET_MEDIA_ITEM_INFO = await _getMediaItem(this, this.token, this.config.serviceApiUrl,
792
+ MEDIA_ITEM_ID, this.debugMode);
793
+ if (GET_MEDIA_ITEM_INFO) _printDatetime(`Media item gotten: ${MEDIA_ITEM_ID}`);
794
+ return GET_MEDIA_ITEM_INFO;
795
+ }
796
+ catch (error)
797
+ {
798
+ _printDatetime(`Media item failed to get: ${MEDIA_ITEM_ID}`);
799
+ throw error;
800
+ }
801
+ }
802
+
803
+ /**
804
+ * @function getMyContent
805
+ * @async
806
+ * @description Gets favorites and continue watching lists of IDs for the logged in user.
807
+ * @returns {Promise<JSON>} - A promise that resolves when the favorites and continue watching
808
+ * lists of IDs are gotten.
809
+ * Returns the information of the gotten favorites and continue watching lists of IDs.
810
+ * @throws {Error} - An error is thrown if the favorites and continue watching lists of IDs fail
811
+ * to get.
812
+ * @throws {Error} - An error is thrown if the API type is not portal.
813
+ */
814
+ async getMyContent()
815
+ {
816
+ if (this.token === null && this.config.username)
817
+ {
818
+ await this._init();
819
+ }
820
+
821
+ if (this.config.apiType !== "portal")
822
+ {
823
+ throw new Error("This function is not available for portal API type.");
824
+ }
825
+
826
+ _printDatetime(`Getting my content`);
827
+
828
+ try
829
+ {
830
+ const GET_MY_CONTENT_INFO = await _getMyContent(this, this.token, this.config.serviceApiUrl,
831
+ this.debugMode);
832
+ if (GET_MY_CONTENT_INFO) _printDatetime(`My content gotten`);
833
+ return GET_MY_CONTENT_INFO;
834
+ }
835
+ catch (error)
836
+ {
837
+ _printDatetime(`My content failed to get`);
838
+ throw error;
839
+ }
840
+ }
841
+
842
+ /**
843
+ * @function getMyGroup
844
+ * @async
845
+ * @description Gets user's group.
846
+ * @param {string} GROUP_ID - The ID of the group.
847
+ * @returns {Promise<JSON>} - A promise that resolves when the user's group is gotten.
848
+ * Returns the information of the gotten user's group.
849
+ * @throws {Error} - An error is thrown if the user's group fails to get.
850
+ * @throws {Error} - An error is thrown if the API type is not portal.
851
+ */
852
+ async getMyGroup(GROUP_ID)
853
+ {
854
+ if (this.token === null && this.config.username)
855
+ {
856
+ await this._init();
857
+ }
858
+
859
+ _printDatetime(`Getting my group: ${GROUP_ID}`);
860
+
861
+ try
862
+ {
863
+ const GET_MY_GROUP_INFO = await _getMyGroup(this, this.token, this.config.serviceApiUrl,
864
+ GROUP_ID, this.debugMode);
865
+ if (GET_MY_GROUP_INFO) _printDatetime(`My group gotten: ${GROUP_ID}`);
866
+ return GET_MY_GROUP_INFO;
867
+ }
868
+ catch (error)
869
+ {
870
+ _printDatetime(`My group failed to get: ${GROUP_ID}`);
871
+ throw error;
872
+ }
873
+ }
874
+
875
+ /**
876
+ * @function getSiteConfig
877
+ * @async
878
+ * @description Gets site config.
879
+ * @param {string} SITE_CONFIG_RECORD_ID - The site config record ID.
880
+ * @returns {Promise<JSON>} - A promise that resolves when the site config is gotten.
881
+ * Returns the information of the gotten site config.
882
+ * @throws {Error} - An error is thrown if the site config fails to get.
883
+ * @throws {Error} - An error is thrown if the API type is not portal.
884
+ */
885
+ async getSiteConfig(SITE_CONFIG_RECORD_ID)
886
+ {
887
+ if (this.token === null && this.config.username)
888
+ {
889
+ await this._init();
890
+ }
891
+
892
+ _printDatetime(`Getting site config: ${SITE_CONFIG_RECORD_ID}`);
893
+
894
+ try
895
+ {
896
+ const GET_DYNAMIC_CONTENT_INFO = await _getSiteConfig(this, this.token,
897
+ this.config.serviceApiUrl, SITE_CONFIG_RECORD_ID, this.debugMode);
898
+ if (GET_DYNAMIC_CONTENT_INFO) _printDatetime(`Site config gotten: ${SITE_CONFIG_RECORD_ID}`);
899
+ return GET_DYNAMIC_CONTENT_INFO;
900
+ }
901
+ catch (error)
902
+ {
903
+ _printDatetime(`Site config failed to get: ${SITE_CONFIG_RECORD_ID}`);
904
+ throw error;
905
+ }
906
+ }
907
+
908
+ /**
909
+ * @function mediaSearch
910
+ * @async
911
+ * @description Searches for media.
912
+ * @param {string | null} QUERY - The query of the search.
913
+ * @param {Array<string> | null} IDS - The IDs of the media to be searched.
914
+ * @param {Array<JSON> | null} SORT_FIELDS - The sort fields of the search.
915
+ * JSON format: [{"fieldName": "string", "sortType": ("Ascending" | "Descending")} ...]
916
+ * @param {number | null} OFFSET - The page offset of the search.
917
+ * @param {number | null} SIZE - The page size of the search.
918
+ * @returns {Promise<JSON>} - A promise that resolves when the media are searched.
919
+ * Returns the information of the searched media.
920
+ * @throws {Error} - An error is thrown if the media fail to search.
921
+ * @throws {Error} - An error is thrown if the API type is not portal.
922
+ */
923
+ async mediaSearch(QUERY, IDS, SORT_FIELDS, OFFSET, SIZE)
924
+ {
925
+ if (this.token === null && this.config.username)
926
+ {
927
+ await this._init();
928
+ }
929
+
930
+ if (this.config.apiType !== "portal")
931
+ {
932
+ throw new Error("This function is only available for portal API type.");
933
+ }
934
+
935
+ _printDatetime(`Searching media...`);
936
+
937
+ try
938
+ {
939
+ const MEDIA_SEARCH_INFO = await _mediaSearch(this, this.token, this.config.serviceApiUrl,
940
+ QUERY, IDS, SORT_FIELDS, OFFSET, SIZE, this.debugMode);
941
+ if (MEDIA_SEARCH_INFO) _printDatetime(`Media search complete`);
942
+ return MEDIA_SEARCH_INFO;
943
+ }
944
+ catch (error)
945
+ {
946
+ _printDatetime(`Media search failed`);
947
+ throw error;
948
+ }
949
+ }
950
+
951
+ // misc functions
952
+ /**
953
+ * @function miscFunctons
954
+ * @async
955
+ * @description Calls any nomad function given URL method and body.
956
+ * @param {string} URL_PATH - The URL path of the function.
957
+ * @param {string} METHOD - The method of the function.
958
+ * @param {JSON | null} BODY - The body of the api call.
959
+ * @param {boolean | null} NOT_API_PATH - If the path has /api.
960
+ * @returns {Promise<JSON>} - A promise that resolves when the function is called.
961
+ * Returns the information of the called function.
962
+ * @throws {Error} - An error is thrown if the function fails to call.
963
+ */
964
+
965
+ async miscFunctions(URL_PATH, METHOD, BODY, NOT_API_PATH)
966
+ {
967
+ if (this.token === null && this.config.username)
968
+ {
969
+ await this._init();
970
+ }
971
+
972
+ _printDatetime(`Calling function: ${URL_PATH}`);
973
+
974
+ try
975
+ {
976
+ let API_URL = `${this.config.serviceApiUrl}/${URL_PATH}`;
977
+ if (NOT_API_PATH) {
978
+ API_URL = API_URL.replace('/api', '');
979
+ API_URL = API_URL.replace('app-api.', '');
980
+ API_URL = API_URL.replace('admin-app.', '');
981
+ }
982
+
983
+ const HEADERS = new Headers();
984
+ HEADERS.append("Content-Type", "application/json");
985
+
986
+ if (this.token !== null)
987
+ {
988
+ HEADERS.append("Authorization", `Bearer ${this.token}`);
989
+ }
990
+
991
+ if (this.debugMode)
992
+ {
993
+ console.log(`URL: ${API_URL}\nMETHOD: ${METHOD}`);
994
+ if (BODY) console.log(`BODY: ${JSON.stringify(BODY, null, 4 )}`);
995
+ }
996
+
997
+ const REQUEST = {
998
+ method: METHOD,
999
+ headers: HEADERS
1000
+ };
1001
+ if (BODY) {
1002
+ REQUEST.body = JSON.stringify(BODY);
1003
+ }
1004
+
1005
+ const RESPONSE = await fetch(API_URL, REQUEST);
1006
+
1007
+ const RESPONSE_BODY = await RESPONSE.text();
1008
+ if (!RESPONSE.ok)
1009
+ {
1010
+ try
1011
+ {
1012
+ throw JSON.parse(RESPONSE_BODY);
1013
+ }
1014
+ catch (error)
1015
+ {
1016
+ throw RESPONSE_BODY;
1017
+ }
1018
+ }
1019
+
1020
+ try
1021
+ {
1022
+ return JSON.parse(RESPONSE_BODY);
1023
+ }
1024
+ catch (error)
1025
+ {
1026
+ return RESPONSE_BODY;
1027
+ }
1028
+ }
1029
+ catch (error)
1030
+ {
1031
+ _apiExceptionHandler(error, "API call failed");
1032
+ }
1033
+ }
1034
+ }
1035
+
1036
+ export default NomadMediaSDK;
1037
+
1038
+
1039
+
1040
+ async function _forgotPassword(instance, URL, USERNAME, DEBUG_MODE)
1041
+ {
1042
+ const API_URL = `${URL}/api/account/forgot-password`;
1043
+
1044
+ const BODY = {
1045
+ username: USERNAME
1046
+ };
1047
+
1048
+ return await _sendRequest(instance, null, "Forgot Password", API_URL, "POST", null, BODY, DEBUG_MODE);
1049
+ }
1050
+
1051
+
1052
+
1053
+
1054
+ async function _login(instance, USERNAME, PASSWORD, URL, DEBUG_MODE)
1055
+ {
1056
+ const API_URL = `${URL}/api/account/login`;
1057
+
1058
+ const BODY = {
1059
+ "userName": USERNAME,
1060
+ "password": PASSWORD
1061
+ };
1062
+
1063
+ try
1064
+ {
1065
+ return await _sendRequest(instance, null, "Login", API_URL, "POST", null, BODY, DEBUG_MODE);
1066
+ }
1067
+ catch (error)
1068
+ {
1069
+ if (error.message.includes("409"))
1070
+ {
1071
+ throw new Error("Invalid username or password");
1072
+ }
1073
+ else
1074
+ {
1075
+ throw error;
1076
+ }
1077
+ }
1078
+ }
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+ async function _logout(instance, AUTH_TOKEN, URL, DEBUG_MODE)
1085
+ {
1086
+ const API_URL = `${URL}/api/account/logout`;
1087
+
1088
+ return await _sendRequest(instance, AUTH_TOKEN, "Logout", API_URL, "POST", null, null, DEBUG_MODE);
1089
+ }
1090
+
1091
+
1092
+
1093
+
1094
+
1095
+
1096
+
1097
+ async function _refreshToken(instance, AUTH_TOKEN, URL, REFRESH_TOKEN, DEBUG_MODE)
1098
+ {
1099
+ const API_URL = `${URL}/api/account/refresh-token`;
1100
+
1101
+ const BODY = {
1102
+ refreshToken: REFRESH_TOKEN
1103
+ };
1104
+
1105
+ const TOKEN_INFO = await _sendRequest(instance, AUTH_TOKEN, "Refreshing Token", API_URL, "POST", null, BODY, DEBUG_MODE);
1106
+ instance.token = TOKEN_INFO.token;
1107
+
1108
+ return true;
1109
+ }
1110
+
1111
+
1112
+
1113
+
1114
+
1115
+ async function _resetPassword(instance, URL, USERNAME, TOKEN, NEW_PASSWORD, DEBUG_MODE)
1116
+ {
1117
+ const API_URL = `${URL}/api/account/reset-password`;
1118
+
1119
+ const BODY = {
1120
+ userName: USERNAME,
1121
+ TOKEN: TOKEN,
1122
+ newPassword: NEW_PASSWORD
1123
+ };
1124
+
1125
+ return await _sendRequest(instance, null, "Reset Password", API_URL, "POST", null, BODY, DEBUG_MODE);
1126
+ }
1127
+
1128
+
1129
+ function _apiExceptionHandler(error, message) {
1130
+ // Check if we have a response object and error message
1131
+ if (!error) {
1132
+ console.error(message);
1133
+ }
1134
+
1135
+ // Check if error is a string
1136
+ if (typeof error === "string") {
1137
+ console.error(`${message}: ${error}`);
1138
+ }
1139
+ else if (error.errors)
1140
+ {
1141
+ if (Array.isArray(error.errors)) {
1142
+ let errorString = "";
1143
+ for (let errorIdx = 0; errorIdx < error.errors.length; errorIdx++)
1144
+ {
1145
+ errorString += `${error.errors[errorIdx].code}: ${error.errors[errorIdx].field}: ${error.errors[errorIdx].message}\n`;
1146
+ }
1147
+ console.error(`${message}: ${errorString}`);
1148
+ }
1149
+ else if (typeof error.errors === "object") {
1150
+ let errorString = "";
1151
+ for (let key in error.errors) {
1152
+ if (Object.prototype.hasOwnProperty.call(error.errors, key)) {
1153
+ errorString += `${key}: ${error.errors[key]}\n`;
1154
+ }
1155
+ }
1156
+ console.error(`${message}: ${errorString}`);
1157
+ }
1158
+ }
1159
+ else
1160
+ {
1161
+ console.error(`${message}: ${error.message}`);
1162
+ }
1163
+
1164
+ return null;
1165
+ }
1166
+
1167
+
1168
+ /**
1169
+ * New GUID
1170
+ *
1171
+ * @returns UUID v4 GUID
1172
+ */
1173
+
1174
+ import { getRandomValues } from 'crypto';
1175
+
1176
+ function _newGuid() {
1177
+ return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
1178
+ (c ^ (getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
1179
+ );
1180
+ }
1181
+
1182
+
1183
+
1184
+ function _printDatetime(msg)
1185
+ {
1186
+ const NOW = new Date();
1187
+ const FORMATTED_TIME = NOW.toLocaleTimeString();
1188
+ console.log(`${FORMATTED_TIME}: ${msg}`);
1189
+ }
1190
+
1191
+
1192
+
1193
+
1194
+
1195
+
1196
+ import axios from 'axios';
1197
+
1198
+ const MAX_RETRIES = 5;
1199
+ const TIMEOUT = 30000;
1200
+ const SLEEP_TIME = .5;
1201
+
1202
+ async function _sendRequest(instance, AUTH_TOKEN, FUNCTION_NAME, URL, METHOD_TYPE, PARAMS, BODY, DEBUG)
1203
+ {
1204
+ const HEADERS = {
1205
+ "Content-Type": "application/json"
1206
+ };
1207
+
1208
+ if (AUTH_TOKEN) HEADERS["Authorization"] = `Bearer ${AUTH_TOKEN}`;
1209
+
1210
+ if (DEBUG && FUNCTION_NAME !== "Login") console.log(`URL: ${URL}\nMETHOD: ${METHOD_TYPE}` + (PARAMS && PARAMS.size === 0 ? `\nPARAMS: ${JSON.stringify(PARAMS, null, 4)}` : "") + (BODY ? `\nBODY: ${JSON.stringify(BODY, null, 4)}` : ""));
1211
+
1212
+ let retries = 0;
1213
+ let RESPONSE = null;
1214
+ let refreshedToken = false;
1215
+ do
1216
+ {
1217
+ try
1218
+ {
1219
+ refreshedToken = true;
1220
+ RESPONSE = await axios({
1221
+ method: METHOD_TYPE,
1222
+ url: URL,
1223
+ headers: HEADERS,
1224
+ params: PARAMS,
1225
+ data: BODY,
1226
+ timeout: TIMEOUT
1227
+ });
1228
+
1229
+ if (RESPONSE.status >= 200 && RESPONSE.status < 300)
1230
+ {
1231
+ break;
1232
+ }
1233
+
1234
+ throw new Error();
1235
+ }
1236
+ catch (error)
1237
+ {
1238
+ if (error?.response?.status === 403 && FUNCTION_NAME !== "Refresh Token" && !refreshedToken)
1239
+ {
1240
+ await instance.refreshToken();
1241
+ HEADERS["Authorization"] = `Bearer ${instance.token}`;
1242
+ refreshedToken = true;
1243
+ }
1244
+ else if (error.code === 'ECONNABORTED')
1245
+ {
1246
+ await _sleep(SLEEP_TIME * 2 ** (retries - 1));
1247
+ }
1248
+ else
1249
+ {
1250
+ return _apiExceptionHandler(error.response?.data.message ? error.response.data.message : error.message, `${FUNCTION_NAME} failed`);
1251
+ }
1252
+ ++retries;
1253
+ }
1254
+ } while ((!RESPONSE || RESPONSE.status < 200 || RESPONSE.status >= 300) && retries < MAX_RETRIES);
1255
+ try { return RESPONSE.data; }
1256
+ catch (error) { return; }
1257
+ }
1258
+
1259
+
1260
+ async function _sleep(duration) {
1261
+ // Check for valid duration
1262
+ if (!duration || duration === 0) {
1263
+ // Ignore
1264
+ return;
1265
+ }
1266
+
1267
+ // Sleep
1268
+ return new Promise((resolve) => {
1269
+ setTimeout(() => {
1270
+ resolve();
1271
+ }, duration * 1000);
1272
+ });
1273
+ }
1274
+
1275
+
1276
+
1277
+ function _slugify(text) {
1278
+ if (!text || text.trim().length === 0) return "";
1279
+ return text
1280
+ .toString()
1281
+ .normalize("NFD")
1282
+ .replace(/[\u0300-\u036f]/g, "")
1283
+ .toLowerCase()
1284
+ .trim()
1285
+ .replace(/\s+/g, "-")
1286
+ .replace(/[^\w-]+/g, "")
1287
+ .replace(/--+/g, "-");
1288
+ }
1289
+
1290
+
1291
+
1292
+
1293
+
1294
+ async function _clearContinueWatching(instance, AUTH_TOKEN, URL, USER_ID, ASSET_ID, DEBUG_MODE)
1295
+ {
1296
+ const API_URL = `${URL}/api/media/clear-watching`;
1297
+
1298
+ const PARAMS = {
1299
+ userId: USER_ID,
1300
+ assetId: ASSET_ID
1301
+ };
1302
+
1303
+ return await _sendRequest(instance, AUTH_TOKEN, "Clear Continue Watching", API_URL, "POST", PARAMS, null, DEBUG_MODE);
1304
+ }
1305
+
1306
+
1307
+
1308
+
1309
+ async function _clearWatchlist(instance, AUTH_TOKEN, URL, USER_ID, DEBUG_MODE)
1310
+ {
1311
+ const API_URL = `${URL}/api/media/clear-watchlist?userId=${USER_ID}`;
1312
+
1313
+ return await _sendRequest(instance, AUTH_TOKEN, "Clear Watchlist", API_URL, "POST", null, null, DEBUG_MODE);
1314
+ }
1315
+
1316
+
1317
+
1318
+
1319
+ async function _createForm(instance, AUTH_TOKEN, URL, CONTENT_DEFINITION_ID, FORM_INFO, DEBUG_MODE)
1320
+ {
1321
+ const API_URL = `${URL}/api/media/form/${CONTENT_DEFINITION_ID}`;
1322
+
1323
+ const BODY = FORM_INFO;
1324
+
1325
+ return await _sendRequest(instance, AUTH_TOKEN, "Creating Form", API_URL, "POST", null, BODY, DEBUG_MODE);
1326
+ }
1327
+
1328
+
1329
+
1330
+
1331
+ async function _getContentCookies(instance, AUTH_TOKEN, URL, ID, DEBUG_MODE)
1332
+ {
1333
+ const API_URL = `${URL}/api/media/set-cookies/${ID}`;
1334
+
1335
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Content Cookies", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1336
+ }
1337
+
1338
+
1339
+
1340
+
1341
+ async function _getDefaultSiteConfig(instance, AUTH_TOKEN, URL, DEBUG_MODE)
1342
+ {
1343
+ const API_URL = `${URL}/api/media/config`;
1344
+
1345
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Default Site Config", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1346
+ }
1347
+
1348
+
1349
+
1350
+
1351
+ async function _getDynamicContent(instance, AUTH_TOKEN, URL, ID, DEBUG_MODE)
1352
+ {
1353
+ const API_URL = `${URL}/api/media/content/${ID}`;
1354
+
1355
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Dynamic Content", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1356
+ }
1357
+
1358
+
1359
+
1360
+
1361
+ async function _getDynamicContents(instance, AUTH_TOKEN, URL, DEBUG_MODE)
1362
+ {
1363
+ const API_URL = `${URL}/api/media/content`;
1364
+
1365
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Dynamic Contents", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1366
+ }
1367
+
1368
+
1369
+
1370
+
1371
+ async function _getMediaGroup(instance, AUTH_TOKEN, URL, ID, DEBUG_MODE)
1372
+ {
1373
+ const API_URL = `${URL}/api/media/group/${ID}`;
1374
+
1375
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Media Group", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1376
+ }
1377
+
1378
+
1379
+
1380
+
1381
+ async function _getMediaItem(instance, AUTH_TOKEN, URL, ID, DEBUG_MODE)
1382
+ {
1383
+ const API_URL = `${URL}/api/media/item/${ID}`;
1384
+
1385
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Media Item", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1386
+ }
1387
+
1388
+
1389
+
1390
+
1391
+ async function _getMyContent(instance, AUTH_TOKEN, URL, DEBUG_MODE)
1392
+ {
1393
+ const API_URL = `${URL}/api/media/my-content`;
1394
+
1395
+ return await _sendRequest(instance, AUTH_TOKEN, "Get My Content", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1396
+ }
1397
+
1398
+
1399
+
1400
+
1401
+ async function _getMyGroup(instance, AUTH_TOKEN, URL, ID, DEBUG_MODE)
1402
+ {
1403
+ const API_URL = `${URL}/api/media/my-group/${ID}`;
1404
+
1405
+ return await _sendRequest(instance, AUTH_TOKEN, "Get My Group", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1406
+ }
1407
+
1408
+
1409
+
1410
+
1411
+ async function _getSiteConfig(instance, AUTH_TOKEN, URL, ID, DEBUG_MODE)
1412
+ {
1413
+ const API_URL = `${URL}/api/media/config/${ID}`;
1414
+
1415
+ return await _sendRequest(instance, AUTH_TOKEN, "Get Site Config", API_URL, "GET", undefined, undefined, DEBUG_MODE);
1416
+ }
1417
+
1418
+
1419
+
1420
+
1421
+ async function _mediaSearch(instance, AUTH_TOKEN, URL, SEARCH_QUERY, IDS, SORT_FIELDS,
1422
+ PAGE_OFFSET, PAGE_SIZE, DEBUG_MODE)
1423
+ {
1424
+ const API_URL = `${URL}/api/media/search`;
1425
+
1426
+ const BODY = {
1427
+ searchQuery: SEARCH_QUERY,
1428
+ ids: IDS,
1429
+ sortFields: SORT_FIELDS
1430
+ };
1431
+
1432
+ PAGE_OFFSET ? BODY["pageOffset"] = PAGE_OFFSET : BODY["pageOffset"] = 0;
1433
+ PAGE_SIZE ? BODY["pageSize"] = PAGE_SIZE : BODY["pageSize"] = 100;
1434
+
1435
+ return await _sendRequest(instance, AUTH_TOKEN, "Media Search", API_URL, "POST", null, BODY, DEBUG_MODE);
1436
+ }
1437
+