@eluvio/elv-client-js 4.0.134 → 4.0.136

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 (52) hide show
  1. package/dist/ElvClient-min.js +15 -14
  2. package/dist/ElvClient-node-min.js +14 -13
  3. package/dist/ElvFrameClient-min.js +10 -10
  4. package/dist/ElvPermissionsClient-min.js +9 -9
  5. package/dist/ElvWalletClient-min.js +15 -14
  6. package/dist/ElvWalletClient-node-min.js +14 -13
  7. package/dist/src/AuthorizationClient.js +9 -12
  8. package/dist/src/ContentObjectAudit.js +3 -3
  9. package/dist/src/ContentObjectVerification.js +3 -3
  10. package/dist/src/Crypto.js +2 -2
  11. package/dist/src/ElvClient.js +522 -397
  12. package/dist/src/ElvWallet.js +7 -5
  13. package/dist/src/EthClient.js +8 -9
  14. package/dist/src/FrameClient.js +9 -10
  15. package/dist/src/HttpClient.js +5 -5
  16. package/dist/src/Id.js +1 -2
  17. package/dist/src/PermissionsClient.js +31 -19
  18. package/dist/src/RemoteSigner.js +10 -11
  19. package/dist/src/UserProfileClient.js +35 -20
  20. package/dist/src/Utils.js +2 -3
  21. package/dist/src/client/ABRPublishing.js +342 -196
  22. package/dist/src/client/AccessGroups.js +2 -2
  23. package/dist/src/client/ContentAccess.js +8 -12
  24. package/dist/src/client/ContentManagement.js +99 -83
  25. package/dist/src/client/Contracts.js +2 -2
  26. package/dist/src/client/Files.js +2 -2
  27. package/dist/src/client/LiveConf.js +43 -26
  28. package/dist/src/client/LiveStream.js +65 -63
  29. package/dist/src/client/NFT.js +2 -2
  30. package/dist/src/client/Shares.js +47 -24
  31. package/dist/src/walletClient/ClientMethods.js +2 -2
  32. package/dist/src/walletClient/Profile.js +2 -2
  33. package/dist/src/walletClient/Utils.js +2 -2
  34. package/dist/src/walletClient/index.js +65 -50
  35. package/package.json +2 -2
  36. package/src/ElvClient.js +67 -3
  37. package/src/FrameClient.js +2 -1
  38. package/src/client/ABRPublishing.js +215 -83
  39. package/src/client/ContentManagement.js +7 -6
  40. package/src/client/LiveConf.js +13 -9
  41. package/src/client/LiveStream.js +8 -3
  42. package/src/walletClient/index.js +1 -1
  43. package/utilities/FrontEndSimpleIngest.js +198 -0
  44. package/utilities/ProductionMasterCreate.js +9 -2
  45. package/utilities/SampleIngest.js +225 -0
  46. package/utilities/SampleIngestWithMaster.js +226 -0
  47. package/utilities/lib/concerns/ArgLibraryId.js +1 -1
  48. package/utilities/lib/concerns/ArgTenant.js +23 -0
  49. package/utilities/lib/concerns/ContentType.js +1 -1
  50. package/utilities/lib/concerns/Finalize.js +12 -7
  51. package/utilities/lib/concerns/LRO.js +3 -3
  52. package/utilities/lib/concerns/Tenant.js +47 -0
@@ -510,7 +510,7 @@ class ElvWalletClient {
510
510
 
511
511
  let fabricToken, expiresAt;
512
512
  if(createRemoteToken && this.client.signer.remoteSigner) {
513
- expiresAt = Date.now() + 24 * 60 * 60 * 1000;
513
+ expiresAt = Date.now() + tokenDuration * 60 * 60 * 1000;
514
514
  const tokenResponse = await this.client.signer.RetrieveCSAT({email, nonce, tenantId, force, duration: tokenDuration});
515
515
  fabricToken = tokenResponse.token;
516
516
  nonce = tokenResponse.nonce;
@@ -0,0 +1,198 @@
1
+ const { ElvClient } = require("../../src/ElvClient");
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+
6
+ // Simple Media Ingest
7
+ // This script allows for the upload of a single media file from a Front End client with an authorization token
8
+ // It creates a single playable object for each media file uploaded
9
+
10
+
11
+
12
+ const MediaUpload = async () => {
13
+
14
+ //
15
+ // BACK END
16
+ //
17
+
18
+ let backendClient = await ElvClient.FromNetworkName({networkName: "demov3"});
19
+ let wallet = backendClient.GenerateWallet();
20
+ let backendSigner = wallet.AddAccount({
21
+ privateKey: process.env.PRIVATE_KEY
22
+ });
23
+ backendClient.SetSigner({signer: backendSigner});
24
+ // Send these 3 items to the front end: writeToken, authToken, node
25
+
26
+
27
+
28
+ // Constants from tenancy
29
+ const libraryId = "ilibxxxx;
30
+ const mezzType = "iq__xxxx";
31
+ const masterType = "iq__xxx";
32
+ const objectName = "Object Name";
33
+ const filePath = path.resolve(__dirname, 'abr_profile.json');
34
+ const abrProfile = JSON.parse(fs.readFileSync(filePath, 'utf8'));
35
+
36
+
37
+
38
+ // Upload by creating a new object
39
+ const newObject = await backendClient.CreateContentObject({
40
+ libraryId,
41
+ options: {
42
+ meta: {
43
+ public: {
44
+ name: objectName,
45
+ }
46
+ },
47
+ type: mezzType
48
+ }
49
+ })
50
+ const objectId = newObject.id;
51
+ const writeToken = newObject.write_token;
52
+
53
+
54
+
55
+
56
+ // Upload to an exisiting object
57
+ // const objectId = "iq__2o68yG4v44LwffBuKetPXGX79K9M"
58
+ // const writeToken = (await backendClient.EditContentObject({libraryId, objectId})).write_token;
59
+
60
+
61
+
62
+
63
+ // Generate auth token
64
+ const authToken = await backendClient.authClient.AuthorizationToken({libraryId, objectId, update: true});
65
+ const node = await backendClient.WriteTokenNodeUrl({writeToken});
66
+ console.log("Send to front end", "writeToken", writeToken, "authToken", authToken, "node", node);
67
+
68
+
69
+
70
+
71
+ //
72
+ // FRONT END
73
+ //
74
+
75
+ let frontendClient = await ElvClient.FromNetworkName({networkName: "demov3"});
76
+ frontendClient.SetNodes({fabricURIs: [node]});
77
+ frontendClient.SetStaticToken({token: authToken, update: true});
78
+
79
+ // Upload Files
80
+ const filePaths = [
81
+ "file/path/file_name.mp4",
82
+ ];
83
+ let fileInfo = [];
84
+ for (let i = 0; i < filePaths.length; i ++) {
85
+ const fd = fs.openSync(filePaths[i]);
86
+ const stats = fs.statSync(filePaths[i]);
87
+ fileInfo.push({
88
+ path: `file_name.mp4`,
89
+ type: "file",
90
+ size: stats.size,
91
+ data: fd
92
+ })
93
+ }
94
+
95
+ const callback = (fileUploadStatus) => {
96
+ console.log(fileUploadStatus);
97
+ };
98
+
99
+
100
+
101
+
102
+ //
103
+ // BACK END
104
+ //
105
+
106
+ let backendClient2 = await ElvClient.FromNetworkName({networkName: "demov3"});
107
+ let wallet2 = backendClient.GenerateWallet();
108
+ let backendSigner2 = wallet2.AddAccount({
109
+ privateKey: process.env.PRIVATE_KEY
110
+ });
111
+ backendClient2.SetSigner({signer: backendSigner2});
112
+ backendClient2.SetNodes({fabricURIs: [node]});
113
+
114
+ // For debbuging purposes
115
+ // backendClient2.ToggleLogging(true);
116
+
117
+ try {
118
+
119
+ // Create Production Master
120
+ const createMasterResponse = await backendClient2.CreateProductionMaster({
121
+ libraryId,
122
+ objectId,
123
+ fileInfo,
124
+ callback,
125
+ encrypt: true,
126
+ type: masterType,
127
+ name: objectName,
128
+ writeToken
129
+ })
130
+ console.log("Master Response", createMasterResponse);
131
+
132
+ // Create ABR Mezzanine
133
+ const createABRMezzResponse = await backendClient2.CreateABRMezzanine({
134
+ libraryId,
135
+ writeToken,
136
+ objectId,
137
+ type: mezzType,
138
+ masterWriteToken: writeToken,
139
+ variant: "default",
140
+ offeringKey: "default",
141
+ abrProfile
142
+ });
143
+ console.log("Create ABR Mezzanine", createABRMezzResponse);
144
+
145
+
146
+ // Start ABR Job
147
+ const startJobsResponse = await backendClient2.StartABRMezzanineJobs({
148
+ libraryId,
149
+ objectId,
150
+ offeringKey: "default",
151
+ writeToken
152
+ });
153
+
154
+ const lroWriteToken = startJobsResponse.lro_draft.write_token;
155
+ const lroNode = startJobsResponse.lro_draft.node;
156
+ const lroData = startJobsResponse.data;
157
+
158
+ console.log("LRO Write Token", lroWriteToken);
159
+ console.log("LRO Node", lroNode);
160
+ console.log("LRO Data", lroData);
161
+
162
+
163
+ // Check ABR Job is Finished
164
+ let done = false;
165
+ while (!done) {
166
+ const lroStatus = await backendClient.LROStatus({ libraryId, objectId, writeToken });
167
+ console.log("LRO Status", lroStatus);
168
+ const lastStatus = lroData.every(lro => lroStatus[lro]?.run_state === "finished")
169
+ console.log(lastStatus);
170
+ if (lastStatus) done = true;
171
+ }
172
+
173
+
174
+
175
+
176
+ // Finalize Mezzanine Object
177
+ if (done) {
178
+ let finalizeAbrResponse = await backendClient2.FinalizeABRMezzanine({
179
+ libraryId,
180
+ objectId,
181
+ writeToken,
182
+ offeringKey: "default"
183
+ });
184
+ console.log("Finalize ABR", finalizeAbrResponse);
185
+
186
+ let finalizeContentObject = await backendClient2.FinalizeContentObject({
187
+ libraryId,
188
+ objectId,
189
+ writeToken,
190
+ });
191
+ console.log("Finalize Object", finalizeContentObject);
192
+ }
193
+ } catch(e) {
194
+ console.log("ERROR", e);
195
+ }
196
+ }
197
+
198
+ MediaUpload();
@@ -33,6 +33,11 @@ class ProductionMasterCreate extends Utility {
33
33
  NewOpt("streams", {
34
34
  descTemplate: "JSON string (or file path if prefixed with '@') containing stream specifications for variant in new production master",
35
35
  type: "string"
36
+ }),
37
+ NewOpt("writeToken", {
38
+ demand: false,
39
+ descTemplate: "Write token of the draft",
40
+ type: "string",
36
41
  })
37
42
  ]
38
43
  };
@@ -77,7 +82,7 @@ class ProductionMasterCreate extends Utility {
77
82
  const client = await this.concerns.Client.get();
78
83
 
79
84
  const type = await await this.concerns.ArgType.typVersionHash();
80
- const {libraryId, s3Copy, s3Reference} = this.args;
85
+ const {libraryId, s3Copy, s3Reference, writeToken} = this.args;
81
86
 
82
87
 
83
88
  const createResponse = await client.CreateProductionMaster({
@@ -90,7 +95,8 @@ class ProductionMasterCreate extends Utility {
90
95
  encrypt: !unencrypted,
91
96
  access,
92
97
  copy: s3Copy && !s3Reference,
93
- callback: (access ? this.concerns.CloudFile : this.concerns.LocalFile).callback
98
+ callback: (access ? this.concerns.CloudFile : this.concerns.LocalFile).callback,
99
+ writeToken
94
100
  });
95
101
 
96
102
  const {errors, warnings, id} = createResponse;
@@ -149,6 +155,7 @@ class ProductionMasterCreate extends Utility {
149
155
  libraryId,
150
156
  objectId: id,
151
157
  versionHash: hash,
158
+ writeToken: write_token,
152
159
  metadataSubtree: "/production_master/variants/default/streams"
153
160
  }));
154
161
  if(!streamsFromServer.hasOwnProperty("audio")) {
@@ -0,0 +1,225 @@
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 ArgTenant = require("./lib/concerns/ArgTenant");
15
+ const {seconds} = require("./lib/helpers");
16
+ const AbrProfile = require("./lib/abr_profiles/abr_profile_clear.json");
17
+
18
+ class SampleIngest extends Utility {
19
+ blueprint() {
20
+ return {
21
+ concerns: [Client, Finalize, LocalFile, ArgLibraryId, ArgTenant, LRO],
22
+ options: [
23
+ ModOpt("libraryId", {demand: true, forX: "new media object"}),
24
+ NewOpt("title", {
25
+ demand: true,
26
+ descTemplate: "Title for new media object",
27
+ type: "string"
28
+ }),
29
+ NewOpt("drm", {
30
+ default: false,
31
+ descTemplate: "Use DRM for playback",
32
+ type: "boolean"
33
+ }),
34
+ ModOpt("files", {forX: "for new media object"})
35
+ ]
36
+ };
37
+ }
38
+
39
+ async body() {
40
+ const logger = this.logger;
41
+
42
+ let fileHandles = [];
43
+ const fileInfo = this.concerns.LocalFile.fileInfo(fileHandles);
44
+
45
+ // delay getting elvClient until this point so script exits faster
46
+ // if there is a validation error above
47
+ const client = await this.concerns.Client.get();
48
+
49
+ // get type from Tenant
50
+ const tenantInfo = await this.concerns.ArgTenant.tenantInfo();
51
+
52
+ const type = tenantInfo.typeTitle;
53
+
54
+ if(R.isNil(type)) throw Error("Library does not specify content type for sample ingests");
55
+
56
+ const {drm, libraryId, title} = this.args;
57
+ const encrypt = true;
58
+
59
+ const {id, writeToken} = await client.CreateContentObject({
60
+ libraryId,
61
+ options: type ? { type } : {}
62
+ });
63
+
64
+ logger.log("Uploading files...");
65
+
66
+ const createMasterResponse = await client.CreateProductionMaster({
67
+ libraryId,
68
+ type,
69
+ name: title,
70
+ description: `Media object created via sample ingest: ${title}`,
71
+ fileInfo,
72
+ encrypt,
73
+ copy: true,
74
+ callback: this.concerns.LocalFile.callback,
75
+ writeToken
76
+ });
77
+
78
+ // Log object id immediately, in case of error later in script
79
+ // Don't log hash yet, it will change if --streams was provided (or any other revision to object is needed)
80
+ logger.data("object_id", id);
81
+
82
+ // Close file handles (if any)
83
+ this.concerns.LocalFile.closeFileHandles(fileHandles);
84
+
85
+ logger.errorsAndWarnings(createMasterResponse);
86
+
87
+ logger.logList(
88
+ "",
89
+ "Production master default variant created:",
90
+ ` Object ID: ${id}`,
91
+ ` Write token: ${writeToken}`,
92
+ ""
93
+ );
94
+
95
+ if(!R.isNil(createMasterResponse.errors) && !R.isEmpty(createMasterResponse.errors)) throw Error(`Error(s) encountered while inspecting uploaded files: ${createMasterResponse.errors.join("\n")}`);
96
+
97
+ // get production master metadata
98
+ const masterMetadata = (await client.ContentObjectMetadata({
99
+ libraryId,
100
+ objectId: id,
101
+ writeToken,
102
+ metadataSubtree: "/production_master"
103
+ }));
104
+
105
+ const sources = R.prop("sources", masterMetadata);
106
+ const variant = R.path(["variants", "default"], masterMetadata);
107
+
108
+ // add info on source files and variant to data if --json selected
109
+ if(this.args.json) {
110
+ logger.data("media_files", sources);
111
+ logger.data("variant_default", variant);
112
+ }
113
+
114
+ // generate ABR profile
115
+ const genProfileRetVal = ABR.ABRProfileForVariant(sources, variant, AbrProfile);
116
+ if(!genProfileRetVal.ok) throw Error(`Error(s) encountered while generating ABR profile: ${genProfileRetVal.errors.join("\n")}`);
117
+
118
+ // filter DRM/clear as needed
119
+ const filterProfileRetVal = drm ?
120
+ ABR.ProfileExcludeClear(genProfileRetVal.result) :
121
+ ABR.ProfileExcludeDRM(genProfileRetVal.result);
122
+ if(!filterProfileRetVal.ok) throw Error(`Error(s) encountered while setting playout formats: ${filterProfileRetVal.errors.join("\n")}`);
123
+
124
+ // set up mezzanine offering
125
+ logger.log("Setting up media file conversion...");
126
+ const createMezResponse = await client.CreateABRMezzanine({
127
+ name: title,
128
+ libraryId,
129
+ writeToken,
130
+ type,
131
+ masterWriteToken: writeToken,
132
+ variant: "default",
133
+ offeringKey: "default",
134
+ abrProfile: filterProfileRetVal.result
135
+ });
136
+
137
+ logger.errorsAndWarnings(createMezResponse);
138
+ const createMezErrors = createMezResponse.errors;
139
+ if(!R.isNil(createMezErrors) && !R.isEmpty(createMezErrors)) throw Error(`Error(s) encountered while setting up media file conversion: ${createMezErrors.join("\n")}`);
140
+
141
+ logger.log("Starting conversion to streaming format...");
142
+
143
+ const startJobsResponse = await client.StartABRMezzanineJobs({
144
+ libraryId,
145
+ objectId: id,
146
+ offeringKey: "default",
147
+ writeToken
148
+ });
149
+
150
+ logger.errorsAndWarnings(startJobsResponse);
151
+ const startJobsErrors = createMezResponse.errors;
152
+ if(!R.isNil(startJobsErrors) && !R.isEmpty(startJobsErrors)) throw Error(`Error(s) encountered while starting file conversion: ${startJobsErrors.join("\n")}`);
153
+
154
+ const lroWriteToken = R.path(["lro_draft", "write_token"], startJobsResponse);
155
+ const lroNode = R.path(["lro_draft", "node"], startJobsResponse);
156
+
157
+ logger.data("library_id", libraryId);
158
+ logger.data("object_id", id);
159
+ logger.data("offering_key", "default");
160
+ logger.data("write_token", lroWriteToken);
161
+ logger.data("write_node", lroNode);
162
+
163
+ logger.logList(
164
+ "",
165
+ `Library ID: ${libraryId}`,
166
+ `Object ID: ${id}`,
167
+ "Offering: default",
168
+ `Write Token: ${lroWriteToken}`,
169
+ `Write Node: ${lroNode}`,
170
+ ""
171
+ );
172
+
173
+ logger.log("Progress:");
174
+
175
+ const lro = this.concerns.LRO;
176
+ let done = false;
177
+ let lastStatus;
178
+ while(!done) {
179
+ const statusMap = await lro.status({libraryId, objectId: id, writeToken}); // TODO: check how offering key is used, if at all
180
+ const statusSummary = lro.statusSummary(statusMap);
181
+ lastStatus = statusSummary.run_state;
182
+ if(lastStatus !== LRO.STATE_RUNNING) done = true;
183
+ logger.log(`run_state: ${lastStatus}`);
184
+ const eta = statusSummary.estimated_time_left_h_m_s;
185
+ if(eta) logger.log(`estimated time left: ${eta}`);
186
+ await seconds(15);
187
+ }
188
+
189
+ const finalizeAbrResponse = await client.FinalizeABRMezzanine({
190
+ libraryId,
191
+ objectId: id,
192
+ writeToken,
193
+ offeringKey: "default"
194
+ });
195
+ const latestHash = finalizeAbrResponse.hash;
196
+
197
+ logger.errorsAndWarnings(finalizeAbrResponse);
198
+ const finalizeErrors = finalizeAbrResponse.errors;
199
+ if(!R.isNil(finalizeErrors) && !R.isEmpty(finalizeErrors)) throw Error(`Error(s) encountered while finalizing object: ${finalizeErrors.join("\n")}`);
200
+
201
+ logger.logList(
202
+ "",
203
+ "Playable media object created:",
204
+ ` Object ID: ${id}`,
205
+ ` Version Hash: ${latestHash}`,
206
+ ""
207
+ );
208
+ logger.data("version_hash", latestHash);
209
+ await this.concerns.Finalize.waitForPublish({
210
+ latestHash,
211
+ libraryId,
212
+ objectId: id
213
+ });
214
+ }
215
+
216
+ header() {
217
+ return "Create playable media object via sample ingest";
218
+ }
219
+ }
220
+
221
+ if(require.main === module) {
222
+ Utility.cmdLineInvoke(SampleIngest);
223
+ } else {
224
+ module.exports = SampleIngest;
225
+ }
@@ -0,0 +1,226 @@
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 ArgTenant = require("./lib/concerns/ArgTenant");
15
+ const {seconds} = require("./lib/helpers");
16
+ const AbrProfile = require("./lib/abr_profiles/abr_profile_clear.json");
17
+
18
+ class SampleIngest extends Utility {
19
+ blueprint() {
20
+ return {
21
+ concerns: [Client, Finalize, LocalFile, ArgLibraryId, ArgTenant, LRO],
22
+ options: [
23
+ ModOpt("libraryId", {demand: true, forX: "new media object"}),
24
+ NewOpt("title", {
25
+ demand: true,
26
+ descTemplate: "Title for new media object",
27
+ type: "string"
28
+ }),
29
+ NewOpt("drm", {
30
+ default: false,
31
+ descTemplate: "Use DRM for playback",
32
+ type: "boolean"
33
+ }),
34
+ ModOpt("files", {forX: "for new media object"})
35
+ ]
36
+ };
37
+ }
38
+
39
+ async body() {
40
+ const logger = this.logger;
41
+
42
+ let fileHandles = [];
43
+ const fileInfo = this.concerns.LocalFile.fileInfo(fileHandles);
44
+
45
+ // delay getting elvClient until this point so script exits faster
46
+ // if there is a validation error above
47
+ const client = await this.concerns.Client.get();
48
+
49
+ // get type from Tenant
50
+ const tenantInfo = await this.concerns.ArgTenant.tenantInfo();
51
+
52
+ const type = tenantInfo.typeTitle;
53
+
54
+ if(R.isNil(type)) throw Error("Tenant does not specify content type for titles");
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} MASTER`,
65
+ description: `Media object created via sample ingest: ${title}`,
66
+ fileInfo,
67
+ encrypt,
68
+ copy: true,
69
+ callback: this.concerns.LocalFile.callback
70
+ });
71
+
72
+ const {id, hash} = createMasterResponse;
73
+
74
+ // Log object id immediately, in case of error later in script
75
+ // Don't log hash yet, it will change if any other revision to object is needed
76
+ logger.data("object_id", id);
77
+
78
+ // Close file handles (if any)
79
+ this.concerns.LocalFile.closeFileHandles(fileHandles);
80
+
81
+ logger.errorsAndWarnings(createMasterResponse);
82
+
83
+ logger.logList(
84
+ "",
85
+ "Production master default variant created:",
86
+ ` Object ID: ${id}`,
87
+ ` Version Hash: ${hash}`,
88
+ ""
89
+ );
90
+
91
+ if(!R.isNil(createMasterResponse.errors) && !R.isEmpty(createMasterResponse.errors)) throw Error(`Error(s) encountered while inspecting uploaded files: ${createMasterResponse.errors.join("\n")}`);
92
+
93
+ // get production master metadata
94
+ const masterMetadata = (await client.ContentObjectMetadata({
95
+ libraryId,
96
+ objectId: id,
97
+ versionHash: hash,
98
+ metadataSubtree: "/production_master"
99
+ }));
100
+
101
+ const sources = R.prop("sources", masterMetadata);
102
+ const variant = R.path(["variants", "default"], masterMetadata);
103
+
104
+ // add info on source files and variant to data if --json selected
105
+ if(this.args.json) {
106
+ logger.data("media_files", sources);
107
+ logger.data("variant_default", variant);
108
+ }
109
+
110
+ // generate ABR profile
111
+ const genProfileRetVal = ABR.ABRProfileForVariant(sources, variant, AbrProfile);
112
+ if(!genProfileRetVal.ok) throw Error(`Error(s) encountered while generating ABR profile: ${genProfileRetVal.errors.join("\n")}`);
113
+
114
+ // filter DRM/clear as needed
115
+ const filterProfileRetVal = drm ?
116
+ ABR.ProfileExcludeClear(genProfileRetVal.result) :
117
+ ABR.ProfileExcludeDRM(genProfileRetVal.result);
118
+ if(!filterProfileRetVal.ok) throw Error(`Error(s) encountered while setting playout formats: ${filterProfileRetVal.errors.join("\n")}`);
119
+
120
+ // set up mezzanine offering
121
+ logger.log("Setting up media file conversion...");
122
+ const {writeToken} = await client.CreateContentObject({
123
+ libraryId,
124
+ options: type ? { type } : {}
125
+ });
126
+
127
+ const createMezResponse = await client.CreateABRMezzanine({
128
+ name: `${title} MEZ`,
129
+ libraryId,
130
+ type,
131
+ writeToken,
132
+ masterVersionHash: hash,
133
+ variant: "default",
134
+ offeringKey: "default",
135
+ abrProfile: filterProfileRetVal.result
136
+ });
137
+
138
+ logger.errorsAndWarnings(createMezResponse);
139
+ const createMezErrors = createMezResponse.errors;
140
+ if(!R.isNil(createMezErrors) && !R.isEmpty(createMezErrors)) throw Error(`Error(s) encountered while setting up media file conversion: ${createMezErrors.join("\n")}`);
141
+
142
+ logger.log("Starting conversion to streaming format...");
143
+
144
+ const startJobsResponse = await client.StartABRMezzanineJobs({
145
+ libraryId,
146
+ objectId: createMezResponse.id,
147
+ offeringKey: "default",
148
+ writeToken
149
+ });
150
+
151
+ logger.errorsAndWarnings(startJobsResponse);
152
+ const startJobsErrors = createMezResponse.errors;
153
+ if(!R.isNil(startJobsErrors) && !R.isEmpty(startJobsErrors)) throw Error(`Error(s) encountered while starting file conversion: ${startJobsErrors.join("\n")}`);
154
+
155
+ const lroWriteToken = R.path(["lro_draft", "write_token"], startJobsResponse);
156
+ const lroNode = R.path(["lro_draft", "node"], startJobsResponse);
157
+
158
+ logger.data("library_id", libraryId);
159
+ logger.data("object_id", id);
160
+ logger.data("offering_key", "default");
161
+ logger.data("write_token", lroWriteToken);
162
+ logger.data("write_node", lroNode);
163
+
164
+ logger.logList(
165
+ "",
166
+ `Library ID: ${libraryId}`,
167
+ `Object ID: ${id}`,
168
+ "Offering: default",
169
+ `Write Token: ${lroWriteToken}`,
170
+ `Write Node: ${lroNode}`,
171
+ ""
172
+ );
173
+
174
+ logger.log("Progress:");
175
+
176
+ const lro = this.concerns.LRO;
177
+ let done = false;
178
+ let lastStatus;
179
+ while(!done) {
180
+ const statusMap = await lro.status({libraryId, objectId: id, writeToken}); // TODO: check how offering key is used, if at all
181
+ const statusSummary = lro.statusSummary(statusMap);
182
+ lastStatus = statusSummary.run_state;
183
+ if(lastStatus !== LRO.STATE_RUNNING) done = true;
184
+ logger.log(`run_state: ${lastStatus}`);
185
+ const eta = statusSummary.estimated_time_left_h_m_s;
186
+ if(eta) logger.log(`estimated time left: ${eta}`);
187
+ await seconds(15);
188
+ }
189
+
190
+ const finalizeAbrResponse = await client.FinalizeABRMezzanine({
191
+ libraryId,
192
+ objectId: createMezResponse.id,
193
+ writeToken,
194
+ offeringKey: "default"
195
+ });
196
+ const latestHash = finalizeAbrResponse.hash;
197
+
198
+ logger.errorsAndWarnings(finalizeAbrResponse);
199
+ const finalizeErrors = finalizeAbrResponse.errors;
200
+ if(!R.isNil(finalizeErrors) && !R.isEmpty(finalizeErrors)) throw Error(`Error(s) encountered while finalizing object: ${finalizeErrors.join("\n")}`);
201
+
202
+ logger.logList(
203
+ "",
204
+ "Playable media object created:",
205
+ ` Object ID: ${id}`,
206
+ ` Version Hash: ${latestHash}`,
207
+ ""
208
+ );
209
+ logger.data("version_hash", latestHash);
210
+ await this.concerns.Finalize.waitForPublish({
211
+ latestHash,
212
+ libraryId,
213
+ objectId: createMezResponse.id
214
+ });
215
+ }
216
+
217
+ header() {
218
+ return "Create playable media object via sample ingest";
219
+ }
220
+ }
221
+
222
+ if(require.main === module) {
223
+ Utility.cmdLineInvoke(SampleIngest);
224
+ } else {
225
+ module.exports = SampleIngest;
226
+ }
@@ -40,4 +40,4 @@ const New = context => {
40
40
  module.exports = {
41
41
  blueprint,
42
42
  New
43
- };
43
+ };