@eluvio/elv-client-js 3.1.91 → 3.1.94
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 +7 -7
- package/dist/ElvClient-node-min.js +12 -12
- package/dist/ElvFrameClient-min.js +6 -6
- package/dist/ElvPermissionsClient-min.js +5 -5
- package/dist/src/AuthorizationClient.js +2 -2
- package/dist/src/HttpClient.js +2 -2
- package/dist/src/UserProfileClient.js +31 -18
- package/dist/src/Utils.js +173 -1
- package/dist/src/client/ContentAccess.js +67 -50
- package/dist/src/client/ContentManagement.js +20 -12
- package/dist/src/client/NFT.js +23 -68
- package/package-lock.json +15239 -910
- package/package.json +2 -1
- package/src/HttpClient.js +2 -2
- package/src/Utils.js +119 -0
- package/src/client/ABRPublishing.js +2 -1
- package/src/client/NFT.js +14 -49
- package/testScripts/VariantABRProfile.js +45 -0
- package/utilities/SimpleIngest.js +245 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eluvio/elv-client-js",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.94",
|
|
4
4
|
"description": "Javascript client for the Eluvio Content Fabric",
|
|
5
5
|
"main": "src/ElvClient.js",
|
|
6
6
|
"author": "Kevin Talmadge",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@babel/runtime": "^7.8.4",
|
|
59
59
|
"@eluvio/crypto": ">=1.0.8",
|
|
60
|
+
"@eluvio/elv-abr-profile": "^0.2.0",
|
|
60
61
|
"@sindresorhus/slugify": "^1.1.0",
|
|
61
62
|
"babel-loader": "^8.0.6",
|
|
62
63
|
"bignumber.js": "^8.0.2",
|
package/src/HttpClient.js
CHANGED
|
@@ -77,10 +77,10 @@ class HttpClient {
|
|
|
77
77
|
headers: this.RequestHeaders(bodyType, headers)
|
|
78
78
|
};
|
|
79
79
|
|
|
80
|
-
if(method === "POST" || method === "PUT") {
|
|
80
|
+
if(method === "POST" || method === "PUT" || method === "DELETE") {
|
|
81
81
|
if(body && bodyType === "JSON") {
|
|
82
82
|
fetchParameters.body = JSON.stringify(body);
|
|
83
|
-
} else {
|
|
83
|
+
} else if(body) {
|
|
84
84
|
fetchParameters.body = body;
|
|
85
85
|
}
|
|
86
86
|
}
|
package/src/Utils.js
CHANGED
|
@@ -150,6 +150,125 @@ const Utils = {
|
|
|
150
150
|
};
|
|
151
151
|
},
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Decode the specified write token into its component parts
|
|
155
|
+
*
|
|
156
|
+
* @param writeToken
|
|
157
|
+
*
|
|
158
|
+
* @returns {Object} - Components of the write token.
|
|
159
|
+
*/
|
|
160
|
+
DecodeWriteToken: (writeToken) => {
|
|
161
|
+
/*
|
|
162
|
+
Format:
|
|
163
|
+
- content write token, LRO:
|
|
164
|
+
- prefix: "tq__", "tqw__", "tlro"
|
|
165
|
+
- format:
|
|
166
|
+
prefix + base58(uvarint(len(QID) | QID |
|
|
167
|
+
uvarint(len(NID) | NID |
|
|
168
|
+
uvarint(len(RAND_BYTES) | RAND_BYTES)
|
|
169
|
+
- content part write token:
|
|
170
|
+
- prefix: "tqp_"
|
|
171
|
+
- format:
|
|
172
|
+
prefix + base58(scheme | flags | uvarint(len(RAND_BYTES) | RAND_BYTES)
|
|
173
|
+
- content write token v1, content part write token v1:
|
|
174
|
+
- prefix: "tqw_", "tqpw"
|
|
175
|
+
- format:
|
|
176
|
+
prefix + base58(RAND_BYTES)
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
if(writeToken.length<4){
|
|
180
|
+
throw new Error(`Invalid write token: ["${writeToken}"] (unknown prefix)`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let tokenType;
|
|
184
|
+
|
|
185
|
+
if(writeToken.startsWith("tqw__")) {
|
|
186
|
+
tokenType = "tq__";
|
|
187
|
+
writeToken = writeToken.slice(5);
|
|
188
|
+
} else {
|
|
189
|
+
tokenType = writeToken.slice(0, 4);
|
|
190
|
+
writeToken = writeToken.slice(4);
|
|
191
|
+
}
|
|
192
|
+
if(writeToken.length===0){
|
|
193
|
+
throw new Error(`Invalid write token: ["${writeToken}"] (too short)`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
switch(tokenType) {
|
|
197
|
+
case "tqw_":
|
|
198
|
+
case "tq__":
|
|
199
|
+
case "tqpw":
|
|
200
|
+
case "tqp_":
|
|
201
|
+
case "tlro":
|
|
202
|
+
break;
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`Invalid write token: ["${writeToken}"] (unknown prefix)`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// decode base58 payload
|
|
208
|
+
let bytes = Utils.FromB58(writeToken);
|
|
209
|
+
|
|
210
|
+
function decodeBytes(isID, prefix) {
|
|
211
|
+
let bsize = VarInt.decode(bytes,0); // decode: count of bytes to read
|
|
212
|
+
let offset = VarInt.decode.bytes; // offset in buffer to start read after decode
|
|
213
|
+
let theBytes;
|
|
214
|
+
let ret;
|
|
215
|
+
|
|
216
|
+
if(isID) {
|
|
217
|
+
theBytes = bytes.slice(offset+1, bsize+offset); // skip 1st byte (code id) at offset 0
|
|
218
|
+
if(theBytes.length===0){
|
|
219
|
+
ret = "";
|
|
220
|
+
} else {
|
|
221
|
+
ret = prefix + Utils.B58(theBytes);
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
theBytes = bytes.slice(offset, bsize+offset);
|
|
225
|
+
ret = "0x" + theBytes.toString("hex");
|
|
226
|
+
}
|
|
227
|
+
bytes = bytes.slice(bsize+offset);
|
|
228
|
+
return ret;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let tokenId;
|
|
232
|
+
let qid;
|
|
233
|
+
let nid;
|
|
234
|
+
let scheme;
|
|
235
|
+
let flags;
|
|
236
|
+
|
|
237
|
+
switch(tokenType) {
|
|
238
|
+
case "tqw_": // content write token v1
|
|
239
|
+
case "tqpw": // content part write token v1
|
|
240
|
+
tokenId = "0x" + bytes.toString("hex");
|
|
241
|
+
break;
|
|
242
|
+
case "tlro": // LRO,
|
|
243
|
+
case "tq__": // content write token
|
|
244
|
+
qid = decodeBytes(true, "iq__");
|
|
245
|
+
nid = decodeBytes(true, "inod");
|
|
246
|
+
tokenId = decodeBytes(false, "");
|
|
247
|
+
break;
|
|
248
|
+
case "tqp_": // content part write token
|
|
249
|
+
if(bytes.length<3) {
|
|
250
|
+
throw new Error(`Invalid write token: ["${writeToken}"] (token truncated)`);
|
|
251
|
+
}
|
|
252
|
+
scheme=bytes[0];
|
|
253
|
+
flags=bytes[1];
|
|
254
|
+
bytes = bytes.slice(2);
|
|
255
|
+
tokenId = decodeBytes(false, "");
|
|
256
|
+
break;
|
|
257
|
+
default:
|
|
258
|
+
// already raised
|
|
259
|
+
throw new Error(`Invalid write token: ["${writeToken}"] (unknown prefix)`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
tokenType: tokenType, // type of token
|
|
264
|
+
tokenId: tokenId, // random bytes generated by the fabric node
|
|
265
|
+
objectId: qid, // content id for content write token (tq__) or LRO (tlro)
|
|
266
|
+
nodeId: nid, // node id where the content write token is valid (tq__)
|
|
267
|
+
scheme, // encryption scheme for part write token - (tqp_)
|
|
268
|
+
flags // flags for part write token (tqp_)
|
|
269
|
+
};
|
|
270
|
+
},
|
|
271
|
+
|
|
153
272
|
/**
|
|
154
273
|
* Convert contract address to multiformat hash
|
|
155
274
|
*
|
|
@@ -478,7 +478,7 @@ exports.StartABRMezzanineJobs = async function({
|
|
|
478
478
|
metadata: lroInfo
|
|
479
479
|
});
|
|
480
480
|
|
|
481
|
-
await this.FinalizeContentObject({
|
|
481
|
+
const finalizeResponse = await this.FinalizeContentObject({
|
|
482
482
|
libraryId,
|
|
483
483
|
objectId,
|
|
484
484
|
writeToken: statusDraft.write_token,
|
|
@@ -500,6 +500,7 @@ exports.StartABRMezzanineJobs = async function({
|
|
|
500
500
|
});
|
|
501
501
|
|
|
502
502
|
return {
|
|
503
|
+
hash: finalizeResponse.hash,
|
|
503
504
|
lro_draft: lroInfo,
|
|
504
505
|
writeToken: processingDraft.write_token,
|
|
505
506
|
data,
|
package/src/client/NFT.js
CHANGED
|
@@ -18,9 +18,8 @@ const {
|
|
|
18
18
|
* @methodGroup Minting
|
|
19
19
|
* @namedParams
|
|
20
20
|
* @param {string} tenantId - The ID of the tenant
|
|
21
|
-
* @param {string=} email - The email of the NFT recipient
|
|
22
21
|
* @param {string=} address - The address of the NFT recipient
|
|
23
|
-
* @param {string}
|
|
22
|
+
* @param {string} marketplaceId - The ID of the marketplace containing the NFT
|
|
24
23
|
* @param {Array<Object>} items - List of items
|
|
25
24
|
* @param {string} items.sku - SKU of the NFT
|
|
26
25
|
* @param {number=} items.quantity=1 - Number to mint
|
|
@@ -30,66 +29,32 @@ const {
|
|
|
30
29
|
*
|
|
31
30
|
* @return Promise<Object> - An object containing the address for whom the NFT was minted and the transactionId of the minting request.
|
|
32
31
|
*/
|
|
33
|
-
exports.MintNFT = async function({tenantId,
|
|
32
|
+
exports.MintNFT = async function({tenantId, address, marketplaceId, items, extraData={}}) {
|
|
34
33
|
ValidatePresence("tenantId", tenantId);
|
|
35
|
-
ValidatePresence("
|
|
36
|
-
ValidatePresence("
|
|
34
|
+
ValidatePresence("address", address);
|
|
35
|
+
ValidatePresence("marketplaceId", marketplaceId);
|
|
37
36
|
ValidatePresence("items", items);
|
|
38
37
|
|
|
39
|
-
ValidateObject(
|
|
40
|
-
|
|
41
|
-
// If address not specified, make call to initialize address for email
|
|
42
|
-
let accountInitializationBody = { ts: Date.now() };
|
|
43
|
-
if(email) {
|
|
44
|
-
accountInitializationBody.email = email;
|
|
45
|
-
} else {
|
|
46
|
-
accountInitializationBody.addr = address;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const accountInitializationSignature = await this.Sign(
|
|
50
|
-
JSON.stringify(accountInitializationBody)
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const {addr} = await this.utils.ResponseToJson(
|
|
54
|
-
await this.authClient.MakeAuthServiceRequest({
|
|
55
|
-
method: "POST",
|
|
56
|
-
path: `/as/tnt/prov/eth/${tenantId}`,
|
|
57
|
-
body: accountInitializationBody,
|
|
58
|
-
headers: {
|
|
59
|
-
"Authorization": `Bearer ${accountInitializationSignature}`
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
address = this.utils.FormatAddress(addr);
|
|
38
|
+
ValidateObject(marketplaceId);
|
|
39
|
+
ValidateAddress(address);
|
|
65
40
|
|
|
66
41
|
let requestBody = {
|
|
67
|
-
|
|
68
|
-
|
|
42
|
+
tickets: null,
|
|
43
|
+
products: items.map(item => ({
|
|
69
44
|
sku: item.sku,
|
|
70
45
|
quant: item.quantity || 1,
|
|
71
46
|
extra: item.tokenId ?
|
|
72
47
|
{ ...(item.extraData || {}), token_id: item.tokenId } :
|
|
73
48
|
{ ...(item.extraData || {}) }
|
|
74
49
|
})),
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
...extraData
|
|
50
|
+
ident: address,
|
|
51
|
+
cust_name: address,
|
|
52
|
+
extra: {
|
|
53
|
+
...extraData,
|
|
54
|
+
elv_addr: address
|
|
79
55
|
}
|
|
80
56
|
};
|
|
81
57
|
|
|
82
|
-
|
|
83
|
-
ValidateAddress(address);
|
|
84
|
-
|
|
85
|
-
if(email) {
|
|
86
|
-
requestBody.email = email;
|
|
87
|
-
} else {
|
|
88
|
-
requestBody.addr = address;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
requestBody.extra.elv_addr = address;
|
|
92
|
-
|
|
93
58
|
const transactionId = this.utils.B58(UUID.parse(UUID.v4()));
|
|
94
59
|
requestBody.ts = Date.now();
|
|
95
60
|
requestBody.trans_id = transactionId;
|
|
@@ -100,7 +65,7 @@ exports.MintNFT = async function({tenantId, email, address, collectionId, items,
|
|
|
100
65
|
|
|
101
66
|
await this.authClient.MakeAuthServiceRequest({
|
|
102
67
|
method: "POST",
|
|
103
|
-
path:
|
|
68
|
+
path: UrlJoin("/as/tnt/trans/base", tenantId, marketplaceId),
|
|
104
69
|
body: requestBody,
|
|
105
70
|
headers: {
|
|
106
71
|
"Authorization": `Bearer ${mintSignature}`
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
const ScriptVariant = require("./parentClasses/ScriptVariant");
|
|
5
|
+
const ABR = require("@eluvio/elv-abr-profile");
|
|
6
|
+
|
|
7
|
+
class VariantABRProfile extends ScriptVariant {
|
|
8
|
+
|
|
9
|
+
async body() {
|
|
10
|
+
const client = await this.client();
|
|
11
|
+
|
|
12
|
+
const libraryId = this.args.libraryId;
|
|
13
|
+
const objectId = this.args.objectId;
|
|
14
|
+
|
|
15
|
+
// get media info from production master
|
|
16
|
+
const masterMetadata = await client.ContentObjectMetadata({
|
|
17
|
+
libraryId,
|
|
18
|
+
objectId,
|
|
19
|
+
metadataSubtree: "/production_master"
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// adapt ABR Profile to production master's video properties
|
|
23
|
+
const generatedProfile = ABR.ABRProfileForVariant(
|
|
24
|
+
masterMetadata.sources,
|
|
25
|
+
masterMetadata.variants.default
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
if(!generatedProfile.ok) {
|
|
29
|
+
console.error("Error generating ABR Profile:\n" + generatedProfile.errors.join("\n"));
|
|
30
|
+
} else {
|
|
31
|
+
console.log(JSON.stringify(generatedProfile.result, null, 2));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
header() {
|
|
36
|
+
return `Generate ABR Profile for production master ${this.args.objectId}, default variant`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
options() {
|
|
40
|
+
return super.options();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const script = new VariantABRProfile;
|
|
45
|
+
script.run();
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// Create new production master from specified file(s)
|
|
2
|
+
const R = require("ramda");
|
|
3
|
+
|
|
4
|
+
const {ModOpt, NewOpt} = require("./lib/options");
|
|
5
|
+
const Utility = require("./lib/Utility");
|
|
6
|
+
|
|
7
|
+
const ABR = require("@eluvio/elv-abr-profile");
|
|
8
|
+
|
|
9
|
+
const Client = require("./lib/concerns/Client");
|
|
10
|
+
const Finalize = require("./lib/concerns/Finalize");
|
|
11
|
+
const LocalFile = require("./lib/concerns/LocalFile");
|
|
12
|
+
const LRO = require("./lib/concerns/LRO");
|
|
13
|
+
const ArgLibraryId = require("./lib/concerns/ArgLibraryId");
|
|
14
|
+
const {seconds} = require("./lib/helpers");
|
|
15
|
+
|
|
16
|
+
class SimpleIngest extends Utility {
|
|
17
|
+
blueprint() {
|
|
18
|
+
return {
|
|
19
|
+
concerns: [Client, Finalize, LocalFile, ArgLibraryId, LRO],
|
|
20
|
+
options: [
|
|
21
|
+
ModOpt("libraryId", {demand: true, forX: "new media object"}),
|
|
22
|
+
NewOpt("title", {
|
|
23
|
+
demand: true,
|
|
24
|
+
descTemplate: "Title for new media object",
|
|
25
|
+
type: "string"
|
|
26
|
+
}),
|
|
27
|
+
NewOpt("drm", {
|
|
28
|
+
default: false,
|
|
29
|
+
descTemplate: "Use DRM for playback",
|
|
30
|
+
type: "boolean"
|
|
31
|
+
}),
|
|
32
|
+
ModOpt("files", {forX: "for new media object"})
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async body() {
|
|
38
|
+
const logger = this.logger;
|
|
39
|
+
|
|
40
|
+
let fileHandles = [];
|
|
41
|
+
const fileInfo = this.concerns.LocalFile.fileInfo(fileHandles);
|
|
42
|
+
|
|
43
|
+
// delay getting elvClient until this point so script exits faster
|
|
44
|
+
// if there is a validation error above
|
|
45
|
+
const client = await this.concerns.Client.get();
|
|
46
|
+
|
|
47
|
+
// get metadata from Library
|
|
48
|
+
const libInfo = await this.concerns.ArgLibraryId.libInfo();
|
|
49
|
+
|
|
50
|
+
const type = R.path(["metadata", "abr", "mez_content_type"], libInfo);
|
|
51
|
+
if(R.isNil(type)) throw Error("Library does not specify content type for simple ingests");
|
|
52
|
+
|
|
53
|
+
const libABRProfile = R.path(["metadata", "abr", "default_profile"], libInfo);
|
|
54
|
+
if(R.isNil(libABRProfile)) throw Error("Library does not specify ABR profile for simple ingests");
|
|
55
|
+
|
|
56
|
+
const {drm, libraryId, title} = this.args;
|
|
57
|
+
const encrypt = true;
|
|
58
|
+
|
|
59
|
+
logger.log("Uploading files...");
|
|
60
|
+
|
|
61
|
+
const createMasterResponse = await client.CreateProductionMaster({
|
|
62
|
+
libraryId,
|
|
63
|
+
type,
|
|
64
|
+
name: title,
|
|
65
|
+
description: `Media object created via simple ingest: ${title}`,
|
|
66
|
+
fileInfo,
|
|
67
|
+
encrypt,
|
|
68
|
+
copy: true,
|
|
69
|
+
callback: this.concerns.LocalFile.callback
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const {id, hash} = createMasterResponse;
|
|
73
|
+
// Log object id immediately, in case of error later in script
|
|
74
|
+
// Don't log hash yet, it will change if --streams was provided (or any other revision to object is needed)
|
|
75
|
+
logger.data("object_id", id);
|
|
76
|
+
|
|
77
|
+
// Close file handles (if any)
|
|
78
|
+
this.concerns.LocalFile.closeFileHandles(fileHandles);
|
|
79
|
+
|
|
80
|
+
logger.errorsAndWarnings(createMasterResponse);
|
|
81
|
+
|
|
82
|
+
logger.logList(
|
|
83
|
+
"",
|
|
84
|
+
"Production master default variant created:",
|
|
85
|
+
` Object ID: ${id}`,
|
|
86
|
+
` Version Hash: ${hash}`,
|
|
87
|
+
""
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
logger.data("version_hash", hash);
|
|
91
|
+
|
|
92
|
+
if(!R.isNil(createMasterResponse.errors) && !R.isEmpty(createMasterResponse.errors)) throw Error(`Error(s) encountered while inspecting uploaded files: ${createMasterResponse.errors.join("\n")}`);
|
|
93
|
+
|
|
94
|
+
await seconds(2);
|
|
95
|
+
|
|
96
|
+
await this.concerns.Finalize.waitForPublish({
|
|
97
|
+
latestHash: hash,
|
|
98
|
+
libraryId,
|
|
99
|
+
objectId: id
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
// get production master metadata
|
|
104
|
+
const masterMetadata = (await client.ContentObjectMetadata({
|
|
105
|
+
libraryId,
|
|
106
|
+
objectId: id,
|
|
107
|
+
versionHash: hash,
|
|
108
|
+
metadataSubtree: "/production_master"
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
const sources = R.prop("sources", masterMetadata);
|
|
112
|
+
const variant = R.path(["variants", "default"], masterMetadata);
|
|
113
|
+
|
|
114
|
+
// add info on source files and variant to data if --json selected
|
|
115
|
+
if(this.args.json) {
|
|
116
|
+
logger.data("media_files", sources);
|
|
117
|
+
logger.data("variant_default", variant);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// generate ABR profile
|
|
121
|
+
const genProfileRetVal = ABR.ABRProfileForVariant(sources, variant, libABRProfile);
|
|
122
|
+
if(!genProfileRetVal.ok) throw Error(`Error(s) encountered while generating ABR profile: ${genProfileRetVal.errors.join("\n")}`);
|
|
123
|
+
|
|
124
|
+
// filter DRM/clear as needed
|
|
125
|
+
const filterProfileRetVal = drm ?
|
|
126
|
+
ABR.ProfileExcludeClear(genProfileRetVal.result) :
|
|
127
|
+
ABR.ProfileExcludeDRM(genProfileRetVal.result);
|
|
128
|
+
if(!filterProfileRetVal.ok) throw Error(`Error(s) encountered while setting playout formats: ${filterProfileRetVal.errors.join("\n")}`);
|
|
129
|
+
|
|
130
|
+
// set up mezzanine offering
|
|
131
|
+
logger.log("Setting up media file conversion...");
|
|
132
|
+
const createMezResponse = await client.CreateABRMezzanine({
|
|
133
|
+
name: title,
|
|
134
|
+
libraryId,
|
|
135
|
+
objectId: id,
|
|
136
|
+
type,
|
|
137
|
+
masterVersionHash: hash,
|
|
138
|
+
variant: "default",
|
|
139
|
+
offeringKey: "default",
|
|
140
|
+
abrProfile: filterProfileRetVal.result
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
logger.errorsAndWarnings(createMezResponse);
|
|
144
|
+
const createMezErrors = createMezResponse.errors;
|
|
145
|
+
if(!R.isNil(createMezErrors) && !R.isEmpty(createMezErrors)) throw Error(`Error(s) encountered while setting up media file conversion: ${createMezErrors.join("\n")}`);
|
|
146
|
+
|
|
147
|
+
await this.concerns.Finalize.waitForPublish({
|
|
148
|
+
latestHash: createMezResponse.hash,
|
|
149
|
+
libraryId,
|
|
150
|
+
objectId: id
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
logger.log("Starting conversion to streaming format...");
|
|
155
|
+
|
|
156
|
+
const startJobsResponse = await client.StartABRMezzanineJobs({
|
|
157
|
+
libraryId,
|
|
158
|
+
objectId: id,
|
|
159
|
+
offeringKey: "default"
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
logger.errorsAndWarnings(startJobsResponse);
|
|
163
|
+
const startJobsErrors = createMezResponse.errors;
|
|
164
|
+
if(!R.isNil(startJobsErrors) && !R.isEmpty(startJobsErrors)) throw Error(`Error(s) encountered while starting file conversion: ${startJobsErrors.join("\n")}`);
|
|
165
|
+
|
|
166
|
+
const lroWriteToken = R.path(["lro_draft", "write_token"], startJobsResponse);
|
|
167
|
+
const lroNode = R.path(["lro_draft", "node"], startJobsResponse);
|
|
168
|
+
|
|
169
|
+
logger.data("library_id", libraryId);
|
|
170
|
+
logger.data("object_id", id);
|
|
171
|
+
logger.data("offering_key", "default");
|
|
172
|
+
logger.data("write_token", lroWriteToken);
|
|
173
|
+
logger.data("write_node", lroNode);
|
|
174
|
+
|
|
175
|
+
logger.logList(
|
|
176
|
+
"",
|
|
177
|
+
`Library ID: ${libraryId}`,
|
|
178
|
+
`Object ID: ${id}`,
|
|
179
|
+
"Offering: default",
|
|
180
|
+
`Write Token: ${lroWriteToken}`,
|
|
181
|
+
`Write Node: ${lroNode}`,
|
|
182
|
+
""
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
// wait for latest version hash to become visible (if publish not finished, then checking progress can fail
|
|
186
|
+
// as metadata /lro_draft_default will not be found)
|
|
187
|
+
|
|
188
|
+
await this.concerns.Finalize.waitForPublish({
|
|
189
|
+
latestHash: startJobsResponse.hash,
|
|
190
|
+
libraryId,
|
|
191
|
+
objectId: id
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
logger.log("Progress:");
|
|
195
|
+
|
|
196
|
+
const lro = this.concerns.LRO;
|
|
197
|
+
let done = false;
|
|
198
|
+
let lastStatus;
|
|
199
|
+
while(!done) {
|
|
200
|
+
const statusMap = await lro.status({libraryId, objectId: id}); // TODO: check how offering key is used, if at all
|
|
201
|
+
const statusSummary = lro.statusSummary(statusMap);
|
|
202
|
+
lastStatus = statusSummary.run_state;
|
|
203
|
+
if(lastStatus !== LRO.STATE_RUNNING) done = true;
|
|
204
|
+
logger.log(`run_state: ${lastStatus}`);
|
|
205
|
+
const eta = statusSummary.estimated_time_left_h_m_s;
|
|
206
|
+
if(eta) logger.log(`estimated time left: ${eta}`);
|
|
207
|
+
await seconds(15);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const finalizeAbrResponse = await client.FinalizeABRMezzanine({
|
|
211
|
+
libraryId,
|
|
212
|
+
objectId: id,
|
|
213
|
+
offeringKey: "default"
|
|
214
|
+
});
|
|
215
|
+
const latestHash = finalizeAbrResponse.hash;
|
|
216
|
+
|
|
217
|
+
logger.errorsAndWarnings(finalizeAbrResponse);
|
|
218
|
+
const finalizeErrors = finalizeAbrResponse.errors;
|
|
219
|
+
if(!R.isNil(finalizeErrors) && !R.isEmpty(finalizeErrors)) throw Error(`Error(s) encountered while finalizing object: ${finalizeErrors.join("\n")}`);
|
|
220
|
+
|
|
221
|
+
logger.logList(
|
|
222
|
+
"",
|
|
223
|
+
"Playable media object created:",
|
|
224
|
+
` Object ID: ${id}`,
|
|
225
|
+
` Version Hash: ${latestHash}`,
|
|
226
|
+
""
|
|
227
|
+
);
|
|
228
|
+
logger.data("version_hash", latestHash);
|
|
229
|
+
await this.concerns.Finalize.waitForPublish({
|
|
230
|
+
latestHash,
|
|
231
|
+
libraryId,
|
|
232
|
+
objectId: id
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
header() {
|
|
237
|
+
return "Create playable media object via simple ingest";
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if(require.main === module) {
|
|
242
|
+
Utility.cmdLineInvoke(SimpleIngest);
|
|
243
|
+
} else {
|
|
244
|
+
module.exports = SimpleIngest;
|
|
245
|
+
}
|