@eluvio/elv-client-js 4.0.20 → 4.0.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "4.0.20",
3
+ "version": "4.0.22",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
@@ -192,7 +192,7 @@ class AuthorizationClient {
192
192
  if(encryption && encryption !== "none" && objectId && await this.AccessType(objectId) === ACCESS_TYPES.OBJECT) {
193
193
  const owner = await this.Owner({id: objectId});
194
194
  const ownerCapKey = `eluv.caps.iusr${Utils.AddressToHash(this.client.signer.address)}`;
195
- const ownerCap = await this.client.ContentObjectMetadata({libraryId, objectId, metadataSubtree: ownerCapKey});
195
+ const ownerCap = await this.client.ContentObjectMetadata({libraryId, objectId, versionHash, metadataSubtree: ownerCapKey});
196
196
 
197
197
  if(!Utils.EqualAddress(owner, this.client.signer.address) && !ownerCap) {
198
198
  const cap = await this.ReEncryptionConk({libraryId, objectId});
package/src/HttpClient.js CHANGED
@@ -12,6 +12,7 @@ class HttpClient {
12
12
  this.uriIndex = 0;
13
13
  this.debug = debug;
14
14
  this.draftURIs = {};
15
+ this.retries = Math.max(3, uris.length);
15
16
  }
16
17
 
17
18
  BaseURI() {
@@ -50,8 +51,9 @@ class HttpClient {
50
51
  bodyType="JSON",
51
52
  headers={},
52
53
  attempts=0,
53
- failover=true,
54
- forceFailover=false
54
+ allowFailover=true,
55
+ forceFailover=false,
56
+ allowRetry=true
55
57
  }) {
56
58
  let baseURI = this.BaseURI();
57
59
 
@@ -60,6 +62,8 @@ class HttpClient {
60
62
  const writeToken = writeTokenMatch ? writeTokenMatch[2] : undefined;
61
63
 
62
64
  if(writeToken) {
65
+ allowFailover = false;
66
+
63
67
  if(this.draftURIs[writeToken]) {
64
68
  // Use saved write token URI
65
69
  baseURI = this.draftURIs[writeToken];
@@ -107,10 +111,21 @@ class HttpClient {
107
111
 
108
112
  if(!response.ok) {
109
113
  // Fail over if not a write token request, the response was a server error, and we haven't tried all available nodes
110
- if(!writeToken && ((failover && parseInt(response.status) >= 500) || forceFailover) && attempts < this.uris.length) {
111
- // Server error - Try next node
112
- this.Log(`HttpClient failing over from ${this.BaseURI()}: ${attempts + 1} attempts`, true);
113
- this.uriIndex = (this.uriIndex + 1) % this.uris.length;
114
+ if(
115
+ (parseInt(response.status) >= 500 || forceFailover) &&
116
+ allowRetry &&
117
+ attempts < this.retries
118
+ ) {
119
+ // Server error
120
+ if(allowFailover) {
121
+ // Fail over to alternate node
122
+ this.uriIndex = (this.uriIndex + 1) % this.uris.length;
123
+ this.Log(`HttpClient failing over from ${baseURI.toString()}: ${attempts + 1} attempts`, true);
124
+ } else {
125
+ // Wait and retry
126
+ this.Log(`HttpClient retrying request from ${baseURI.toString()}: ${attempts + 1} attempts`, true);
127
+ await new Promise(resolve => setTimeout(resolve, 1000));
128
+ }
114
129
 
115
130
  return await this.Request({
116
131
  method,
@@ -1831,7 +1831,7 @@ exports.CallBitcodeMethod = async function({
1831
1831
  method: constant ? "GET" : "POST",
1832
1832
  path,
1833
1833
  queryParams,
1834
- failover: false
1834
+ allowFailover: false
1835
1835
  })
1836
1836
  );
1837
1837
  };
@@ -2477,7 +2477,7 @@ exports.EncryptionConk = async function({libraryId, objectId, versionHash, write
2477
2477
  const owner = await this.authClient.Owner({id: objectId});
2478
2478
 
2479
2479
  const ownerCapKey = `eluv.caps.iusr${this.utils.AddressToHash(this.signer.address)}`;
2480
- const ownerCap = await this.ContentObjectMetadata({libraryId, objectId, metadataSubtree: ownerCapKey});
2480
+ const ownerCap = await this.ContentObjectMetadata({libraryId, objectId, versionHash, metadataSubtree: ownerCapKey});
2481
2481
 
2482
2482
  if(!this.utils.EqualAddress(owner, this.signer.address) && !ownerCap) {
2483
2483
  if(download) {
@@ -967,7 +967,7 @@ exports.FinalizeContentObject = async function({
967
967
  headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
968
968
  method: "POST",
969
969
  path: path,
970
- failover: false
970
+ allowFailover: false
971
971
  })
972
972
  );
973
973
 
@@ -1127,7 +1127,7 @@ exports.MergeMetadata = async function({libraryId, objectId, writeToken, metadat
1127
1127
  method: "POST",
1128
1128
  path: path,
1129
1129
  body: metadata,
1130
- failover: false
1130
+ allowFailover: false
1131
1131
  });
1132
1132
  };
1133
1133
 
@@ -1159,7 +1159,7 @@ exports.ReplaceMetadata = async function({libraryId, objectId, writeToken, metad
1159
1159
  method: "PUT",
1160
1160
  path: path,
1161
1161
  body: metadata,
1162
- failover: false
1162
+ allowFailover: false
1163
1163
  });
1164
1164
  };
1165
1165
 
@@ -1190,7 +1190,7 @@ exports.DeleteMetadata = async function({libraryId, objectId, writeToken, metada
1190
1190
  headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
1191
1191
  method: "DELETE",
1192
1192
  path: path,
1193
- failover: false
1193
+ allowFailover: false
1194
1194
  });
1195
1195
  };
1196
1196
 
@@ -267,6 +267,7 @@ exports.UploadFilesFromS3 = async function({
267
267
  exports.UploadFiles = async function({libraryId, objectId, writeToken, fileInfo, encryption="none", callback}) {
268
268
  ValidateParameters({libraryId, objectId});
269
269
  ValidateWriteToken(writeToken);
270
+ ValidatePresence("fileInfo", fileInfo);
270
271
 
271
272
  this.Log(`Uploading files: ${libraryId} ${objectId} ${writeToken}`);
272
273
 
@@ -279,8 +280,10 @@ exports.UploadFiles = async function({libraryId, objectId, writeToken, fileInfo,
279
280
  let progress = {};
280
281
  let fileDataMap = {};
281
282
 
282
- for(let i = 0; i < fileInfo.length; i++) {
283
- let entry = { ...fileInfo[i], data: undefined };
283
+ let originalFileInfo = fileInfo;
284
+ fileInfo = [];
285
+ for(let i = 0; i < originalFileInfo.length; i++) {
286
+ let entry = { ...originalFileInfo[i], data: undefined };
284
287
 
285
288
  entry.path = entry.path.replace(/^\/+/, "");
286
289
 
@@ -290,9 +293,8 @@ exports.UploadFiles = async function({libraryId, objectId, writeToken, fileInfo,
290
293
  };
291
294
  }
292
295
 
293
- fileDataMap[entry.path] = fileInfo[i].data;
296
+ fileDataMap[entry.path] = originalFileInfo[i].data;
294
297
 
295
- delete entry.data;
296
298
  entry.type = "file";
297
299
 
298
300
  progress[entry.path] = {
@@ -300,7 +302,7 @@ exports.UploadFiles = async function({libraryId, objectId, writeToken, fileInfo,
300
302
  total: entry.size
301
303
  };
302
304
 
303
- fileInfo[i] = entry;
305
+ fileInfo.push(entry);
304
306
  }
305
307
 
306
308
  this.Log(fileInfo);
@@ -321,7 +323,7 @@ exports.UploadFiles = async function({libraryId, objectId, writeToken, fileInfo,
321
323
  this.Log(jobs);
322
324
 
323
325
  // How far encryption can get ahead of upload
324
- const bufferSize = 100 * 1024 * 1024;
326
+ const bufferSize = 500 * 1024 * 1024;
325
327
 
326
328
  let jobSpecs = [];
327
329
  let prepared = 0;
@@ -387,7 +389,34 @@ exports.UploadFiles = async function({libraryId, objectId, writeToken, fileInfo,
387
389
  for(let f = 0; f < files.length; f++) {
388
390
  const fileInfo = files[f];
389
391
 
390
- await this.UploadFileData({libraryId, objectId, writeToken, uploadId: id, jobId, filePath: fileInfo.path, fileData: fileInfo.data});
392
+ let retries = 0;
393
+ let succeeded = false;
394
+ do {
395
+ try {
396
+ await this.UploadFileData({
397
+ libraryId,
398
+ objectId,
399
+ writeToken,
400
+ uploadId: id,
401
+ jobId,
402
+ filePath: fileInfo.path,
403
+ fileData: fileInfo.data,
404
+ encryption
405
+ });
406
+
407
+ succeeded = true;
408
+ } catch(error) {
409
+ this.Log(error, true);
410
+
411
+ retries += 1;
412
+
413
+ if(retries >= 10) {
414
+ throw error;
415
+ }
416
+
417
+ await new Promise(resolve => setTimeout(resolve, 10 * retries * 1000));
418
+ }
419
+ } while(!succeeded && retries < 10);
391
420
 
392
421
  delete jobSpecs[j].files[f].data;
393
422
  uploaded += fileInfo.len;
@@ -460,7 +489,7 @@ exports.CreateFileUploadJob = async function({libraryId, objectId, writeToken, o
460
489
  method: "POST",
461
490
  path: path,
462
491
  body,
463
- failover: false
492
+ allowFailover: false
464
493
  })
465
494
  );
466
495
  };
@@ -476,7 +505,7 @@ exports.UploadStatus = async function({libraryId, objectId, writeToken, uploadId
476
505
  headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
477
506
  method: "GET",
478
507
  path: path,
479
- failover: false
508
+ allowFailover: false
480
509
  })
481
510
  );
482
511
  };
@@ -487,80 +516,51 @@ exports.UploadJobStatus = async function({libraryId, objectId, writeToken, uploa
487
516
 
488
517
  const path = UrlJoin("q", writeToken, "file_jobs", uploadId, "uploads", jobId);
489
518
 
490
- // This request is sent during file data upload and might fail due to congestion
491
- do {
492
- try {
493
- let jobStatus = this.utils.ResponseToJson(
494
- this.HttpClient.Request({
495
- headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
496
- method: "GET",
497
- path: path,
498
- failover: false
499
- })
500
- );
501
- return jobStatus;
502
- } catch(error) {
503
- this.Log(error, true);
504
-
505
- retries += 1;
506
- if(retries >= 5) {
507
- throw error;
508
- }
509
- await new Promise(resolve => setTimeout(resolve, 10 * retries * 1000));
510
- }
511
- } while(retries < 5);
512
-
519
+ return await this.utils.ResponseToJson(
520
+ this.HttpClient.Request({
521
+ headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
522
+ method: "GET",
523
+ path: path,
524
+ allowFailover: false
525
+ })
526
+ );
513
527
  };
514
528
 
515
- exports.UploadFileData = async function({libraryId, objectId, writeToken, uploadId, jobId, filePath, fileData}) {
529
+ exports.UploadFileData = async function({libraryId, objectId, writeToken, encryption, uploadId, jobId, filePath, fileData}) {
516
530
  ValidateParameters({libraryId, objectId});
517
531
  ValidateWriteToken(writeToken);
518
532
 
519
- let retries = 0;
520
- do {
521
- try {
522
-
523
- const jobStatus = await this.UploadJobStatus({libraryId, objectId, writeToken, uploadId, jobId});
524
-
525
- // Find the status of this file
526
- const fileStatus = jobStatus.files.find(item => {
527
- return item.path == filePath
528
- });
529
-
530
- if(fileStatus.rem === 0) {
531
- // Job is actually done
532
- return;
533
- } else if(fileStatus.skip) {
534
- fileData = fileData.slice(fileStatus.skip);
535
- }
533
+ const jobStatus = await this.UploadJobStatus({libraryId, objectId, writeToken, uploadId, jobId});
536
534
 
537
- let path = UrlJoin("q", writeToken, "file_jobs", uploadId, jobId);
538
-
539
- return await this.utils.ResponseToJson(
540
- this.HttpClient.Request({
541
- method: "POST",
542
- path: path,
543
- body: fileData,
544
- bodyType: "BINARY",
545
- headers: {
546
- "Content-type": "application/octet-stream",
547
- ...(await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}))
548
- },
549
- failover: false
550
- })
551
- );
552
- } catch(error){
553
- this.Log(error, true);
535
+ // Find the status of this file
536
+ let fileStatus = jobStatus.files.find(item => item.path == filePath);
537
+ if(encryption && encryption !== "none") {
538
+ fileStatus = fileStatus.encrypted;
539
+ }
554
540
 
555
- retries += 1;
541
+ if(fileStatus.rem === 0) {
542
+ // Job is actually done
543
+ return;
544
+ } else if(fileStatus.skip) {
545
+ fileData = fileData.slice(fileStatus.skip);
546
+ }
556
547
 
557
- if(retries >= 5) {
558
- throw error;
559
- }
548
+ let path = UrlJoin("q", writeToken, "file_jobs", uploadId, jobId);
560
549
 
561
- await new Promise(resolve => setTimeout(resolve, 10 * retries * 1000));
562
- }
563
- } while(retries < 5);
550
+ return await this.utils.ResponseToJson(
551
+ this.HttpClient.Request({
552
+ method: "POST",
553
+ path: path,
554
+ body: fileData,
555
+ bodyType: "BINARY",
556
+ headers: {
557
+ "Content-type": "application/octet-stream",
558
+ ...(await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}))
559
+ },
560
+ allowFailover: false,
561
+ allowRetry: false
562
+ })
563
+ );
564
564
  };
565
565
 
566
566
  exports.FinalizeUploadJob = async function({libraryId, objectId, writeToken}) {
@@ -576,7 +576,7 @@ exports.FinalizeUploadJob = async function({libraryId, objectId, writeToken}) {
576
576
  path: path,
577
577
  bodyType: "BINARY",
578
578
  headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
579
- failover: false
579
+ allowFailover: false
580
580
  });
581
581
  };
582
582
 
@@ -637,7 +637,7 @@ exports.DeleteFiles = async function({libraryId, objectId, writeToken, filePaths
637
637
  * @param {string=} versionHash - Hash of the object version - if not specified, latest version will be used
638
638
  * @param {string=} writeToken - Write token for the draft from which to download the file
639
639
  * @param {string} filePath - Path to the file to download
640
- * @param {string=} format="blob" - Format in which to return the data ("blob" | "arraybuffer" | "buffer)
640
+ * @param {string=} format="arrayBuffer" - Format in which to return the data ("blob" | "arraybuffer" | "buffer")
641
641
  * @param {boolean=} chunked=false - If specified, file will be downloaded and decrypted in chunks. The
642
642
  * specified callback will be invoked on completion of each chunk. This is recommended for large files.
643
643
  * @param {number=} chunkSize=1000000 - Size of file chunks to request for download
@@ -689,7 +689,7 @@ exports.DownloadFile = async function({
689
689
 
690
690
  // If not owner, indicate re-encryption
691
691
  const ownerCapKey = `eluv.caps.iusr${this.utils.AddressToHash(this.signer.address)}`;
692
- const ownerCap = await this.ContentObjectMetadata({libraryId, objectId, metadataSubtree: ownerCapKey});
692
+ const ownerCap = await this.ContentObjectMetadata({libraryId, objectId, versionHash, metadataSubtree: ownerCapKey});
693
693
 
694
694
  if(encrypted && !this.utils.EqualAddress(this.signer.address, await this.ContentObjectOwner({objectId})) && !ownerCap) {
695
695
  headers["X-Content-Fabric-Decryption-Mode"] = "reencrypt";
@@ -1040,7 +1040,7 @@ exports.CreatePart = async function({libraryId, objectId, writeToken, encryption
1040
1040
  path,
1041
1041
  bodyType: "BINARY",
1042
1042
  body: "",
1043
- failover: false
1043
+ allowFailover: false
1044
1044
  })
1045
1045
  );
1046
1046
 
@@ -1079,7 +1079,7 @@ exports.UploadPartChunk = async function({libraryId, objectId, writeToken, partW
1079
1079
  path: UrlJoin(path, partWriteToken),
1080
1080
  body: chunk,
1081
1081
  bodyType: "BINARY",
1082
- failover: false
1082
+ allowFailover: false
1083
1083
  })
1084
1084
  );
1085
1085
  };
@@ -1110,7 +1110,7 @@ exports.FinalizePart = async function({libraryId, objectId, writeToken, partWrit
1110
1110
  path: UrlJoin(path, partWriteToken),
1111
1111
  bodyType: "BINARY",
1112
1112
  body: "",
1113
- failover: false
1113
+ allowFailover: false
1114
1114
  })
1115
1115
  );
1116
1116
  };
@@ -1189,6 +1189,6 @@ exports.DeletePart = async function({libraryId, objectId, writeToken, partHash})
1189
1189
  headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
1190
1190
  method: "DELETE",
1191
1191
  path: path,
1192
- failover: false
1192
+ allowFailover: false
1193
1193
  });
1194
1194
  };
@@ -1,8 +1,7 @@
1
1
  const { ElvClient } = require("../src/ElvClient");
2
2
  const { ElvWalletClient } = require("../src/walletClient/index");
3
3
  const ClientConfiguration = require("../TestConfiguration.json");
4
-
5
- const ethers = require("ethers");
4
+ const fs = require("fs");
6
5
 
7
6
  const Test = async () => {
8
7
  try {
@@ -0,0 +1,84 @@
1
+ const { ElvClient } = require("../src/ElvClient");
2
+ const { ElvWalletClient } = require("../src/walletClient/index");
3
+ const ClientConfiguration = require("../TestConfiguration.json");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const createHash = require("node:crypto").createHash;
8
+ const MD5 = str => {
9
+ const f = createHash("md5");
10
+ f.update(str);
11
+ return f.digest("hex");
12
+ };
13
+
14
+ const Test = async () => {
15
+ try {
16
+ const client = await ElvClient.FromNetworkName({
17
+ networkName: "demo"
18
+ });
19
+
20
+ const wallet = client.GenerateWallet();
21
+ const signer = wallet.AddAccount({
22
+ privateKey: process.env.PRIVATE_KEY
23
+ });
24
+
25
+ client.SetSigner({signer});
26
+
27
+ const uploadDir = process.argv[2];
28
+
29
+ const dirname = `upload-test-${Date.now()}`;
30
+ const fileList = fs.readdirSync(uploadDir);
31
+ const fileInfo = fileList.map(filename => {
32
+ const data = fs.readFileSync(path.join(uploadDir, filename));
33
+
34
+ return {
35
+ path: `${dirname}/${filename}`,
36
+ size: data.length,
37
+ data
38
+ };
39
+ }).sort(() => Math.random() > 0.5 ? -1 : 1);
40
+
41
+
42
+ const libraryId = "ilib3Drbefo7VPfWvY1NVup4VZFzDJ68";
43
+ const objectId = "iq__2aqbcJhSKdkuRmAUqs6v99SLRRp";
44
+
45
+ const {hash} = await client.EditAndFinalizeContentObject({
46
+ libraryId,
47
+ objectId,
48
+ callback: async ({writeToken}) => {
49
+ await client.UploadFiles({
50
+ libraryId,
51
+ objectId,
52
+ writeToken,
53
+ //callback: console.log,
54
+ //encryption: "cgck",
55
+ fileInfo
56
+ });
57
+ }
58
+ });
59
+
60
+ console.log("\n\n");
61
+ for(let i = 0; i < fileInfo.length; i++) {
62
+ const {path, data} = fileInfo[i];
63
+
64
+ const downloadedData = await client.DownloadFile({
65
+ versionHash: hash,
66
+ format: "buffer",
67
+ filePath: path
68
+ });
69
+
70
+ console.log(path);
71
+ console.log(MD5(data.toString()));
72
+ console.log(MD5(downloadedData.toString()));
73
+ console.log(MD5(data.toString()) === MD5(downloadedData.toString()));
74
+ console.log();
75
+ }
76
+ } catch(error) {
77
+ console.error(error);
78
+ console.error(JSON.stringify(error, null, 2));
79
+ }
80
+
81
+ process.exit(0);
82
+ };
83
+
84
+ Test();
@@ -105,16 +105,6 @@
105
105
  "type": "ProtoHls"
106
106
  }
107
107
  },
108
- "hls-fairplay": {
109
- "drm": {
110
- "enc_scheme_name": "cbcs",
111
- "license_servers": [],
112
- "type": "DrmFairplay"
113
- },
114
- "protocol": {
115
- "type": "ProtoHls"
116
- }
117
- },
118
108
  "hls-sample-aes": {
119
109
  "drm": {
120
110
  "enc_scheme_name": "cbcs",
@@ -0,0 +1,128 @@
1
+ {
2
+ "drm_optional": false,
3
+ "store_clear": false,
4
+ "ladder_specs": {
5
+ "{\"media_type\":\"audio\",\"channels\":1}": {
6
+ "rung_specs": [
7
+ {
8
+ "bit_rate": 128000,
9
+ "media_type": "audio",
10
+ "pregenerate": true
11
+ }
12
+ ]
13
+ },
14
+ "{\"media_type\":\"audio\",\"channels\":2}": {
15
+ "rung_specs": [
16
+ {
17
+ "bit_rate": 192000,
18
+ "media_type": "audio",
19
+ "pregenerate": true
20
+ }
21
+ ]
22
+ },
23
+ "{\"media_type\":\"audio\",\"channels\":6}": {
24
+ "rung_specs": [
25
+ {
26
+ "bit_rate": 384000,
27
+ "media_type": "audio",
28
+ "pregenerate": true
29
+ }
30
+ ]
31
+ },
32
+ "{\"media_type\":\"video\",\"aspect_ratio_height\":9,\"aspect_ratio_width\":16}": {
33
+ "rung_specs": [
34
+ {
35
+ "bit_rate": 20000000,
36
+ "height": 2160,
37
+ "media_type": "video",
38
+ "pregenerate": true,
39
+ "width": 3840
40
+ },
41
+ {
42
+ "bit_rate": 9500000,
43
+ "height": 1080,
44
+ "media_type": "video",
45
+ "pregenerate": false,
46
+ "width": 1920
47
+ },
48
+ {
49
+ "bit_rate": 4500000,
50
+ "height":720 ,
51
+ "media_type": "video",
52
+ "pregenerate": false,
53
+ "width": 1280
54
+ },
55
+ {
56
+ "bit_rate": 2000000,
57
+ "height": 540,
58
+ "media_type": "video",
59
+ "pregenerate": false,
60
+ "width": 960
61
+ },
62
+ {
63
+ "bit_rate": 1100000,
64
+ "height": 432,
65
+ "media_type": "video",
66
+ "pregenerate": false,
67
+ "width": 768
68
+ },
69
+ {
70
+ "bit_rate": 810000,
71
+ "height": 360,
72
+ "media_type": "video",
73
+ "pregenerate": false,
74
+ "width": 640
75
+ },
76
+ {
77
+ "bit_rate": 520000,
78
+ "height": 360,
79
+ "media_type": "video",
80
+ "pregenerate": false,
81
+ "width": 640
82
+ }
83
+ ]
84
+ }
85
+ },
86
+ "playout_formats": {
87
+ "dash-widevine": {
88
+ "drm": {
89
+ "content_id": "",
90
+ "enc_scheme_name": "cenc",
91
+ "license_servers": [],
92
+ "type": "DrmWidevine"
93
+ },
94
+ "protocol": {
95
+ "min_buffer_length": 2,
96
+ "type": "ProtoDash"
97
+ }
98
+ },
99
+ "hls-sample-aes": {
100
+ "drm": {
101
+ "enc_scheme_name": "cbcs",
102
+ "type": "DrmSampleAes"
103
+ },
104
+ "protocol": {
105
+ "type": "ProtoHls"
106
+ }
107
+ },
108
+ "hls-aes128": {
109
+ "drm": {
110
+ "enc_scheme_name": "aes-128",
111
+ "type": "DrmAes128"
112
+ },
113
+ "protocol": {
114
+ "type": "ProtoHls"
115
+ }
116
+ }
117
+ },
118
+ "segment_specs": {
119
+ "audio": {
120
+ "segs_per_chunk": 15,
121
+ "target_dur": 2
122
+ },
123
+ "video": {
124
+ "segs_per_chunk": 15,
125
+ "target_dur": 2
126
+ }
127
+ }
128
+ }
@@ -1930,16 +1930,6 @@
1930
1930
  "type": "ProtoDash"
1931
1931
  }
1932
1932
  },
1933
- "hls-fairplay": {
1934
- "drm": {
1935
- "enc_scheme_name": "cbcs",
1936
- "license_servers": [],
1937
- "type": "DrmFairplay"
1938
- },
1939
- "protocol": {
1940
- "type": "ProtoHls"
1941
- }
1942
- },
1943
1933
  "hls-sample-aes": {
1944
1934
  "drm": {
1945
1935
  "enc_scheme_name": "cbcs",