@eluvio/elv-client-js 3.1.95 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/ElvClient-min.js +11 -15
  2. package/dist/ElvClient-node-min.js +13 -17
  3. package/dist/ElvFrameClient-min.js +9 -13
  4. package/dist/ElvPermissionsClient-min.js +9 -13
  5. package/dist/src/AuthorizationClient.js +1980 -2238
  6. package/dist/src/ContentObjectVerification.js +173 -164
  7. package/dist/src/Crypto.js +324 -376
  8. package/dist/src/ElvClient.js +1022 -1182
  9. package/dist/src/ElvWallet.js +95 -119
  10. package/dist/src/EthClient.js +896 -1040
  11. package/dist/src/FrameClient.js +300 -331
  12. package/dist/src/HttpClient.js +147 -153
  13. package/dist/src/Id.js +3 -1
  14. package/dist/src/PermissionsClient.js +1168 -1294
  15. package/dist/src/RemoteSigner.js +211 -263
  16. package/dist/src/UserProfileClient.js +1023 -1164
  17. package/dist/src/Utils.js +217 -212
  18. package/dist/src/client/ABRPublishing.js +858 -895
  19. package/dist/src/client/AccessGroups.js +959 -1102
  20. package/dist/src/client/ContentAccess.js +3433 -3717
  21. package/dist/src/client/ContentManagement.js +2068 -2252
  22. package/dist/src/client/Contracts.js +563 -647
  23. package/dist/src/client/Files.js +1757 -1886
  24. package/dist/src/client/NFT.js +112 -126
  25. package/dist/src/client/NTP.js +422 -478
  26. package/dist/src/index.js +11 -0
  27. package/dist/src/marketplaceClient/ClientMethods.js +1918 -0
  28. package/dist/src/marketplaceClient/Configuration.js +29 -0
  29. package/dist/src/marketplaceClient/Utils.js +304 -0
  30. package/dist/src/marketplaceClient/index.js +1553 -0
  31. package/dist/src/walletClient/ClientMethods.js +1828 -0
  32. package/dist/src/walletClient/Configuration.js +29 -0
  33. package/dist/src/walletClient/Utils.js +290 -0
  34. package/dist/src/walletClient/index.js +1459 -0
  35. package/package-lock.json +22001 -0
  36. package/package.json +6 -4
  37. package/src/AuthorizationClient.js +1 -1
  38. package/src/ElvClient.js +4 -1
  39. package/src/Utils.js +44 -3
  40. package/src/client/ContentAccess.js +4 -0
  41. package/src/index.js +7 -0
  42. package/src/walletClient/ClientMethods.js +1016 -0
  43. package/src/walletClient/Configuration.js +40 -0
  44. package/src/walletClient/README.md +185 -0
  45. package/src/walletClient/Utils.js +234 -0
  46. package/src/walletClient/index.js +884 -0
  47. package/testScripts/TestMarketplaceClient.js +25 -0
  48. package/utilities/ObjectSetPermission.js +4 -4
  49. package/utilities/SimpleIngest.js +41 -0
  50. package/utilities/example_files/simple_ingest_library_metadata.json +180 -0
  51. package/utilities/example_files/simple_ingest_library_metadata_animation_NFTs.json +133 -0
@@ -0,0 +1,25 @@
1
+ const { ElvMarketplaceClient } = require("../src/walletClient/ElvMarketplaceClient");
2
+ const ClientConfiguration = require("../TestConfiguration.json");
3
+
4
+ const Test = async () => {
5
+ try {
6
+ const idToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Inlwd1ZUbXJkWENkYU5tcjAzVGRDaCJ9.eyJodHRwczovL2F1dGguY29udGVudGZhYnJpYy5pby9nZW8iOnsiY291bnRyeV9jb2RlIjoiVVMiLCJjb3VudHJ5X2NvZGUzIjoiVVNBIiwiY291bnRyeV9uYW1lIjoiVW5pdGVkIFN0YXRlcyIsImNpdHlfbmFtZSI6IlJhbmNobyBDb3Jkb3ZhIiwibGF0aXR1ZGUiOjM4LjYxMDYsImxvbmdpdHVkZSI6LTEyMS4yNzg5LCJ0aW1lX3pvbmUiOiJBbWVyaWNhL0xvc19BbmdlbGVzIiwiY29udGluZW50X2NvZGUiOiJOQSIsInN1YmRpdmlzaW9uX2NvZGUiOiJDQSIsInN1YmRpdmlzaW9uX25hbWUiOiJDYWxpZm9ybmlhIn0sIm5pY2tuYW1lIjoia2V2aW4rNyIsIm5hbWUiOiJrZXZpbis3QGVsdXYuaW8iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvZmQ0MzE3ZjhmN2YzMGM1NWRlMDZhMjljYTFjYjY5ZjE_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZrZS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyMi0wNi0xN1QxOTo1Nzo0NC4yODZaIiwiZW1haWwiOiJrZXZpbis3QGVsdXYuaW8iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImlzcyI6Imh0dHBzOi8vYXV0aC5jb250ZW50ZmFicmljLmlvLyIsInN1YiI6ImF1dGgwfDYxNjY3NzE3ODk5YjkyMDA3MGYzNGFjNCIsImF1ZCI6Ik9OeXViUDlyRkk1Qkh6bVlnbFFLQloxYkJiaXlvQjNTIiwiaWF0IjoxNjU1NDk1ODY1LCJleHAiOjE2NTU1MzE4NjUsIm5vbmNlIjoiY0c4MlFrTkplV2wwU1U1RVVrOUpaR1kwTW1oRlZXaFpOSE5LVGxZNU5VWjJjRmwwWkhwVmIxQjJNQT09In0.dPBk0hGjHAW5Dz8yfhW0IEG-ArJ258Q7x3dYMz0tIIj9EUY438issp0rJwfoAVWu4hw6SBUGNS2bnAZ9bvhag8IMZm_YYRfKTnY7gV7ST_-ni72mQ04F2Kpc9H2jzNKwRWqdKdXy3Rp0YoIR1PYOTwk2BWJtiqoyA11og-QNiI4pBEhZ6JRyDO7693jPoGXdUPJpXPHsfEJqLbGM8BYcv5X-PwVnU8TzSqgFpB5G4pZSfnoyz26wbmpFs5jc2_QgWAIvc94pW-cwpMbfpHb10LejrBFbO9FW3Sv6eOPY9W-AuxAj1UT-ZDJytNRD72R0aFKlv8r0fvOiTDWGXE4P5g";
7
+
8
+ const marketplaceClient = await ElvMarketplaceClient.Initialize({
9
+ configUrl: ClientConfiguration["config-url"]
10
+ });
11
+
12
+ const token = await marketplaceClient.AuthenticateOAuth({
13
+ idToken
14
+ });
15
+
16
+ console.log(token);
17
+ } catch(error) {
18
+ console.error(error);
19
+ console.error(JSON.stringify(error, null, 2));
20
+ }
21
+
22
+ process.exit(0);
23
+ };
24
+
25
+ Test();
@@ -9,7 +9,7 @@ const Logger = require("./lib/concerns/Logger");
9
9
 
10
10
  const permissionTypes = ["owner", "editable", "viewable", "listable", "public"];
11
11
 
12
- class ObjectAddGroupPerms extends Utility {
12
+ class ObjectSetPermission extends Utility {
13
13
  blueprint() {
14
14
  return {
15
15
  concerns: [Logger, ArgObjectId, Client],
@@ -55,7 +55,7 @@ class ObjectAddGroupPerms extends Utility {
55
55
  }
56
56
 
57
57
  if(require.main === module) {
58
- Utility.cmdLineInvoke(ObjectAddGroupPerms);
58
+ Utility.cmdLineInvoke(ObjectSetPermission);
59
59
  } else {
60
- module.exports = ObjectAddGroupPerms;
61
- }
60
+ module.exports = ObjectSetPermission;
61
+ }
@@ -53,6 +53,10 @@ class SimpleIngest extends Utility {
53
53
  const libABRProfile = R.path(["metadata", "abr", "default_profile"], libInfo);
54
54
  if(R.isNil(libABRProfile)) throw Error("Library does not specify ABR profile for simple ingests");
55
55
 
56
+ const libMezManageGroups = R.path(["metadata", "abr", "mez_manage_groups"], libInfo);
57
+
58
+ const libMezPermission = R.path(["metadata", "abr", "mez_permission_level"], libInfo);
59
+
56
60
  const {drm, libraryId, title} = this.args;
57
61
  const encrypt = true;
58
62
 
@@ -91,6 +95,7 @@ class SimpleIngest extends Utility {
91
95
 
92
96
  if(!R.isNil(createMasterResponse.errors) && !R.isEmpty(createMasterResponse.errors)) throw Error(`Error(s) encountered while inspecting uploaded files: ${createMasterResponse.errors.join("\n")}`);
93
97
 
98
+ // TODO: replace with a 'waitForNewObject' call (Finalize.waitForPublish throws exception for brand new object not yet visible)
94
99
  await seconds(2);
95
100
 
96
101
  await this.concerns.Finalize.waitForPublish({
@@ -218,6 +223,42 @@ class SimpleIngest extends Utility {
218
223
  const finalizeErrors = finalizeAbrResponse.errors;
219
224
  if(!R.isNil(finalizeErrors) && !R.isEmpty(finalizeErrors)) throw Error(`Error(s) encountered while finalizing object: ${finalizeErrors.join("\n")}`);
220
225
 
226
+ if(libMezManageGroups && libMezManageGroups.length > 0){
227
+ for(const groupAddress of libMezManageGroups){
228
+ logger.log("Setting access permissions for managers");
229
+ await client.AddContentObjectGroupPermission({
230
+ objectId: id,
231
+ groupAddress,
232
+ permission: "manage"
233
+ });
234
+
235
+ }
236
+ }
237
+
238
+ if(libMezPermission) {
239
+ if(!["owner", "editable", "viewable", "listable", "public"].includes(libMezPermission)) {
240
+ logger.warn(`Bad value for mez_permission_level: '${libMezPermission}', skipping permission setting`);
241
+ } else {
242
+ logger.log(`Setting object permission to '${libMezPermission}'`);
243
+ const prevHash = await client.LatestVersionHash({objectId: id});
244
+
245
+ await client.SetPermission({
246
+ objectId: id,
247
+ permission: libMezPermission
248
+ });
249
+
250
+ const newHash = await client.LatestVersionHash({objectId: id});
251
+
252
+ if(prevHash === newHash) {
253
+ logger.log("Version hash unchanged: " + newHash );
254
+ } else {
255
+ logger.log("Previous version hash: " + prevHash );
256
+ logger.log("New version hash: " + newHash );
257
+ }
258
+ logger.data("version_hash", newHash);
259
+ }
260
+ }
261
+
221
262
  logger.logList(
222
263
  "",
223
264
  "Playable media object created:",
@@ -0,0 +1,180 @@
1
+ {
2
+ "abr": {
3
+ "comments": [
4
+ "For movies/TV - snapAR is set to true, this profile will attempt to conform aspect ratio to nearby standard",
5
+ "also specifies 'store encrypted', offers both clear and drm playout formats"
6
+ ],
7
+ "mez_content_type": "YOUR_TITLE_(MEZ)_CONTENT_TYPE_ID",
8
+ "mez_manage_groups": [
9
+ "ADDRESS_FOR_YOUR_CONTENT_ADMINS_GROUP"
10
+ ],
11
+ "mez_permission_level": "ONE_OF_THE_FOLLOWING: owner, editable, viewable, listable, public",
12
+ "default_profile": {
13
+ "drm_optional": true,
14
+ "store_clear": false,
15
+ "video_parametric_ladder": {
16
+ "baseAspectRatio": "16/9",
17
+ "baseFrameRate": "30",
18
+ "rungSpecs": [
19
+ {
20
+ "dim": 2160,
21
+ "bitrate": 14000000
22
+ },
23
+ {
24
+ "dim": 1440,
25
+ "bitrate": 11500000
26
+ },
27
+ {
28
+ "dim": 1080,
29
+ "bitrate": 9500000
30
+ },
31
+ {
32
+ "dim": 720,
33
+ "bitrate": 4500000
34
+ },
35
+ {
36
+ "dim": 480,
37
+ "bitrate": 1750000
38
+ },
39
+ {
40
+ "dim": 360,
41
+ "bitrate": 810000
42
+ },
43
+ {
44
+ "dim": 240,
45
+ "bitrate": 500000
46
+ }
47
+ ],
48
+ "options": {
49
+ "upscale": false,
50
+ "snapAR": true,
51
+ "maxARSnap": 0.06,
52
+ "minDimStepdown": 0.12,
53
+ "frameRateScaleFactor": 0.5
54
+ },
55
+ "limits": {
56
+ "aspectRatioMax": "3",
57
+ "aspectRatioMin": "1/3",
58
+ "avgBitrateMax": 100000000,
59
+ "avgBitrateMin": 100000,
60
+ "fileSizeMax": 100000000,
61
+ "fileSizeMin": 10000,
62
+ "durationMax": 14400,
63
+ "durationMin": 1,
64
+ "finalBitrateMax": 30000000,
65
+ "frameRateMax": "60",
66
+ "frameRateMin": "15",
67
+ "heightMax": 5000,
68
+ "heightMin": 100,
69
+ "sampleAspectRatioMax": "3/2",
70
+ "sampleAspectRatioMin": "2/3",
71
+ "widthMax": 5000,
72
+ "widthMin": 100
73
+ }
74
+ },
75
+ "ladder_specs": {
76
+ "{\"media_type\":\"audio\",\"channels\":1}": {
77
+ "rung_specs": [
78
+ {
79
+ "bit_rate": 128000,
80
+ "media_type": "audio",
81
+ "pregenerate": true
82
+ }
83
+ ]
84
+ },
85
+ "{\"media_type\":\"audio\",\"channels\":2}": {
86
+ "rung_specs": [
87
+ {
88
+ "bit_rate": 192000,
89
+ "media_type": "audio",
90
+ "pregenerate": true
91
+ }
92
+ ]
93
+ },
94
+ "{\"media_type\":\"audio\",\"channels\":6}": {
95
+ "rung_specs": [
96
+ {
97
+ "bit_rate": 384000,
98
+ "media_type": "audio",
99
+ "pregenerate": true
100
+ }
101
+ ]
102
+ }
103
+ },
104
+ "playout_formats": {
105
+ "dash-widevine": {
106
+ "drm": {
107
+ "content_id": "",
108
+ "enc_scheme_name": "cenc",
109
+ "license_servers": [],
110
+ "type": "DrmWidevine"
111
+ },
112
+ "protocol": {
113
+ "min_buffer_length": 2,
114
+ "type": "ProtoDash"
115
+ }
116
+ },
117
+ "hls-aes128": {
118
+ "drm": {
119
+ "enc_scheme_name": "aes-128",
120
+ "type": "DrmAes128"
121
+ },
122
+ "protocol": {
123
+ "type": "ProtoHls"
124
+ }
125
+ },
126
+ "hls-fairplay": {
127
+ "drm": {
128
+ "enc_scheme_name": "cbcs",
129
+ "license_servers": [],
130
+ "type": "DrmFairplay"
131
+ },
132
+ "protocol": {
133
+ "type": "ProtoHls"
134
+ }
135
+ },
136
+ "hls-sample-aes": {
137
+ "drm": {
138
+ "enc_scheme_name": "cbcs",
139
+ "type": "DrmSampleAes"
140
+ },
141
+ "protocol": {
142
+ "type": "ProtoHls"
143
+ }
144
+ },
145
+ "dash-clear": {
146
+ "drm": null,
147
+ "protocol": {
148
+ "min_buffer_length": 2,
149
+ "type": "ProtoDash"
150
+ }
151
+ },
152
+ "hls-clear": {
153
+ "drm": null,
154
+ "protocol": {
155
+ "type": "ProtoHls"
156
+ }
157
+ }
158
+ },
159
+ "segment_specs": {
160
+ "audio": {
161
+ "segs_per_chunk": 15,
162
+ "target_dur": 2
163
+ },
164
+ "video": {
165
+ "segs_per_chunk": 15,
166
+ "target_dur": 2
167
+ }
168
+ }
169
+ }
170
+ },
171
+ "elv": {
172
+ "media": {
173
+ "drm": {
174
+ "fps": {
175
+ "cert": "MIIExzCCA6+gAwIBAgIIHyfkXhxLHC4wDQYJKoZIhvcNAQEFBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYDVQQDDCpBcHBsZSBLZXkgU2VydmljZXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwOTEyMDMzMjI0WhcNMjIwOTEzMDMzMjI0WjBgMQswCQYDVQQGEwJVUzETMBEGA1UECgwKRWx1dmlvIEluYzETMBEGA1UECwwKMktIOEtDM01NWDEnMCUGA1UEAwweRmFpclBsYXkgU3RyZWFtaW5nOiBFbHV2aW8gSW5jMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDslbBURB6gj07g7VrS7Ojixe7FNZOupomcZt+mtMvyavjg7X7/T4RccmKUQxOoMLKCJcQ6WrdHhIpN8+bciq7lr0mNzaN467zREiUNYOpkVPi13sJLieY2m2MEPOQTbIl52Cu1YyH+4/g1dKPmeguSnzZRo36jsCGHlJBjHq0jkQIDAQABo4IB6DCCAeQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRj5EdUy4VxWUYsg6zMRDFkZwMsvjCB4gYDVR0gBIHaMIHXMIHUBgkqhkiG92NkBQEwgcYwgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5hcHBsZS5jb20va2V5c2VydmljZXMuY3JsMB0GA1UdDgQWBBR4jerseBHEUDC7mU+NQuIzZqHRFDAOBgNVHQ8BAf8EBAMCBSAwOAYLKoZIhvdjZAYNAQMBAf8EJgFuNnNkbHQ2OXFuc3l6eXp5bWFzdmdudGthbWd2bGE1Y212YzdpMC4GCyqGSIb3Y2QGDQEEAQH/BBwBd252bHhlbGV1Y3Vpb2JyZW4yeHZlZmV6N2Y5MA0GCSqGSIb3DQEBBQUAA4IBAQBM17YYquw0soDPAadr1aIM6iC6BQ/kOGYu3y/6AlrwYgAQNFy8DjsQUoqlQWFuA0sigp57bTUymkXEBf9yhUmXXiPafGjbxzsPF5SPFLIciolWbxRCB153L1a/Vh2wg3rhf4IvAZuJpnml6SSg5SjD19bN+gD7zrtp3yWKBKuarLSjDvVIB1SoxEToBs3glAEqoBiA2eZjikBA0aBlbvjUF2gqOmZjZJ7dmG1Tos2Zd4SdGL6ltSpKUeSGSxyv41aqF83vNpymNJmey2t2kPPtC7mt0LM32Ift3AkAl8Za9JbV/pOnc95oAfPhVTOGOI+u2BuB2qaKWjqHwkfqCz4A"
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,133 @@
1
+ {
2
+ "abr": {
3
+ "comments": [
4
+ "For animation NFTs that are not movie/TV clips - snapAR is set to false",
5
+ "also specifies 'store clear', only offers clear playout formats (no drm)",
6
+ "and object permission 'listable'.",
7
+ "does not include DRM cert @ /elv/media/drm/fps/cert"
8
+ ],
9
+ "mez_content_type": "YOUR_TITLE_(NFT)_CONTENT_TYPE_ID",
10
+ "mez_manage_groups": [
11
+ "ADDRESS_FOR_YOUR_CONTENT_ADMINS_GROUP"
12
+ ],
13
+ "mez_permission_level": "listable",
14
+ "default_profile": {
15
+ "drm_optional": true,
16
+ "store_clear": true,
17
+ "video_parametric_ladder": {
18
+ "baseAspectRatio": "16/9",
19
+ "baseFrameRate": "30",
20
+ "rungSpecs": [
21
+ {
22
+ "dim": 2160,
23
+ "bitrate": 14000000
24
+ },
25
+ {
26
+ "dim": 1440,
27
+ "bitrate": 11500000
28
+ },
29
+ {
30
+ "dim": 1080,
31
+ "bitrate": 9500000
32
+ },
33
+ {
34
+ "dim": 720,
35
+ "bitrate": 4500000
36
+ },
37
+ {
38
+ "dim": 480,
39
+ "bitrate": 1750000
40
+ },
41
+ {
42
+ "dim": 360,
43
+ "bitrate": 810000
44
+ },
45
+ {
46
+ "dim": 240,
47
+ "bitrate": 500000
48
+ }
49
+ ],
50
+ "options": {
51
+ "upscale": false,
52
+ "snapAR": false,
53
+ "maxARSnap": 0.06,
54
+ "minDimStepdown": 0.12,
55
+ "frameRateScaleFactor": 0.5
56
+ },
57
+ "limits": {
58
+ "aspectRatioMax": "3",
59
+ "aspectRatioMin": "1/3",
60
+ "avgBitrateMax": 100000000,
61
+ "avgBitrateMin": 100000,
62
+ "fileSizeMax": 100000000,
63
+ "fileSizeMin": 10000,
64
+ "durationMax": 14400,
65
+ "durationMin": 1,
66
+ "finalBitrateMax": 30000000,
67
+ "frameRateMax": "60",
68
+ "frameRateMin": "15",
69
+ "heightMax": 5000,
70
+ "heightMin": 100,
71
+ "sampleAspectRatioMax": "3/2",
72
+ "sampleAspectRatioMin": "2/3",
73
+ "widthMax": 5000,
74
+ "widthMin": 100
75
+ }
76
+ },
77
+ "ladder_specs": {
78
+ "{\"media_type\":\"audio\",\"channels\":1}": {
79
+ "rung_specs": [
80
+ {
81
+ "bit_rate": 128000,
82
+ "media_type": "audio",
83
+ "pregenerate": true
84
+ }
85
+ ]
86
+ },
87
+ "{\"media_type\":\"audio\",\"channels\":2}": {
88
+ "rung_specs": [
89
+ {
90
+ "bit_rate": 192000,
91
+ "media_type": "audio",
92
+ "pregenerate": true
93
+ }
94
+ ]
95
+ },
96
+ "{\"media_type\":\"audio\",\"channels\":6}": {
97
+ "rung_specs": [
98
+ {
99
+ "bit_rate": 384000,
100
+ "media_type": "audio",
101
+ "pregenerate": true
102
+ }
103
+ ]
104
+ }
105
+ },
106
+ "playout_formats": {
107
+ "dash-clear": {
108
+ "drm": null,
109
+ "protocol": {
110
+ "min_buffer_length": 2,
111
+ "type": "ProtoDash"
112
+ }
113
+ },
114
+ "hls-clear": {
115
+ "drm": null,
116
+ "protocol": {
117
+ "type": "ProtoHls"
118
+ }
119
+ }
120
+ },
121
+ "segment_specs": {
122
+ "audio": {
123
+ "segs_per_chunk": 15,
124
+ "target_dur": 2
125
+ },
126
+ "video": {
127
+ "segs_per_chunk": 15,
128
+ "target_dur": 2
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }