@eluvio/elv-client-js 4.0.104 → 4.0.107
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.
- package/dist/ElvClient-min.js +15 -14
- package/dist/ElvClient-node-min.js +14 -13
- package/dist/ElvFrameClient-min.js +10 -10
- package/dist/ElvPermissionsClient-min.js +9 -9
- package/dist/ElvWalletClient-min.js +15 -14
- package/dist/ElvWalletClient-node-min.js +14 -13
- package/dist/src/AuthorizationClient.js +9 -12
- package/dist/src/ContentObjectAudit.js +3 -3
- package/dist/src/ContentObjectVerification.js +3 -3
- package/dist/src/Crypto.js +2 -2
- package/dist/src/ElvClient.js +47 -28
- package/dist/src/ElvWallet.js +7 -5
- package/dist/src/EthClient.js +8 -9
- package/dist/src/FrameClient.js +8 -9
- package/dist/src/HttpClient.js +1 -2
- package/dist/src/Id.js +1 -2
- package/dist/src/PermissionsClient.js +31 -19
- package/dist/src/RemoteSigner.js +10 -11
- package/dist/src/UserProfileClient.js +194 -150
- package/dist/src/Utils.js +2 -3
- package/dist/src/abr_profiles/abr_profile_live_drm.js +22 -0
- package/dist/src/client/ABRPublishing.js +2 -2
- package/dist/src/client/AccessGroups.js +2 -2
- package/dist/src/client/ContentAccess.js +9 -6
- package/dist/src/client/ContentManagement.js +3 -3
- package/dist/src/client/Contracts.js +433 -108
- package/dist/src/client/Files.js +2 -2
- package/dist/src/client/LiveConf.js +60 -78
- package/dist/src/client/LiveStream.js +270 -158
- package/dist/src/client/NFT.js +2 -2
- package/dist/src/walletClient/ClientMethods.js +2 -2
- package/dist/src/walletClient/Profile.js +2 -2
- package/dist/src/walletClient/Utils.js +2 -2
- package/dist/src/walletClient/index.js +19 -16
- package/package.json +1 -1
- package/src/UserProfileClient.js +19 -20
- package/src/abr_profiles/abr_profile_live_drm.js +22 -0
- package/src/client/Contracts.js +244 -42
- package/src/client/LiveConf.js +86 -111
- package/src/client/LiveStream.js +141 -44
- package/testScripts/TestAddTenantContractId.js +45 -4
package/src/client/LiveConf.js
CHANGED
|
@@ -1,53 +1,48 @@
|
|
|
1
|
-
const
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
representation: "videovideo_960x540_h264@900000",
|
|
47
|
-
stream_name: "video",
|
|
48
|
-
stream_index: 0,
|
|
49
|
-
width: 960
|
|
50
|
-
}
|
|
1
|
+
const DefaultABRLadder = {
|
|
2
|
+
"video" : [
|
|
3
|
+
{
|
|
4
|
+
bit_rate: 14000000,
|
|
5
|
+
codecs: "avc1.640028,mp4a.40.2",
|
|
6
|
+
height: 2160,
|
|
7
|
+
width: 3840
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
bit_rate: 9500000,
|
|
11
|
+
codecs: "avc1.640028,mp4a.40.2",
|
|
12
|
+
height: 1080,
|
|
13
|
+
width: 1920
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
bit_rate: 4500000,
|
|
17
|
+
codecs: "avc1.640028,mp4a.40.2",
|
|
18
|
+
height: 720,
|
|
19
|
+
width: 1280
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
bit_rate: 2000000,
|
|
23
|
+
codecs: "avc1.640028,mp4a.40.2",
|
|
24
|
+
height: 540,
|
|
25
|
+
width: 960
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
bit_rate: 900000,
|
|
29
|
+
codecs: "avc1.640028,mp4a.40.2",
|
|
30
|
+
height: 540,
|
|
31
|
+
width: 960
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"audio" : [
|
|
35
|
+
{
|
|
36
|
+
bit_rate: 192000,
|
|
37
|
+
channels: 2,
|
|
38
|
+
codecs: "mp4a.40.2",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
bit_rate: 384000,
|
|
42
|
+
channels: 6,
|
|
43
|
+
codecs: "mp4a.40.2",
|
|
44
|
+
}
|
|
45
|
+
]
|
|
51
46
|
};
|
|
52
47
|
|
|
53
48
|
const LiveconfTemplate = {
|
|
@@ -115,16 +110,6 @@ const LiveconfTemplate = {
|
|
|
115
110
|
}
|
|
116
111
|
};
|
|
117
112
|
|
|
118
|
-
const LadderSpecAudio = {
|
|
119
|
-
bit_rate: 384000,
|
|
120
|
-
channels: 2,
|
|
121
|
-
codecs: "mp4a.40.2",
|
|
122
|
-
media_type: 2,
|
|
123
|
-
representation: "audioaudio_aac@384000",
|
|
124
|
-
stream_name: "audio",
|
|
125
|
-
stream_index: 0
|
|
126
|
-
};
|
|
127
|
-
|
|
128
113
|
class LiveConf {
|
|
129
114
|
constructor(probeData, nodeId, nodeUrl, includeAVSegDurations, overwriteOriginUrl, syncAudioToVideo) {
|
|
130
115
|
this.probeData = probeData;
|
|
@@ -390,7 +375,7 @@ class LiveConf {
|
|
|
390
375
|
generateAudioStreamsConfig({customSettings}) {
|
|
391
376
|
|
|
392
377
|
let audioStreams = {};
|
|
393
|
-
if(customSettings && customSettings.audio) {
|
|
378
|
+
if(customSettings && customSettings.audio && Object.keys(customSettings.audio).length > 0) {
|
|
394
379
|
for(let i = 0; i < Object.keys(customSettings.audio).length; i ++) {
|
|
395
380
|
let audioIdx = Object.keys(customSettings.audio)[i];
|
|
396
381
|
let audio = customSettings.audio[audioIdx];
|
|
@@ -405,7 +390,7 @@ class LiveConf {
|
|
|
405
390
|
}
|
|
406
391
|
|
|
407
392
|
// If no audio streams specified in custom config, set up all the suitable audio streams in the probe
|
|
408
|
-
if(!customSettings.audio) {
|
|
393
|
+
if(!customSettings.audio || Object.keys(customSettings.audio).length == 0) {
|
|
409
394
|
audioStreams = this.getAudioStreamsFromProbe();
|
|
410
395
|
}
|
|
411
396
|
|
|
@@ -506,68 +491,57 @@ class LiveConf {
|
|
|
506
491
|
conf.live_recording.recording_config.recording_params.xc_params.video_frame_duration_ts = segDurations.videoFrameDurationTs;
|
|
507
492
|
}
|
|
508
493
|
|
|
509
|
-
|
|
510
|
-
case 2160:
|
|
511
|
-
conf.live_recording.recording_config.recording_params.ladder_specs.unshift(
|
|
512
|
-
LadderTemplate[2160],
|
|
513
|
-
LadderTemplate[1080],
|
|
514
|
-
LadderTemplate[720],
|
|
515
|
-
LadderTemplate[540],
|
|
516
|
-
LadderTemplate["540_low"]
|
|
517
|
-
);
|
|
518
|
-
conf.live_recording.recording_config.recording_params.xc_params.video_bitrate = LadderTemplate[2160].bit_rate;
|
|
519
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_height = 2160;
|
|
520
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_width = 3840;
|
|
494
|
+
const ladderProfile = customSettings.ladder_profile || DefaultABRLadder;
|
|
521
495
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
conf.live_recording.recording_config.recording_params.ladder_specs.unshift(
|
|
525
|
-
LadderTemplate[1080],
|
|
526
|
-
LadderTemplate[720],
|
|
527
|
-
LadderTemplate[540],
|
|
528
|
-
LadderTemplate["540_low"]
|
|
529
|
-
);
|
|
530
|
-
conf.live_recording.recording_config.recording_params.xc_params.video_bitrate = LadderTemplate[1080].bit_rate;
|
|
531
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_height = 1080;
|
|
532
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_width = 1920;
|
|
533
|
-
break;
|
|
534
|
-
case 720:
|
|
535
|
-
conf.live_recording.recording_config.recording_params.ladder_specs.unshift(
|
|
536
|
-
LadderTemplate[720],
|
|
537
|
-
LadderTemplate[540],
|
|
538
|
-
LadderTemplate["540_low"]
|
|
539
|
-
);
|
|
540
|
-
conf.live_recording.recording_config.recording_params.xc_params.video_bitrate = LadderTemplate[720].bit_rate;
|
|
541
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_height = 720;
|
|
542
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_width = 1280;
|
|
543
|
-
break;
|
|
544
|
-
case 540:
|
|
545
|
-
conf.live_recording.recording_config.recording_params.ladder_specs.unshift(
|
|
546
|
-
LadderTemplate[540],
|
|
547
|
-
LadderTemplate["540_low"]
|
|
548
|
-
);
|
|
549
|
-
conf.live_recording.recording_config.recording_params.xc_params.video_bitrate = LadderTemplate[540].bit_rate;
|
|
550
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_height = 540;
|
|
551
|
-
conf.live_recording.recording_config.recording_params.xc_params.enc_width = 960;
|
|
552
|
-
break;
|
|
553
|
-
default:
|
|
554
|
-
throw new Error("ERROR: Probed stream does not conform to one of the following built in resolution ladders [4096, 2160], [1920, 1080] [1280, 720], [960, 540]");
|
|
555
|
-
}
|
|
496
|
+
conf.live_recording.recording_config.recording_params.xc_params.enc_height = videoStream.height;
|
|
497
|
+
conf.live_recording.recording_config.recording_params.xc_params.enc_width = videoStream.width;
|
|
556
498
|
|
|
499
|
+
// Determine video recording bitrate and ABR ladder
|
|
500
|
+
let topLadderRate = 0
|
|
501
|
+
for (let i = 0; i < ladderProfile.video.length; i ++) {
|
|
502
|
+
let elem = ladderProfile.video[i];
|
|
503
|
+
if (elem.height > videoStream.height)
|
|
504
|
+
continue;
|
|
505
|
+
if (elem.bit_rate > topLadderRate) {
|
|
506
|
+
topLadderRate = elem.bit_rate
|
|
507
|
+
}
|
|
508
|
+
elem.media_type = 1;
|
|
509
|
+
elem.stream_name = "video";
|
|
510
|
+
elem.stream_index = 0;
|
|
511
|
+
elem.representation = "videovideo_" + elem.width + "x" + elem.height + "_h264@" + elem.bit_rate;
|
|
512
|
+
conf.live_recording.recording_config.recording_params.ladder_specs.push(elem);
|
|
513
|
+
}
|
|
514
|
+
// Currently the recording bitrate is the top bitrate of the ladder (it will be configurable separately in the future)
|
|
515
|
+
conf.live_recording.recording_config.recording_params.xc_params.video_bitrate = topLadderRate;
|
|
557
516
|
|
|
517
|
+
// Determine audio recording bitrate and ABR ladder
|
|
558
518
|
let globalAudioBitrate = 0;
|
|
559
519
|
let nAudio = 0;
|
|
560
520
|
|
|
561
521
|
for(let i = 0; i < Object.keys(audioStreams).length; i ++ ) {
|
|
562
|
-
let audioLadderSpec = {
|
|
522
|
+
let audioLadderSpec = {};
|
|
563
523
|
const audioIndex = Object.keys(audioStreams)[i];
|
|
564
524
|
const audio = audioStreams[audioIndex];
|
|
565
|
-
|
|
566
|
-
|
|
525
|
+
|
|
526
|
+
// Find ladder rung for the specific channel layout (2 or 6 channels)
|
|
527
|
+
for (let j = 0; j < ladderProfile.audio.length; j ++) {
|
|
528
|
+
let elem = ladderProfile.audio[j];
|
|
529
|
+
if (elem.channels == audio.recordingChannels) {
|
|
530
|
+
audioLadderSpec = {...elem};
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (Object.keys(audioLadderSpec).length === 0) {
|
|
535
|
+
// If no channels layout match, just use the first element in the ladder
|
|
536
|
+
audioLadderSpec = {...ladderProfile.audio[0]};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
audioLadderSpec.representation = `audioaudio_aac@${audioLadderSpec.bit_rate}`;
|
|
567
540
|
audioLadderSpec.channels = audio.recordingChannels;
|
|
568
541
|
audioLadderSpec.stream_index = parseInt(audioIndex);
|
|
569
542
|
audioLadderSpec.stream_name = `audio_${audioIndex}`;
|
|
570
543
|
audioLadderSpec.stream_label = audio.playoutLabel ? audio.playoutLabel : null;
|
|
544
|
+
audioLadderSpec.media_type = 2;
|
|
571
545
|
|
|
572
546
|
conf.live_recording.recording_config.recording_params.ladder_specs.push(audioLadderSpec);
|
|
573
547
|
if(audio.recordingBitrate > globalAudioBitrate) {
|
|
@@ -583,4 +557,5 @@ class LiveConf {
|
|
|
583
557
|
return conf;
|
|
584
558
|
}
|
|
585
559
|
}
|
|
560
|
+
|
|
586
561
|
exports.LiveConf = LiveConf;
|
package/src/client/LiveStream.js
CHANGED
|
@@ -415,16 +415,23 @@ exports.StreamStatus = async function({name, stopLro=false, showParams=false}) {
|
|
|
415
415
|
|
|
416
416
|
status.edge_write_token = edgeWriteToken;
|
|
417
417
|
status.stream_id = edgeWriteToken; // By convention the stream ID is its write token
|
|
418
|
-
let edgeMeta
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
418
|
+
let edgeMeta;
|
|
419
|
+
try {
|
|
420
|
+
edgeMeta = await this.ContentObjectMetadata({
|
|
421
|
+
libraryId: libraryId,
|
|
422
|
+
objectId: objectId,
|
|
423
|
+
writeToken: edgeWriteToken,
|
|
424
|
+
select: [
|
|
425
|
+
"live_recording"
|
|
426
|
+
]
|
|
427
|
+
});
|
|
428
|
+
} catch(error) {
|
|
429
|
+
console.error("Unable to read edge write token metadata. Has token been deleted?", error);
|
|
430
|
+
status.state = "inactive";
|
|
431
|
+
return status;
|
|
432
|
+
}
|
|
426
433
|
|
|
427
|
-
status.edge_meta_size = JSON.stringify(edgeMeta).length;
|
|
434
|
+
status.edge_meta_size = JSON.stringify(edgeMeta || "").length;
|
|
428
435
|
|
|
429
436
|
// If a stream has never been started return state 'inactive'
|
|
430
437
|
if(edgeMeta.live_recording === undefined ||
|
|
@@ -1030,6 +1037,18 @@ exports.StreamSetOfferingAndDRM = async function({name, typeAbrMaster, typeLiveS
|
|
|
1030
1037
|
};
|
|
1031
1038
|
continue;
|
|
1032
1039
|
}
|
|
1040
|
+
if(formats[i] === "dash-clear") {
|
|
1041
|
+
abrProfile.drm_optional = true;
|
|
1042
|
+
playoutFormats["dash-clear"] = {
|
|
1043
|
+
"drm": null,
|
|
1044
|
+
"protocol": {
|
|
1045
|
+
"min_buffer_length": 2,
|
|
1046
|
+
"type": "ProtoDash"
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1033
1052
|
playoutFormats[formats[i]] = abrProfile.playout_formats[formats[i]];
|
|
1034
1053
|
}
|
|
1035
1054
|
} else if(!drm) {
|
|
@@ -1040,6 +1059,13 @@ exports.StreamSetOfferingAndDRM = async function({name, typeAbrMaster, typeLiveS
|
|
|
1040
1059
|
"protocol": {
|
|
1041
1060
|
"type": "ProtoHls"
|
|
1042
1061
|
}
|
|
1062
|
+
},
|
|
1063
|
+
"dash-clear": {
|
|
1064
|
+
"drm": null,
|
|
1065
|
+
"protocol": {
|
|
1066
|
+
"min_buffer_length": 2,
|
|
1067
|
+
"type": "ProtoDash"
|
|
1068
|
+
}
|
|
1043
1069
|
}
|
|
1044
1070
|
};
|
|
1045
1071
|
} else {
|
|
@@ -1766,26 +1792,36 @@ exports.StreamCopyToVod = async function({
|
|
|
1766
1792
|
*
|
|
1767
1793
|
* @methodGroup Live Stream
|
|
1768
1794
|
* @namedParams
|
|
1795
|
+
* @param {string=} libraryId - Library ID of the live stream
|
|
1769
1796
|
* @param {string} objectId - Object ID of the live stream
|
|
1797
|
+
* @param {string=} writeToken - Write token of the draft
|
|
1770
1798
|
* @param {Array<string>} types - Specify which type of watermark to remove. Possible values:
|
|
1771
1799
|
* - "image"
|
|
1772
1800
|
* - "text"
|
|
1801
|
+
* - "forensic"
|
|
1773
1802
|
* @param {boolean=} finalize - If enabled, target object will be finalized after removing watermark
|
|
1774
1803
|
*
|
|
1775
1804
|
* @return {Promise<Object>} - The finalize response
|
|
1776
1805
|
*/
|
|
1777
1806
|
exports.StreamRemoveWatermark = async function({
|
|
1807
|
+
libraryId,
|
|
1778
1808
|
objectId,
|
|
1809
|
+
writeToken,
|
|
1779
1810
|
types,
|
|
1780
1811
|
finalize=true
|
|
1781
1812
|
}) {
|
|
1782
1813
|
ValidateObject(objectId);
|
|
1783
1814
|
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1815
|
+
if(!libraryId) {
|
|
1816
|
+
libraryId = await this.ContentObjectLibraryId({objectId});
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
if(!writeToken) {
|
|
1820
|
+
({writeToken} = await this.EditContentObject({
|
|
1821
|
+
objectId,
|
|
1822
|
+
libraryId
|
|
1823
|
+
}));
|
|
1824
|
+
}
|
|
1789
1825
|
|
|
1790
1826
|
this.Log(`Removing watermark types: ${types.join(", ")} ${libraryId} ${objectId}`);
|
|
1791
1827
|
|
|
@@ -1795,25 +1831,27 @@ exports.StreamRemoveWatermark = async function({
|
|
|
1795
1831
|
metadataSubtree: "/live_recording/fabric_config/edge_write_token"
|
|
1796
1832
|
});
|
|
1797
1833
|
|
|
1798
|
-
const
|
|
1834
|
+
const metadataPath = "live_recording/playout_config";
|
|
1799
1835
|
|
|
1800
|
-
const
|
|
1836
|
+
const objectMetadata = await this.ContentObjectMetadata({
|
|
1801
1837
|
libraryId,
|
|
1802
1838
|
objectId,
|
|
1803
1839
|
writeToken,
|
|
1804
|
-
metadataSubtree:
|
|
1840
|
+
metadataSubtree: metadataPath,
|
|
1805
1841
|
resolveLinks: false
|
|
1806
1842
|
});
|
|
1807
1843
|
|
|
1808
|
-
if(!
|
|
1809
|
-
throw Error("Stream object must be configured");
|
|
1844
|
+
if(!objectMetadata) {
|
|
1845
|
+
throw Error("Stream object must be configured before removing a watermark");
|
|
1810
1846
|
}
|
|
1811
1847
|
|
|
1812
1848
|
types.forEach(type => {
|
|
1813
1849
|
if(type === "text") {
|
|
1814
|
-
delete
|
|
1850
|
+
delete objectMetadata.simple_watermark;
|
|
1815
1851
|
} else if(type === "image") {
|
|
1816
|
-
delete
|
|
1852
|
+
delete objectMetadata.image_watermark;
|
|
1853
|
+
} else if(type === "forensic") {
|
|
1854
|
+
delete objectMetadata.forensic_watermark;
|
|
1817
1855
|
}
|
|
1818
1856
|
});
|
|
1819
1857
|
|
|
@@ -1821,8 +1859,8 @@ exports.StreamRemoveWatermark = async function({
|
|
|
1821
1859
|
libraryId,
|
|
1822
1860
|
objectId,
|
|
1823
1861
|
writeToken,
|
|
1824
|
-
metadataSubtree:
|
|
1825
|
-
metadata:
|
|
1862
|
+
metadataSubtree: metadataPath,
|
|
1863
|
+
metadata: objectMetadata
|
|
1826
1864
|
});
|
|
1827
1865
|
|
|
1828
1866
|
if(edgeWriteToken) {
|
|
@@ -1830,8 +1868,8 @@ exports.StreamRemoveWatermark = async function({
|
|
|
1830
1868
|
libraryId,
|
|
1831
1869
|
objectId,
|
|
1832
1870
|
writeToken: edgeWriteToken,
|
|
1833
|
-
metadataSubtree:
|
|
1834
|
-
metadata:
|
|
1871
|
+
metadataSubtree: metadataPath,
|
|
1872
|
+
metadata: objectMetadata
|
|
1835
1873
|
});
|
|
1836
1874
|
}
|
|
1837
1875
|
|
|
@@ -1852,26 +1890,72 @@ exports.StreamRemoveWatermark = async function({
|
|
|
1852
1890
|
*
|
|
1853
1891
|
* @methodGroup Live Stream
|
|
1854
1892
|
* @namedParams
|
|
1893
|
+
* @param {string=} libraryId - Library ID of the live stream
|
|
1855
1894
|
* @param {string} objectId - Object ID of the live stream
|
|
1895
|
+
* @param {string=} writeToken - Write token of the draft
|
|
1856
1896
|
* @param {Object} simpleWatermark - Text watermark
|
|
1857
1897
|
* @param {Object} imageWatermark - Image watermark
|
|
1898
|
+
* @param {Object} forensicWatermark - Forensic watermark
|
|
1858
1899
|
* @param {boolean=} finalize - If enabled, target object will be finalized after adding watermark
|
|
1900
|
+
* Watermark examples:
|
|
1901
|
+
*
|
|
1902
|
+
* Simple Watermark:
|
|
1903
|
+
{
|
|
1904
|
+
"font_color": "",
|
|
1905
|
+
"font_relative_height": 0,
|
|
1906
|
+
"shadow": false,
|
|
1907
|
+
"template": "",
|
|
1908
|
+
"timecode": "",
|
|
1909
|
+
"timecode_rate": 0,
|
|
1910
|
+
"x": "",
|
|
1911
|
+
"y": ""
|
|
1912
|
+
}
|
|
1913
|
+
*
|
|
1914
|
+
* Image watermark:
|
|
1915
|
+
{
|
|
1916
|
+
"image": "",
|
|
1917
|
+
"align_h": "",
|
|
1918
|
+
"align_v": "",
|
|
1919
|
+
"target_video_height": 0,
|
|
1920
|
+
"wm_enabled": false
|
|
1921
|
+
}
|
|
1922
|
+
*
|
|
1923
|
+
* Forensic watermark:
|
|
1924
|
+
{
|
|
1925
|
+
"algo": 6,
|
|
1926
|
+
"forensic_duration": 0,
|
|
1927
|
+
"forensic_start": "",
|
|
1928
|
+
"image_a": <path_to_image>,
|
|
1929
|
+
"image_b": <path_to_image>,
|
|
1930
|
+
"is_stub": true,
|
|
1931
|
+
"payload_bit_nb": 23,
|
|
1932
|
+
"wm_enabled": true
|
|
1933
|
+
}
|
|
1934
|
+
*
|
|
1859
1935
|
*
|
|
1860
1936
|
* @return {Promise<Object>} - The finalize response
|
|
1861
1937
|
*/
|
|
1862
1938
|
exports.StreamAddWatermark = async function({
|
|
1939
|
+
libraryId,
|
|
1863
1940
|
objectId,
|
|
1941
|
+
writeToken,
|
|
1864
1942
|
simpleWatermark,
|
|
1865
1943
|
imageWatermark,
|
|
1944
|
+
forensicWatermark,
|
|
1866
1945
|
finalize=true
|
|
1867
1946
|
}) {
|
|
1868
1947
|
ValidateObject(objectId);
|
|
1869
1948
|
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1949
|
+
if(!libraryId) {
|
|
1950
|
+
libraryId = await this.ContentObjectLibraryId({objectId});
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
if(!writeToken) {
|
|
1954
|
+
({writeToken} = await this.EditContentObject({
|
|
1955
|
+
objectId,
|
|
1956
|
+
libraryId
|
|
1957
|
+
}));
|
|
1958
|
+
}
|
|
1875
1959
|
|
|
1876
1960
|
const edgeWriteToken = await this.ContentObjectMetadata({
|
|
1877
1961
|
objectId,
|
|
@@ -1879,34 +1963,46 @@ exports.StreamAddWatermark = async function({
|
|
|
1879
1963
|
metadataSubtree: "/live_recording/fabric_config/edge_write_token"
|
|
1880
1964
|
});
|
|
1881
1965
|
|
|
1882
|
-
|
|
1966
|
+
const watermarkType = imageWatermark ? "image" : forensicWatermark ? "forensic" : "text";
|
|
1967
|
+
const metadataPath = "live_recording/playout_config";
|
|
1883
1968
|
|
|
1884
|
-
|
|
1969
|
+
this.Log(`Adding watermarking type: ${watermarkType} ${libraryId} ${objectId}`);
|
|
1885
1970
|
|
|
1886
|
-
const
|
|
1971
|
+
const objectMetadata = await this.ContentObjectMetadata({
|
|
1887
1972
|
libraryId,
|
|
1888
1973
|
objectId,
|
|
1889
1974
|
writeToken,
|
|
1890
|
-
metadataSubtree:
|
|
1975
|
+
metadataSubtree: metadataPath,
|
|
1891
1976
|
resolveLinks: false
|
|
1892
1977
|
});
|
|
1893
1978
|
|
|
1894
|
-
if(!
|
|
1895
|
-
throw Error("Stream object must be configured");
|
|
1979
|
+
if(!objectMetadata) {
|
|
1980
|
+
throw Error("Stream object must be configured before adding a watermark");
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
const watermarkArgCount = [simpleWatermark, imageWatermark, forensicWatermark].filter(i => !!i).length;
|
|
1984
|
+
console.log("watermark arg count", watermarkArgCount)
|
|
1985
|
+
|
|
1986
|
+
if(watermarkArgCount === 0) {
|
|
1987
|
+
throw Error("No watermark was provided");
|
|
1988
|
+
} else if(watermarkArgCount > 1) {
|
|
1989
|
+
throw Error("Only one watermark is allowed")
|
|
1896
1990
|
}
|
|
1897
1991
|
|
|
1898
1992
|
if(simpleWatermark) {
|
|
1899
|
-
|
|
1993
|
+
objectMetadata.simple_watermark = simpleWatermark;
|
|
1900
1994
|
} else if(imageWatermark) {
|
|
1901
|
-
|
|
1995
|
+
objectMetadata.image_watermark = imageWatermark;
|
|
1996
|
+
} else if(forensicWatermark) {
|
|
1997
|
+
objectMetadata.forensic_watermark = forensicWatermark;
|
|
1902
1998
|
}
|
|
1903
1999
|
|
|
1904
2000
|
await this.ReplaceMetadata({
|
|
1905
2001
|
libraryId,
|
|
1906
2002
|
objectId,
|
|
1907
2003
|
writeToken,
|
|
1908
|
-
metadataSubtree:
|
|
1909
|
-
metadata:
|
|
2004
|
+
metadataSubtree: metadataPath,
|
|
2005
|
+
metadata: objectMetadata
|
|
1910
2006
|
});
|
|
1911
2007
|
|
|
1912
2008
|
if(edgeWriteToken) {
|
|
@@ -1914,14 +2010,15 @@ exports.StreamAddWatermark = async function({
|
|
|
1914
2010
|
libraryId,
|
|
1915
2011
|
objectId,
|
|
1916
2012
|
writeToken: edgeWriteToken,
|
|
1917
|
-
metadataSubtree:
|
|
1918
|
-
metadata:
|
|
2013
|
+
metadataSubtree: metadataPath,
|
|
2014
|
+
metadata: objectMetadata
|
|
1919
2015
|
});
|
|
1920
2016
|
}
|
|
1921
2017
|
|
|
1922
2018
|
const response = {
|
|
1923
|
-
"imageWatermark":
|
|
1924
|
-
"textWatermark":
|
|
2019
|
+
"imageWatermark": objectMetadata.image_watermark,
|
|
2020
|
+
"textWatermark": objectMetadata.simple_watermark,
|
|
2021
|
+
"forensicWatermark": objectMetadata.forensic_watermark
|
|
1925
2022
|
};
|
|
1926
2023
|
|
|
1927
2024
|
if(finalize) {
|
|
@@ -7,15 +7,28 @@ const argv = yargs
|
|
|
7
7
|
description: "Fabric configuration URL (e.g. https://main.net955210.contentfabric.io/config)"
|
|
8
8
|
})
|
|
9
9
|
.option("tenantContractId", {
|
|
10
|
-
description: "tenant Contract Id to set for the
|
|
10
|
+
description: "tenant Contract Id to set for the objects"
|
|
11
|
+
})
|
|
12
|
+
.option("tenantIdToBeReplaced", {
|
|
13
|
+
description: "tenant Id to be changed for the objects"
|
|
11
14
|
})
|
|
12
15
|
.demandOption(
|
|
13
|
-
["configUrl", "tenantContractId"],
|
|
14
|
-
"\nUsage: PRIVATE_KEY=<private-key> node
|
|
16
|
+
["configUrl", "tenantContractId", "tenantIdToBeReplaced" ],
|
|
17
|
+
"\nUsage: PRIVATE_KEY=<private-key> node TestAddTenantContractId --configUrl <config-url> --tenantContractId <tenant_contract_id> --tenantIdToBeReplaced <tenant_id>\n"
|
|
15
18
|
)
|
|
16
19
|
.argv;
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
/**
|
|
22
|
+
* TestAddTenantContractId adds tenantContractId to wallet,library,group,content-type object
|
|
23
|
+
* and change tenantId to value provided.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} configUrl - Config Url
|
|
26
|
+
* @param {string} tenantContractId - Id of tenantContract to be set
|
|
27
|
+
* @param {string} tenantIdToBeReplaced - Id of tenant admin group to be replaced
|
|
28
|
+
* @returns {Promise<void>}
|
|
29
|
+
* @constructor
|
|
30
|
+
*/
|
|
31
|
+
const TestAddTenantContractId = async ({configUrl, tenantContractId, tenantIdToBeReplaced}) => {
|
|
19
32
|
try {
|
|
20
33
|
if(!process.env.PRIVATE_KEY) {
|
|
21
34
|
console.log("ERROR: 'PRIVATE_KEY' environment variable must be set");
|
|
@@ -79,6 +92,34 @@ const TestAddTenantContractId = async ({configUrl, tenantContractId}) => {
|
|
|
79
92
|
// libraryId: client.contentSpaceLibraryId,
|
|
80
93
|
// objectId: client.utils.AddressToObjectId(groupAddress)}));
|
|
81
94
|
|
|
95
|
+
|
|
96
|
+
// Change tenantID (which in turn changes tenantContractId) to user, group, library and content-type
|
|
97
|
+
await client.userProfileClient.SetTenantId({id: tenantIdToBeReplaced});
|
|
98
|
+
const newTenantId = await client.userProfileClient.TenantId();
|
|
99
|
+
if(newTenantId !== tenantIdToBeReplaced) {
|
|
100
|
+
throw Error(`tenant mismatch, actual: ${tenantInfo.tenantId}, expected: ${tenantIdToBeReplaced}`);
|
|
101
|
+
}
|
|
102
|
+
console.log();
|
|
103
|
+
console.log(`tenantId for user changed to ${tenantIdToBeReplaced}`);
|
|
104
|
+
|
|
105
|
+
tenantInfo = await client.SetTenantId({objectId: libraryId, tenantId: tenantIdToBeReplaced});
|
|
106
|
+
if(tenantInfo.tenantId !== tenantIdToBeReplaced) {
|
|
107
|
+
throw Error(`tenant mismatch, actual: ${tenantInfo.tenantId}, expected: ${tenantIdToBeReplaced}`);
|
|
108
|
+
}
|
|
109
|
+
console.log(`tenantId for library changed to ${tenantIdToBeReplaced}`);
|
|
110
|
+
|
|
111
|
+
tenantInfo = await client.SetTenantId({contractAddress: contentTypeAddress, tenantId: tenantIdToBeReplaced});
|
|
112
|
+
if(tenantInfo.tenantId !== tenantIdToBeReplaced) {
|
|
113
|
+
throw Error(`tenant mismatch, actual: ${tenantInfo.tenantId}, expected: ${tenantIdToBeReplaced}`);
|
|
114
|
+
}
|
|
115
|
+
console.log(`tenantId for content-type object changed to ${tenantIdToBeReplaced}`)
|
|
116
|
+
|
|
117
|
+
tenantInfo = await client.SetTenantId({contractAddress: groupAddress, tenantId: tenantIdToBeReplaced});
|
|
118
|
+
if(tenantInfo.tenantId !== tenantIdToBeReplaced) {
|
|
119
|
+
throw Error(`tenant mismatch, actual: ${tenantInfo.tenantId}, expected: ${tenantIdToBeReplaced}`);
|
|
120
|
+
}
|
|
121
|
+
console.log(`tenantId for group-address changed to ${tenantIdToBeReplaced}`)
|
|
122
|
+
|
|
82
123
|
} catch(e){
|
|
83
124
|
console.error(e);
|
|
84
125
|
}
|