@nomad-media/public 1.1.12 → 1.1.14

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