@eluvio/elv-client-js 4.0.93 → 4.0.95

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.
@@ -1,10 +1,12 @@
1
1
  var _slicedToArray = require("@babel/runtime/helpers/slicedToArray");
2
+ var _objectWithoutProperties = require("@babel/runtime/helpers/objectWithoutProperties");
2
3
  var _defineProperty = require("@babel/runtime/helpers/defineProperty");
3
4
  var _regeneratorRuntime = require("@babel/runtime/regenerator");
4
5
  var _typeof = require("@babel/runtime/helpers/typeof");
5
6
  var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator");
6
7
  var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
7
8
  var _createClass = require("@babel/runtime/helpers/createClass");
9
+ var _excluded = ["code", "address", "type", "authToken", "expiresAt"];
8
10
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
9
11
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
10
12
  var _require = require("../ElvClient"),
@@ -1002,11 +1004,11 @@ var ElvWalletClient = /*#__PURE__*/function () {
1002
1004
  key: "SetCodeAuth",
1003
1005
  value: function () {
1004
1006
  var _SetCodeAuth = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16(_ref15) {
1005
- var code, address, type, authToken;
1007
+ var code, address, type, authToken, expiresAt, additionalPayload;
1006
1008
  return _regeneratorRuntime.wrap(function _callee16$(_context16) {
1007
1009
  while (1) switch (_context16.prev = _context16.next) {
1008
1010
  case 0:
1009
- code = _ref15.code, address = _ref15.address, type = _ref15.type, authToken = _ref15.authToken;
1011
+ code = _ref15.code, address = _ref15.address, type = _ref15.type, authToken = _ref15.authToken, expiresAt = _ref15.expiresAt, additionalPayload = _objectWithoutProperties(_ref15, _excluded);
1010
1012
  _context16.next = 3;
1011
1013
  return Utils.ResponseToJson(this.client.authClient.MakeAuthServiceRequest({
1012
1014
  path: UrlJoin("as", "wlt", "login", "session", code),
@@ -1018,12 +1020,13 @@ var ElvWalletClient = /*#__PURE__*/function () {
1018
1020
  op: "set",
1019
1021
  id: code,
1020
1022
  format: "auth_token",
1021
- payload: JSON.stringify({
1023
+ payload: JSON.stringify(_objectSpread({
1022
1024
  addr: Utils.FormatAddress(address),
1023
1025
  eth: address ? "ikms".concat(Utils.AddressToHash(address)) : "",
1024
1026
  type: type,
1025
- token: authToken
1026
- })
1027
+ token: authToken,
1028
+ expiresAt: expiresAt
1029
+ }, additionalPayload))
1027
1030
  }
1028
1031
  }));
1029
1032
  case 3:
@@ -1875,11 +1878,11 @@ var ElvWalletClient = /*#__PURE__*/function () {
1875
1878
  key: "DeployTenant",
1876
1879
  value: function () {
1877
1880
  var _DeployTenant = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee24(_ref23) {
1878
- var tenantId, _ref23$tenantSlug, tenantSlug, tenantHash, tenantLink, deployedTenantHash, body, token;
1881
+ var tenantId, _ref23$tenantSlug, tenantSlug, tenantHash, _ref23$environment, environment, tenantLink, deployedTenantHash, body, token;
1879
1882
  return _regeneratorRuntime.wrap(function _callee24$(_context24) {
1880
1883
  while (1) switch (_context24.prev = _context24.next) {
1881
1884
  case 0:
1882
- tenantId = _ref23.tenantId, _ref23$tenantSlug = _ref23.tenantSlug, tenantSlug = _ref23$tenantSlug === void 0 ? "" : _ref23$tenantSlug, tenantHash = _ref23.tenantHash;
1885
+ tenantId = _ref23.tenantId, _ref23$tenantSlug = _ref23.tenantSlug, tenantSlug = _ref23$tenantSlug === void 0 ? "" : _ref23$tenantSlug, tenantHash = _ref23.tenantHash, _ref23$environment = _ref23.environment, environment = _ref23$environment === void 0 ? "production" : _ref23$environment;
1883
1886
  if (tenantHash) {
1884
1887
  _context24.next = 11;
1885
1888
  break;
@@ -1913,6 +1916,7 @@ var ElvWalletClient = /*#__PURE__*/function () {
1913
1916
  case 11:
1914
1917
  body = {
1915
1918
  content_hash: tenantHash,
1919
+ env: environment,
1916
1920
  ts: Date.now()
1917
1921
  };
1918
1922
  _context24.next = 14;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "4.0.93",
3
+ "version": "4.0.95",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
@@ -702,7 +702,7 @@ class ElvWalletClient {
702
702
  return response;
703
703
  }
704
704
 
705
- async SetCodeAuth({code, address, type, authToken}) {
705
+ async SetCodeAuth({code, address, type, authToken, expiresAt, ...additionalPayload}) {
706
706
  await Utils.ResponseToJson(
707
707
  this.client.authClient.MakeAuthServiceRequest({
708
708
  path: UrlJoin("as", "wlt", "login", "session", code),
@@ -718,7 +718,9 @@ class ElvWalletClient {
718
718
  addr: Utils.FormatAddress(address),
719
719
  eth: address ? `ikms${Utils.AddressToHash(address)}` : "",
720
720
  type,
721
- token: authToken
721
+ token: authToken,
722
+ expiresAt,
723
+ ...additionalPayload
722
724
  })
723
725
  }
724
726
  })
@@ -1386,7 +1388,7 @@ class ElvWalletClient {
1386
1388
  }
1387
1389
  }
1388
1390
 
1389
- async DeployTenant({tenantId, tenantSlug="", tenantHash}) {
1391
+ async DeployTenant({tenantId, tenantSlug="", tenantHash, environment="production"}) {
1390
1392
  if(!tenantHash) {
1391
1393
  const tenantLink = await this.client.ContentObjectMetadata({
1392
1394
  libraryId: this.mainSiteLibraryId,
@@ -1410,7 +1412,7 @@ class ElvWalletClient {
1410
1412
  tenantHash = await this.client.LatestVersionHash({versionHash: deployedTenantHash});
1411
1413
  }
1412
1414
 
1413
- const body = { content_hash: tenantHash, ts: Date.now() };
1415
+ const body = { content_hash: tenantHash, env: environment, ts: Date.now() };
1414
1416
  const token = await this.client.Sign(JSON.stringify(body));
1415
1417
  await this.client.authClient.MakeAuthServiceRequest({
1416
1418
  path: UrlJoin("as", "tnt", "config", tenantId, "metadata"),
@@ -15,7 +15,7 @@ const Tool = async () => {
15
15
  });
16
16
 
17
17
  client.SetSigner({signer});
18
- client.ToggleLogging(true);
18
+ //client.ToggleLogging(true);
19
19
 
20
20
 
21
21
  try {
@@ -0,0 +1,291 @@
1
+ /* eslint-disable no-console */
2
+ const ScriptBase = require("./parentClasses/ScriptBase");
3
+ const utils = require("../src/Utils");
4
+ const Fraction = require("fraction.js");
5
+ const {JSONPath} = require("jsonpath-plus");
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const { execSync } = require("child_process");
9
+
10
+ class OfferingDownloadMedia2 extends ScriptBase {
11
+
12
+ async body(){
13
+
14
+ let objectId=this.args.objectId;
15
+ const versionHash=this.args.versionHash;
16
+ const offeringKey=this.args.offeringKey;
17
+ const streamKey=this.args.streamKey;
18
+ const startTime=this.args.startTime;
19
+ let endTime=this.args.endTime;
20
+ const out=this.args.out;
21
+
22
+ if(!objectId && !versionHash) throw new Error("Require object-id or object-hash to be provided");
23
+ if(!objectId) {
24
+ objectId = utils.DecodeVersionHash(versionHash).objectId;
25
+ }
26
+
27
+ if(startTime < 0) {
28
+ throw new Error(`start time provided needs to be greater than 0: start=${startTime}s`);
29
+ }
30
+ if(startTime >= endTime) {
31
+ throw new Error(`end time needs to be greater than start time, values provided: start=${startTime}s, end=${endTime}s`);
32
+ }
33
+
34
+ const client=await this.client();
35
+ const libraryId=await client.ContentObjectLibraryId({objectId, versionHash});
36
+
37
+ // get object metadata
38
+ const metadata = await client.ContentObjectMetadata({ libraryId, objectId });
39
+
40
+ const offeringMetadata=JSONPath({
41
+ json: metadata,
42
+ path: `offerings.${offeringKey}`,
43
+ wrap: false
44
+ });
45
+
46
+ const transcodesMetadata=JSONPath({
47
+ json:metadata,
48
+ path: "transcodes"
49
+ });
50
+
51
+ // Retrieve stream metadata from transcodes or offering metadata
52
+ // Create a map of streamKey => stream metadata
53
+ const streamsMap = Object.fromEntries(
54
+ Object.keys(offeringMetadata.playout.streams).map(streamKey => {
55
+ const info = this.getStreamInfo(offeringMetadata, transcodesMetadata, streamKey);
56
+ if (info === undefined) {
57
+ console.log(`StreamInfo returned undefined for streamKey: ${streamKey}`);
58
+ }
59
+ return [streamKey, info || {}];
60
+ })
61
+ );
62
+
63
+ let streamKeyArray = streamKey.split(",").map(key => key.trim()); // trim() to remove any extra spaces
64
+ const streamsMapKeys = new Set(Object.keys(streamsMap));
65
+
66
+ // Filter the streamKeyArray to only include keys present in streamsMap
67
+ streamKeyArray = streamKeyArray.filter(key => {
68
+ if (!streamsMapKeys.has(key)) {
69
+ console.warn(`Warning: Stream key "${key}" not found in streamsMap.`);
70
+ return false;
71
+ }
72
+ return true;
73
+ });
74
+
75
+ // Retrieve all parts that includes the start and end time for each streamKey
76
+ const partsMap = this.getPartsMap(streamsMap, streamKeyArray, startTime, endTime);
77
+ console.log("PARTS MAP => { parts, minStart, maxEnd } map:", partsMap);
78
+
79
+ // handle directories
80
+ const dirPath=path.resolve(out);
81
+ if(!fs.existsSync(dirPath)) {
82
+ fs.mkdirSync(dirPath, {recursive: true});
83
+ console.log(`Directory created at ${dirPath}`);
84
+ } else {
85
+ console.log(`Directory already exists at ${dirPath}`);
86
+ }
87
+ // create directory for object provided : iq_XXX_start-time_end-time
88
+ const contentObjDirPath = path.join(dirPath, `${objectId}_${this.secondsToHms(startTime, "-")}_${this.secondsToHms(endTime, "-")}`);
89
+ // if(fs.existsSync(contentObjDirPath)) throw new Error(`Directory already exists at ${contentObjDirPath}`);
90
+ // fs.mkdirSync(contentObjDirPath, { recursive: true });
91
+ if(!fs.existsSync(contentObjDirPath)) {
92
+ fs.mkdirSync(contentObjDirPath, { recursive: true });
93
+ console.log(`Directory created at ${contentObjDirPath}`);
94
+ }
95
+
96
+ const trimmedDirectory = path.join(contentObjDirPath, "trimmed");
97
+ if(!fs.existsSync(trimmedDirectory)) {
98
+ fs.mkdirSync(trimmedDirectory, { recursive: true });
99
+ }
100
+
101
+ // Download and concatenate the parts for each streamKey
102
+ // Then, trim the concatenated media
103
+ for(const streamKey of Object.keys(partsMap)) {
104
+ const { parts, minStart, maxEnd } = partsMap[streamKey];
105
+ const partsFile = await this.downloadParts(contentObjDirPath, libraryId, objectId, streamKey, parts);
106
+ console.log(`parts file for ${streamKey}: ${partsFile}\n`);
107
+
108
+ // concatenate the parts
109
+ let mediaFile=path.join(contentObjDirPath, `${streamKey}.mp4`);
110
+ let cmd=`ffmpeg -f concat -safe 0 -i ${partsFile} -c copy ${mediaFile}`;
111
+ console.log("Running", cmd);
112
+ try {
113
+ execSync(cmd);
114
+ console.log("Concatenation complete.");
115
+ } catch(error) {
116
+ console.error("Error running ffmpeg:", error);
117
+ }
118
+
119
+ // trim the parts
120
+ let trimStartTime=null;
121
+ let trimEndTime=null;
122
+ // since new concatenated video starts from 0s
123
+ if(minStart !== null && maxEnd !== null) {
124
+ trimStartTime=startTime - minStart;
125
+ trimEndTime=endTime - minStart;
126
+ }
127
+
128
+ let mediaTrimmedFile=path.join(trimmedDirectory, `${streamKey}_trimmed.mp4`);
129
+ cmd=`ffmpeg -i ${mediaFile} -ss ${this.secondsToHms(trimStartTime, ":")} -t ${this.secondsToHms(trimEndTime - trimStartTime, ":")} ${mediaTrimmedFile}`;
130
+ console.log("Running", cmd);
131
+ try {
132
+ execSync(cmd);
133
+ console.log(`\nTrimmed ${streamKey} file: ${mediaTrimmedFile}`);
134
+ } catch(error) {
135
+ console.error("Error running ffmpeg:", error);
136
+ }
137
+
138
+ console.log("================================================");
139
+ }
140
+
141
+ }
142
+
143
+ getStreamInfo(offering, transcodes, streamKey) {
144
+ const reps = offering.playout.streams[streamKey].representations;
145
+ const rep = reps && Object.values(reps).find(r => r.transcode_id);
146
+ return rep && (transcodes[0] && transcodes[0][rep.transcode_id] && transcodes[0][rep.transcode_id].stream) || offering.media_struct.streams[streamKey];
147
+ }
148
+
149
+ getPartsMap(streamsMap, streamKeyArray, startTime, endTime){
150
+ const partsMap = {};
151
+
152
+ streamKeyArray.forEach(key => {
153
+ let sourcesMetadata = streamsMap[key].sources;
154
+ let durationMetadata = streamsMap[key].duration;
155
+
156
+ const totalDuration = new Fraction(durationMetadata.ts).mul(new Fraction(durationMetadata.time_base));
157
+ if (endTime > totalDuration) {
158
+ console.warn(`Warning: end time exceeds total duration. Setting end time to total duration: ${totalDuration}s`);
159
+ endTime = totalDuration;
160
+ }
161
+
162
+ const sourcesTimeInfo = sourcesMetadata.map(part => {
163
+ const start = new Fraction(part.timeline_start.ts).mul(new Fraction(part.timeline_start.time_base));
164
+ const end = new Fraction(part.timeline_end.ts).mul(new Fraction(part.timeline_end.time_base));
165
+ return {
166
+ start: start.valueOf(),
167
+ end: end.valueOf(),
168
+ source: part.source
169
+ };
170
+ });
171
+
172
+ let parts = [];
173
+ let minStart = null;
174
+ let maxEnd = null;
175
+ sourcesTimeInfo.forEach(item => {
176
+ if(startTime < item.end && endTime > item.start) {
177
+ parts.push(item.source);
178
+ if (minStart === null || item.start < minStart) {
179
+ minStart = item.start;
180
+ }
181
+ if(maxEnd === null || item.end > maxEnd) {
182
+ maxEnd = item.end;
183
+ }
184
+ }
185
+ });
186
+
187
+ partsMap[key] = {
188
+ parts,
189
+ minStart,
190
+ maxEnd
191
+ };
192
+ });
193
+ return partsMap;
194
+ }
195
+
196
+ async downloadParts(outDir, libraryId, objectId, streamKey, parts) {
197
+ const mtPath=path.join(outDir, streamKey);
198
+ if(!fs.existsSync(mtPath)) {
199
+ fs.mkdirSync(mtPath, {recursive: true});
200
+ console.log(`Directory created at ${mtPath}`);
201
+ } else {
202
+ throw new Error(`Directory already exists at ${mtPath}`);
203
+ }
204
+
205
+ const partsFile=path.join(outDir, `parts_${streamKey}.txt`);
206
+ const client=await this.client();
207
+
208
+ console.log("\nDownloading parts...\n");
209
+ for(const [index, partHash] of parts.entries()) {
210
+ let ph=(index + 1).toString().padStart(4, "0") + "." + partHash;
211
+ console.log(`processing ${ph}...`);
212
+
213
+ const buf=await client.DownloadPart({
214
+ libraryId,
215
+ objectId,
216
+ partHash,
217
+ format: "buffer",
218
+ chunked: false,
219
+ });
220
+
221
+ let partFile=path.join(mtPath, ph + ".mp4");
222
+ fs.appendFileSync(partFile, buf, (err) => {
223
+ if(err) {
224
+ console.log(err);
225
+ }
226
+ });
227
+
228
+ fs.appendFileSync(partsFile, `file '${partFile}'\n`, (err) => {
229
+ if(err) {
230
+ console.log(err);
231
+ }
232
+ });
233
+ }
234
+ return partsFile;
235
+ }
236
+
237
+ secondsToHms(seconds, separator) {
238
+ const date=new Date(seconds * 1000);
239
+ const hh=String(date.getUTCHours()).padStart(2, "0");
240
+ const mm=String(date.getUTCMinutes()).padStart(2, "0");
241
+ const ss=String(date.getUTCSeconds()).padStart(2, "0");
242
+ const ms=String(date.getUTCMilliseconds()).padStart(3, "0");
243
+ return `${hh}${separator}${mm}${separator}${ss}.${ms}`;
244
+ }
245
+
246
+ header() {
247
+ return `Downloading parts from startTime: ${this.args.startTime}s to endTime: ${this.args.endTime}s`;
248
+ }
249
+
250
+ options() {
251
+ return super.options()
252
+ .option("objectId", {
253
+ alias: "object-id",
254
+ describe: "Object ID (should start with 'iq__')",
255
+ type: "string"
256
+ })
257
+ .option("versionHash", {
258
+ alias: "version-hash",
259
+ describe: "Object Version Hash (should start with 'hq__')",
260
+ type: "string"
261
+ })
262
+ .option("offeringKey", {
263
+ describe: "offering key",
264
+ type: "string",
265
+ default: "default",
266
+ })
267
+ .option("streamKey", {
268
+ describe: "comma separated list of offerings stream key",
269
+ type: "string",
270
+ default: "video",
271
+ })
272
+ .option("startTime", {
273
+ describe: "start time to retrieve parts in seconds",
274
+ demandOption: true,
275
+ type: "number",
276
+ })
277
+ .option("endTime", {
278
+ describe: "end time to retrieve parts in seconds",
279
+ demandOption: true,
280
+ type: "number",
281
+ })
282
+ .option("out",{
283
+ describe: "output directory",
284
+ type: "string",
285
+ default: "./out",
286
+ });
287
+ }
288
+ }
289
+
290
+ const script = new OfferingDownloadMedia2();
291
+ script.run();