@eluvio/elv-client-js 4.0.10 → 4.0.12

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 (78) hide show
  1. package/dist/.keep +0 -0
  2. package/dist/ElvClient-min.js +10 -10
  3. package/dist/ElvClient-node-min.js +3 -3
  4. package/dist/ElvFrameClient-min.js +10 -10
  5. package/dist/ElvWalletClient-min.js +9 -9
  6. package/dist/ElvWalletClient-node-min.js +3 -3
  7. package/dist/src/AuthorizationClient.js +7 -8
  8. package/dist/src/client/Files.js +2 -1
  9. package/package.json +4 -21
  10. package/src/AuthorizationClient.js +5 -5
  11. package/src/client/Files.js +1 -1
  12. package/dist/AccessClient-min.js +0 -54
  13. package/dist/AccessClient-node-min.js +0 -74
  14. package/dist/src/AccessClient.js +0 -798
  15. package/dist/src/LimitedMap.js +0 -120
  16. package/dist/src/client/Access.js +0 -1
  17. package/dist/src/client/Management.js +0 -1606
  18. package/dist/src/contracts/AccessIndexor.js +0 -831
  19. package/dist/src/contracts/Accessible.js +0 -31
  20. package/dist/src/contracts/AdmgrAdvertisement.js +0 -695
  21. package/dist/src/contracts/AdmgrCampaign.js +0 -648
  22. package/dist/src/contracts/AdmgrCampaignManager.js +0 -493
  23. package/dist/src/contracts/AdmgrCommercialOffering.js +0 -622
  24. package/dist/src/contracts/AdmgrCommercialOfferingManager.js +0 -413
  25. package/dist/src/contracts/AdmgrMarketPlace.js +0 -413
  26. package/dist/src/contracts/AvailsDelivery.js +0 -535
  27. package/dist/src/contracts/BaseAccessControlGroup.js +0 -1221
  28. package/dist/src/contracts/BaseAccessWallet.js +0 -1575
  29. package/dist/src/contracts/BaseAccessWalletFactory.js +0 -93
  30. package/dist/src/contracts/BaseContent.js +0 -1104
  31. package/dist/src/contracts/BaseContentFactory.js +0 -99
  32. package/dist/src/contracts/BaseContentFactoryExt.js +0 -219
  33. package/dist/src/contracts/BaseContentSpace.js +0 -1346
  34. package/dist/src/contracts/BaseContentType.js +0 -353
  35. package/dist/src/contracts/BaseFactory.js +0 -107
  36. package/dist/src/contracts/BaseGroupFactory.js +0 -93
  37. package/dist/src/contracts/BaseLibrary.js +0 -1035
  38. package/dist/src/contracts/BaseLibraryFactory.js +0 -96
  39. package/dist/src/contracts/Certifyer.js +0 -87
  40. package/dist/src/contracts/Container.js +0 -543
  41. package/dist/src/contracts/Content.js +0 -432
  42. package/dist/src/contracts/Editable.js +0 -295
  43. package/dist/src/contracts/FactorySpace.js +0 -57
  44. package/dist/src/contracts/KmsSpace.js +0 -52
  45. package/dist/src/contracts/LvProvider.js +0 -512
  46. package/dist/src/contracts/LvRecordableStream.js +0 -1026
  47. package/dist/src/contracts/LvRecording.js +0 -627
  48. package/dist/src/contracts/LvStreamRightsHolder.js +0 -551
  49. package/dist/src/contracts/MetaObject.js +0 -110
  50. package/dist/src/contracts/Node.js +0 -167
  51. package/dist/src/contracts/NodeSpace.js +0 -18
  52. package/dist/src/contracts/NodeSpaceImpl.js +0 -273
  53. package/dist/src/contracts/Ownable.js +0 -87
  54. package/dist/src/contracts/PaymentService.js +0 -616
  55. package/dist/src/contracts/Precompile.js +0 -15
  56. package/dist/src/contracts/SampleContentAdMarketplace.js +0 -564
  57. package/dist/src/contracts/SampleContentAdvertising.js +0 -444
  58. package/dist/src/contracts/SampleContentHelloWorld.js +0 -459
  59. package/dist/src/contracts/SampleContentLicensing.js +0 -618
  60. package/dist/src/contracts/SampleContentSigned.js +0 -447
  61. package/dist/src/contracts/SampleInstance.js +0 -438
  62. package/dist/src/contracts/SampleInstanceFactory.js +0 -451
  63. package/dist/src/contracts/Transactable.js +0 -82
  64. package/dist/src/contracts/UserSpace.js +0 -18
  65. package/dist/src/contracts/UserSpaceImpl.js +0 -43
  66. package/dist/src/contracts/Utils.js +0 -18
  67. package/dist/src/contracts/Verifier.js +0 -53
  68. package/dist/src/contracts/strings.js +0 -4
  69. package/dist/src/contracts/v2/BaseContentFactoryExt.js +0 -219
  70. package/dist/src/contracts/v2/FactorySpace.js +0 -57
  71. package/dist/src/contracts/v2/KmsSpace.js +0 -52
  72. package/dist/src/contracts/v2/NodeSpaceImpl.js +0 -273
  73. package/dist/src/contracts/v2/UserSpaceImpl.js +0 -43
  74. package/dist/src/marketplaceClient/ClientMethods.js +0 -1918
  75. package/dist/src/marketplaceClient/Configuration.js +0 -29
  76. package/dist/src/marketplaceClient/Utils.js +0 -304
  77. package/dist/src/marketplaceClient/index.js +0 -1553
  78. package/testScripts/CreateMezMonolithic.js +0 -779
@@ -1,779 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- const R = require("ramda");
4
- const curry = require("crocks/helpers/curry");
5
- const pipe = require("crocks/helpers/pipe");
6
-
7
- const {
8
- ObjectModel,
9
- NonNegativeInteger,
10
- PositiveInteger
11
- } = require("../utilities/lib/models/Models");
12
-
13
-
14
- const MP4AtomReadContextModel = ObjectModel(
15
- {
16
- buffer: Buffer,
17
- currentAtomLength: PositiveInteger,
18
- currentAtomStart: NonNegativeInteger,
19
- posWithinAtom: NonNegativeInteger
20
- })
21
- .assert(x => x.currentAtomLength >= 8, ()=>"currentAtomLength must be >= 8")
22
- .assert(x => x.posWithinAtom < x.currentAtomLength, ()=>"posWithinAtom must be < currentAtomLength")
23
- .assert(x => (x.currentAtomStart + x.currentAtomLength) <= x.buffer.length,()=> "currentAtomStart + currentAtomLength must be <= buffer.length");
24
-
25
- class MP4AtomReadContext extends MP4AtomReadContextModel
26
- {
27
-
28
- get currentAtomBytesLeft() {
29
- return this.currentAtomLength - this.posWithinAtom;
30
- }
31
-
32
- get currentAtomEnd() {
33
- return this.currentAtomStart + this.currentAtomLength;
34
- }
35
-
36
- get currentBufPos() {
37
- return this.currentAtomStart + this.posWithinAtom;
38
- }
39
- }
40
-
41
- // enter atom under read head, then move read head past header (length and type fields)
42
- const enter = readContext => {
43
- let {atomType, atomLength, headerLength} = readHeader(readContext);
44
- // logger.log(`Entering atom '${atomType}', atom start = ${readContext.currentBufPos}, skipping ${headerLength} byte header`);
45
- return new MP4AtomReadContext(
46
- {
47
- buffer: readContext.buffer,
48
- currentAtomLength: atomLength,
49
- currentAtomStart: readContext.currentBufPos,
50
- currentAtomType: atomType,
51
- posWithinAtom: headerLength
52
- }
53
- );
54
- };
55
-
56
- // Read atoms without entering, looking for particular atom atomType(s)
57
- // The read head must be at the start of any atom (reading the next 4 bytes must return the length field)
58
- const find = curry(
59
- (atomTypes, readContext) => {
60
- let eof = false;
61
- let found = false;
62
- while(!found && !eof) {
63
- let {atomType, atomLength} = readHeader(readContext);
64
- if(atomTypes.includes(atomType)) {
65
- found = true;
66
- } else {
67
- // skip to next atom
68
- readContext = moveWithin(atomLength, readContext);
69
- // check if we have run out of data
70
- if(readContext.posWithinAtom === readContext.currentAtomLength) eof = true;
71
- }
72
- }
73
- if(!found) throw Error(`Atom type(s) not found: ${atomTypes}`);
74
-
75
- return readContext;
76
- }
77
- );
78
-
79
- const findAndEnter = curry(
80
- (atomTypes, readContext) => {
81
- return enter(find(atomTypes, readContext));
82
- }
83
- );
84
-
85
- const moveWithin = curry(
86
- (offset, readContext) => {
87
- // logger.log(`Move within atom: ${offset} bytes`);
88
-
89
- const newPosWithinParent = readContext.posWithinAtom + offset;
90
- if(newPosWithinParent >= readContext.currentAtomLength) throw Error("Cannot move past end of atom");
91
- if(newPosWithinParent < 0) throw Error("Cannot move before beginning of atom");
92
- return new MP4AtomReadContext({
93
- buffer: readContext.buffer,
94
- currentAtomLength: readContext.currentAtomLength,
95
- currentAtomStart: readContext.currentAtomStart,
96
- currentAtomType: readContext.currentAtomType,
97
- posWithinAtom: newPosWithinParent
98
- });
99
- }
100
- );
101
-
102
-
103
- const newContextFromBuffer = buffer => {
104
- return new MP4AtomReadContext({
105
- buffer,
106
- currentAtomLength: buffer.length,
107
- currentAtomStart: 0,
108
- currentAtomType: "",
109
- posWithinAtom: 0
110
- });
111
- };
112
-
113
- const readAtom = readContext => {
114
- const {atomLength} = readHeader(readContext);
115
- const atomStart = readContext.currentBufPos;
116
- const atomEnd = atomStart + atomLength;
117
- return readContext.buffer.subarray(atomStart, atomEnd);
118
- };
119
-
120
- const readHeader = readContext => {
121
- const {buffer, currentAtomBytesLeft, currentBufPos} = readContext;
122
- let headerLength = 8;
123
-
124
- if(currentAtomBytesLeft < headerLength) throw Error("Cannot read atom, not enough bytes available to hold atomLength + type fields");
125
-
126
- // read 4 bytes to get atomLength
127
- let atomLength = buffer.readUInt32BE(currentBufPos);
128
- if(atomLength === 0 || (atomLength > 1 && atomLength < 8)) throw Error(`Invalid length 0 found: ${atomLength}`);
129
-
130
- // read 4 bytes to get atom type
131
- const atomType = buffer.toString("ascii", currentBufPos + 4, currentBufPos + 8);
132
-
133
- // if atomLength === 1, need to read 8 more bytes to get 64-bit atomLength
134
- if(atomLength === 1) {
135
- headerLength = 16;
136
- if(currentAtomBytesLeft < headerLength) throw Error("Cannot read atom, not enough bytes available to hold 64-bit atomLength field");
137
- atomLength = buffer.readUInt64BE(currentBufPos + 8);
138
- }
139
-
140
- if(atomLength > currentAtomBytesLeft) {
141
- throw Error(`Invalid length found: ${atomLength} (only ${currentAtomBytesLeft} available)`);
142
- }
143
-
144
- return {atomLength, atomType, headerLength};
145
- };
146
-
147
- module.exports = {
148
- enter,
149
- find,
150
- findAndEnter,
151
- moveWithin,
152
- MP4AtomReadContext,
153
- newContextFromBuffer,
154
- readAtom,
155
- readHeader
156
- };
157
-
158
-
159
-
160
- // takes buffer containing MP4 init segment (or entire MP4 file) for a single x264/x265 video stream
161
- // and returns codec descriptor string (e.g. "avc1.640028", "hev1.2.4.L150.90" etc.)
162
- const codecDesc = buffer => {
163
- let resultContext = decoderConfigAtom(buffer);
164
- let {atomLength, atomType, headerLength} = readHeader(resultContext);
165
-
166
- // make new buffer that omits header (length and type fields)
167
- const decoderBodyBuf = resultContext.buffer.subarray(headerLength, atomLength);
168
- switch(atomType) {
169
- case "avcC":
170
- return x264codecString(decoderBodyBuf);
171
- case "hvcC":
172
- return x265codecString(decoderBodyBuf);
173
- default:
174
- throw Error(`Unknown decoder configuration atom type: '${atomType}'`);
175
- }
176
- };
177
-
178
- // buffer containing init segment -> MP4AtomReadContext with buffer containing only avcC or hvcC atom
179
- const decoderConfigAtom = pipe(
180
- newContextFromBuffer,
181
- findAndEnter(["moov"]),
182
- findAndEnter(["trak"]),
183
- findAndEnter(["mdia"]),
184
- findAndEnter(["minf"]),
185
- findAndEnter(["stbl"]),
186
- findAndEnter(["stsd"]),
187
- moveWithin(8),
188
- findAndEnter(["avc1", "encv", "hev1"]),
189
- moveWithin(78),
190
- find(["avcC", "hvcC"]),
191
- readAtom,
192
- newContextFromBuffer
193
- );
194
-
195
- // takes buffer containing decoder config atom (without the type/length fields at front) and returns x264 codec string
196
- const x264codecString = atomBodyBuf => {
197
- // See https://dvb.org/wp-content/uploads/2019/10/a168_DVB_MPEG-DASH_Nov_2017.pdf
198
-
199
- if(atomBodyBuf.length < 4) throw Error("Not enough bytes in AVCDecoderConfiguration");
200
-
201
- const avcProfileIndication = atomBodyBuf.readUInt8(1).toString(16).padStart(2, "0");
202
- const profileCompatibility = atomBodyBuf.readUInt8(2).toString(16).padStart(2, "0");
203
- const avcLevelIndication = atomBodyBuf.readUInt8(3).toString(16).padStart(2, "0");
204
- return `avc1.${avcProfileIndication}${profileCompatibility}${avcLevelIndication}`;
205
- };
206
-
207
- // takes buffer containing decoder config atom (without the type/length fields at front) and returns x265 codec string
208
- const x265codecString = atomBodyBuf => {
209
- // See https://dvb.org/wp-content/uploads/2019/10/a168_DVB_MPEG-DASH_Nov_2017.pdf
210
-
211
- if(atomBodyBuf.length < 13) throw Error("Not enough bytes in HVCDecoderConfiguration");
212
-
213
- // parse bytes/bits into values
214
- const bitFlags = atomBodyBuf.readUInt8(1);
215
- const genProfileSpaceBits = (bitFlags & 0b11000000) >>> 6;
216
- const genTierBit = (bitFlags & 0b00100000) >>> 5;
217
- const genProfileIDC = bitFlags & 0b00011111;
218
- const genProfileCompatibility = parseInt(R.reverse(atomBodyBuf.readUInt32BE(2).toString(2).padStart(32, "0")), 2).toString(16);
219
- let genConstraintFlags = [
220
- atomBodyBuf.readUInt8(6),
221
- atomBodyBuf.readUInt8(7),
222
- atomBodyBuf.readUInt8(8),
223
- atomBodyBuf.readUInt8(9),
224
- atomBodyBuf.readUInt8(10),
225
- atomBodyBuf.readUInt8(11)
226
- ];
227
- const genLevelIDC = atomBodyBuf.readUInt8(12);
228
-
229
- // Format values into appropriate strings
230
-
231
- // CODECSTRING = CODEC "." PROFILE "." LEVEL "." CONSTRAINTS
232
-
233
- // CODEC = ("hev1" | "hvc1" )
234
- let pieces = ["hev1"];
235
-
236
- // PROFILE = PROFILE_SPACE PROFILE_IDC "." PROFILE_COMPATIBILITY
237
-
238
- // PROFILE_SPACE = "" | "A" | "B" | "C" (for general_profile_space values 0,1,2,3)
239
- let profileSpace = "";
240
- switch(genProfileSpaceBits){
241
- case 1:
242
- profileSpace = "A";
243
- break;
244
- case 2:
245
- profileSpace = "B";
246
- break;
247
- case 3:
248
- profileSpace = "C";
249
- break;
250
- }
251
-
252
- // PROFILE_IDC is a decimal number, PROFILE_COMPATIBILITY is a hex string
253
- const profile = `${profileSpace}${genProfileIDC}.${genProfileCompatibility}`;
254
- pieces.push(profile);
255
-
256
- // LEVEL = TIER LEVEL_IDC
257
-
258
- // TIER = "L" / "H" (general_tier_flag, 0=="L", 1=="H")
259
- const tier = genTierBit ? "H" : "L";
260
- const level = `${tier}${genLevelIDC}`;
261
- pieces.push(level);
262
-
263
- // CONSTRAINTS = 2(HEXDIG) [ "." CONSTRAINTS ] (hexadecimal representation of the general_constraint_indicator_flags. Each byte is separated by a '.', and trailing zero bytes may be omitted.)
264
-
265
- while(genConstraintFlags.length > 0 && genConstraintFlags.slice(-1)[0] === 0) {
266
- genConstraintFlags.pop();
267
- }
268
- const constraints = genConstraintFlags.map(x => x.toString(16)).join(".");
269
- pieces.push(constraints);
270
-
271
- return pieces.join(".");
272
- };
273
-
274
-
275
-
276
- const setCodecDescs = async ({elvClient, libraryId, objectId, offeringKey, offeringMetadata, writeToken}) => {
277
-
278
- // get first available playout format (for constructing init segment urls)
279
- const formats = offeringMetadata.playout.playout_formats;
280
- const firstFormatKey = Object.keys(formats)[0];
281
- const player_profile = formats[firstFormatKey].drm && formats[firstFormatKey].drm.type === "DrmAes128" ?
282
- "hls-js" :
283
- "";
284
-
285
- // find video streams, request init segments, set codec_desc
286
- for(const [streamKey, stream] of Object.entries(offeringMetadata.media_struct.streams)) {
287
- if(stream.codec_type === "video") {
288
- console.log(`constructing codec strings for stream '${streamKey}'...`);
289
- // get bitrate ladder
290
- const reps = offeringMetadata.playout.streams[streamKey].representations;
291
- for(const [repKey, rep] of R.sortBy(x => -x[1].bit_rate, Object.entries(reps))) {
292
- const initSegUrl = `playout/${offeringKey}/${firstFormatKey}/${streamKey}/${repKey}/init.m4s`;
293
- console.log("\n>> calling ElvClient.FabricUrl() with noAuth: false\n");
294
- const url = new URL(
295
- await elvClient.FabricUrl({
296
- libraryId,
297
- objectId,
298
- rep: initSegUrl,
299
- writeToken,
300
- noAuth: false,
301
- })
302
- );
303
-
304
- const path = url.pathname;
305
- let queryParams = {
306
- authorization: url.searchParams.get("authorization")
307
- };
308
- if(player_profile) queryParams.player_profile = player_profile;
309
-
310
- console.log(`\n\nretrieving init segment @ ${url.href}\n`);
311
- console.log(`queryParams: ${JSON.stringify(queryParams)}\n\n`);
312
-
313
- // get init segment
314
- const response = await elvClient.HttpClient.Request({
315
- path,
316
- queryParams,
317
- method: "GET"
318
- });
319
- const buffer = Buffer.from(await response.arrayBuffer());
320
-
321
- console.log(`constructing codec desc... ${repKey}`);
322
-
323
- // make codec desc based on init seg
324
- rep.codec_desc = codecDesc(buffer);
325
- }
326
- }
327
- }
328
-
329
- return {};
330
- };
331
-
332
-
333
-
334
- const Utils = require("../src/Utils");
335
-
336
- const preFinalizeFn = async ({elvClient, nodeUrl, writeToken}) => {
337
-
338
- console.log(`\n\npreFinalizeFn() nodeUrl: ${JSON.stringify(nodeUrl,null,2)} writeToken: ${JSON.stringify(writeToken,null,2)}`);
339
-
340
- const objectId = Utils.DecodeWriteToken(writeToken).objectId;
341
- const libraryId = await elvClient.ContentObjectLibraryId({objectId});
342
-
343
- // make sure client knows proper node to contact
344
- elvClient.HttpClient.RecordWriteToken(writeToken, nodeUrl);
345
-
346
- // get metadata from draft
347
- const abrMezOfferingsMetadata = await elvClient.ContentObjectMetadata({
348
- libraryId,
349
- metadataSubtree: "/abr_mezzanine/offerings",
350
- objectId,
351
- writeToken
352
- });
353
-
354
- if(!abrMezOfferingsMetadata) throw Error("codecDescPrefinalizeFn: null metadata /abr_mezzanine/offerings from draft");
355
-
356
- // get offering keys (there will be more than one if addlOfferingSpecs was used)
357
- const offeringKeys = Object.keys(abrMezOfferingsMetadata);
358
- if(offeringKeys.length === 0) throw Error("codecDescPrefinalizeFn: no offering keys found in draft's /abr_mezzanine/offerings");
359
-
360
- // construct new metadata with codec descriptions included
361
- const newAbrMezOffMetadata = {};
362
- for(const offeringKey of offeringKeys) {
363
- newAbrMezOffMetadata[offeringKey] = await setCodecDescs({
364
- elvClient,
365
- libraryId,
366
- objectId,
367
- offeringKey,
368
- offeringMetadata: abrMezOfferingsMetadata[offeringKey],
369
- writeToken
370
- });
371
- }
372
-
373
- console.log("WRITING BACK TO METADATA...");
374
-
375
- // write metadata back to draft
376
- await elvClient.ReplaceMetadata({
377
- libraryId,
378
- metadata: newAbrMezOffMetadata,
379
- metadataSubtree: "/abr_mezzanine/offerings",
380
- objectId,
381
- writeToken
382
- });
383
-
384
- };
385
-
386
-
387
- /* eslint-disable no-console */
388
- const ScriptBase = require("./parentClasses/ScriptBase");
389
- ScriptBase.deprecationNotice("MezzanineCreate.js");
390
-
391
-
392
- const {ElvClient} = require("../src/ElvClient");
393
- const readline = require("readline");
394
- const fs = require("fs");
395
-
396
- const yargs = require("yargs");
397
- const argv = yargs
398
- .option("library", {
399
- description: "ID of the library in which to create the mezzanine"
400
- })
401
- .option("masterHash", {
402
- description: "Version hash of the master object"
403
- })
404
- .option("type", {
405
- description: "Name, object ID, or version hash of the type for the mezzanine"
406
- })
407
- .option("name", {
408
- description: "Name for the mezzanine object (derived from ip-title-id and title if not provided)"
409
- })
410
- .option("title", {
411
- description: "Title for the mezzanine"
412
- })
413
- .option("display-title", {
414
- description: "Display title for the mezzanine (set to title if not specified)"
415
- })
416
- .option("slug", {
417
- description: "Slug for the mezzanine (generated based on title if not specified)"
418
- })
419
- .option("ip-title-id", {
420
- description: "IP title ID for the mezzanine (equivalent to slug if not specified)",
421
- type: "string"
422
- })
423
- .option("title-type", {
424
- description: "Title type for the mezzanine",
425
- default: "title"
426
- })
427
- .option("asset-type", {
428
- description: "Asset type for the mezzanine",
429
- default: "primary"
430
- })
431
- .option("addlOfferingSpecs", {
432
- description: "Additional offerings to create via patching - JSON string (or file path if prefixed with '@')"
433
- })
434
- .option("metadata", {
435
- description: "Metadata JSON string (or file path if prefixed with '@') to include in the object metadata"
436
- })
437
- .option("variant", {
438
- description: "Variant of the mezzanine",
439
- default: "default"
440
- })
441
- .option("offering-key", {
442
- description: "Offering key for the new mezzanine",
443
- default: "default"
444
- })
445
- .option("existingMezzId", {
446
- description: "If using an existing object to store mezzanine offering, the ID of that object",
447
- type: "string"
448
- })
449
- .option("keep-other-streams", {
450
- description: "If using an existing object to store mezzanine offering, and offering already exists,whether to preserve other streams",
451
- default: false,
452
- type: "boolean",
453
- })
454
- .option("stream-keys", {
455
- description: "If supplied, only the specified stream(s) will be processed",
456
- string: true,
457
- type: "array",
458
- })
459
- .option("abr-profile", {
460
- description: "Path to JSON file containing alternative ABR profile"
461
- })
462
- .option("elv-geo", {
463
- type: "string",
464
- description: "Geographic region for the fabric nodes. Available regions: na-west-north, na-west-south, na-east, eu-west, eu-east, as-east, au-east"
465
- })
466
- .option("config-url", {
467
- type: "string",
468
- description: "URL pointing to the Fabric configuration. i.e. https://main.net955210.contentfabric.io/config"
469
- })
470
- .option("credentials", {
471
- type: "string",
472
- description: "Path to JSON file containing credential sets for files stored in cloud"
473
- })
474
- .option("debug", {
475
- type: "boolean",
476
- description: "Enable client logging"
477
- })
478
- .option("wait", {
479
- type: "boolean",
480
- description: "Wait for mezzanine to finish transcoding, then finalize before exiting script"
481
- })
482
- .demandOption(
483
- ["library", "masterHash", "type"],
484
- "\nUsage: PRIVATE_KEY=<private-key> node CreateABRMezzanine.js --library <mezzanine-library-id> --type <type> </type>--masterHash <production-master-hash> --title <title> (--variant <variant>) (--metadata '<metadata-json>') (--addlOfferingSpecs '<specs-json>') (--existingMezzId <object-id>) (--elv-geo eu-west)\n"
485
- )
486
- .strict().argv;
487
-
488
- const ClientConfiguration = (!argv["config-url"]) ? (require("../TestConfiguration.json")) : {"config-url": argv["config-url"]};
489
-
490
- const Slugify = str =>
491
- (str || "").toLowerCase().replace(/ /g, "-").replace(/[^a-z0-9-]/g, "");
492
-
493
- const Report = response => {
494
- if(response.errors.length > 0) {
495
- console.error("Errors:");
496
- console.error(response.errors.join("\n"), "\n");
497
- }
498
-
499
- if(response.warnings.length) {
500
- console.warn("Warnings:");
501
- console.warn(response.warnings.join("\n"), "\n");
502
- }
503
- };
504
-
505
- const Create = async (
506
- {
507
- library,
508
- masterHash,
509
- type,
510
- variant,
511
- offeringKey,
512
- name,
513
- title,
514
- displayTitle,
515
- slug,
516
- ipTitleId,
517
- titleType,
518
- assetType,
519
- metadata,
520
- addlOfferingSpecs,
521
- existingMezzId,
522
- abrProfile,
523
- elvGeo,
524
- credentials,
525
- debug,
526
- wait = false,
527
- keepOtherStreams,
528
- streamKeys
529
- }
530
- ) => {
531
-
532
- if(!existingMezzId && (keepOtherStreams)) {
533
- throw Error("--existingMezzId required when using --keepOtherStreams");
534
- }
535
-
536
- if(addlOfferingSpecs && !abrProfile) {
537
- throw Error("--abrProfile required when using --addlOfferingSpecs");
538
- }
539
-
540
- // force ipTitleId to be a string, if present
541
- if(ipTitleId) {
542
- ipTitleId = ipTitleId.toString();
543
- }
544
-
545
- try {
546
- const privateKey = process.env.PRIVATE_KEY;
547
- if(!privateKey) {
548
- console.error("PRIVATE_KEY environment variable must be specified");
549
- return;
550
- }
551
-
552
- if(!existingMezzId && !title) {
553
- throw Error("--title argument is required unless --existingMezzId is specified");
554
- }
555
-
556
- const client = await ElvClient.FromConfigurationUrl({
557
- configUrl: ClientConfiguration["config-url"],
558
- region: elvGeo
559
- });
560
-
561
- let wallet = client.GenerateWallet();
562
- let signer = wallet.AddAccount({
563
- privateKey: process.env.PRIVATE_KEY
564
- });
565
-
566
- await client.SetSigner({signer});
567
-
568
- if(debug) {
569
- client.ToggleLogging(true);
570
- }
571
-
572
- // construct metadata
573
- if(metadata) {
574
- try {
575
- if(metadata.startsWith("@")) {
576
- metadata = fs.readFileSync(metadata.substring(1));
577
- }
578
-
579
- metadata = JSON.parse(metadata) || {};
580
- if(!metadata.public) {
581
- metadata.public = {};
582
- }
583
-
584
- name = name || metadata.public.name || metadata.name;
585
- } catch(error) {
586
- console.error("Error parsing metadata:");
587
- console.error(error);
588
- return;
589
- }
590
- } else if(existingMezzId) {
591
- const libraryId = await client.ContentObjectLibraryId({objectId: existingMezzId});
592
- const assetMetadata = (await client.ContentObjectMetadata({
593
- libraryId,
594
- objectId: existingMezzId,
595
- metadataSubtree: "public/asset_metadata"
596
- })) || {};
597
-
598
- const existingName = (await client.ContentObjectMetadata({
599
- libraryId,
600
- objectId: existingMezzId,
601
- metadataSubtree: "public/name"
602
- })) || {};
603
-
604
- metadata = {
605
- public: {
606
- asset_metadata: assetMetadata || {},
607
- name: name || existingName || ""
608
- }
609
- };
610
-
611
- if(!title && !metadata.public.asset_metadata.title) {
612
- throw Error("Existing mez does not have 'title' set and title argument was not provided");
613
- }
614
- } else {
615
- metadata = {public: {asset_metadata: {}}};
616
- }
617
-
618
- if(abrProfile) {
619
- abrProfile = JSON.parse(fs.readFileSync(abrProfile));
620
- }
621
-
622
- if(addlOfferingSpecs) {
623
- try {
624
- if(addlOfferingSpecs.startsWith("@")) {
625
- addlOfferingSpecs = fs.readFileSync(addlOfferingSpecs.substring(1));
626
- }
627
-
628
- addlOfferingSpecs = JSON.parse(addlOfferingSpecs) || undefined;
629
- } catch(error) {
630
- console.error("Error parsing addlOfferingSpecs:");
631
- console.error(error);
632
- return;
633
- }
634
- }
635
-
636
- metadata.public.asset_metadata = {
637
- title,
638
- display_title: displayTitle || title,
639
- slug: slug || Slugify(displayTitle || title),
640
- ip_title_id: ipTitleId || slug || Slugify(displayTitle || title),
641
- title_type: titleType,
642
- asset_type: assetType,
643
- ...(metadata.public.asset_metadata || {})
644
- };
645
-
646
- name = name || metadata.public.name || metadata.public.asset_metadata.title + " MEZ";
647
-
648
- let access;
649
- if(credentials) {
650
- access = JSON.parse(fs.readFileSync(credentials));
651
- } else {
652
- access = [
653
- {
654
- path_matchers: [".*"],
655
- remote_access: {
656
- protocol: "s3",
657
- platform: "aws",
658
- path: process.env.AWS_BUCKET + "/",
659
- storage_endpoint: {
660
- region: process.env.AWS_REGION
661
- },
662
- cloud_credentials: {
663
- access_key_id: process.env.AWS_KEY,
664
- secret_access_key: process.env.AWS_SECRET
665
- }
666
- }
667
- }
668
- ];
669
- }
670
-
671
- const originalType = type;
672
- if(type.startsWith("iq__")) {
673
- type = await client.ContentType({typeId: type});
674
- } else if(type.startsWith("hq__")) {
675
- type = await client.ContentType({versionHash: type});
676
- } else {
677
- type = await client.ContentType({name: type});
678
- }
679
-
680
- if(!type) {
681
- throw Error(`Unable to find content type "${originalType}"`);
682
- }
683
-
684
- type = type.hash;
685
-
686
- console.log("\nCreating ABR Mezzanine...");
687
- const createResponse = await client.CreateABRMezzanine({
688
- name,
689
- libraryId: library,
690
- objectId: existingMezzId,
691
- type,
692
- masterVersionHash: masterHash,
693
- variant,
694
- offeringKey: offeringKey,
695
- metadata,
696
- addlOfferingSpecs,
697
- abrProfile,
698
- keepOtherStreams,
699
- streamKeys
700
- });
701
-
702
- Report(createResponse);
703
-
704
- const objectId = createResponse.id;
705
-
706
- console.log("Starting Mezzanine Job(s)");
707
-
708
- const startResponse = await client.StartABRMezzanineJobs({
709
- libraryId: library,
710
- objectId,
711
- offeringKey,
712
- access
713
- });
714
-
715
- Report(startResponse);
716
-
717
- console.log("\nLibrary ID", library);
718
- console.log("Object ID", objectId);
719
- console.log("Offering:", offeringKey);
720
- console.log("Write Token:", startResponse.lro_draft.write_token);
721
- console.log("Write Node:", startResponse.lro_draft.node, "\n");
722
-
723
- if(!wait) {
724
- return;
725
- }
726
-
727
- console.log("Progress:");
728
-
729
- // eslint-disable-next-line no-constant-condition
730
- while(true) {
731
- const status = await client.LROStatus({libraryId: library, objectId, offeringKey});
732
-
733
- let done = true;
734
- const progress = Object.keys(status).map(id => {
735
- const info = status[id];
736
-
737
- if(!info.end) {
738
- done = false;
739
- }
740
-
741
- if(done && info.run_state !== "finished") {
742
- throw Error(`LRO ${id} failed with status ${info.run_state}`);
743
- }
744
-
745
- return `${id}: ${parseFloat(info.progress.percentage || 0).toFixed(1)}%`;
746
- });
747
-
748
- readline.clearLine(process.stdout, 0);
749
- readline.cursorTo(process.stdout, 0, null);
750
- process.stdout.write(progress.join(" "));
751
-
752
- if(done) {
753
- break;
754
- }
755
-
756
- await new Promise(resolve => setTimeout(resolve, 10000));
757
- }
758
-
759
- const finalizeResponse = await client.FinalizeABRMezzanine({
760
- libraryId: library,
761
- objectId,
762
- offeringKey: offeringKey,
763
- preFinalizeThrow: true,
764
- preFinalizeFn // Before object is finalized, try to set codec descriptors
765
- });
766
-
767
- Report(finalizeResponse);
768
-
769
- console.log("\n\nABR mezzanine object created:");
770
- console.log("\tObject ID:", objectId);
771
- console.log("\tVersion Hash:", finalizeResponse.hash, "\n");
772
- } catch(error) {
773
- console.error("Error creating mezzanine:");
774
- console.error(error.body ? JSON.stringify(error, null, 2) : error);
775
- }
776
- };
777
-
778
-
779
- Create(argv);