@quatrain/worker 1.1.14 → 1.1.16

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,8 +1,20 @@
1
+ import { FileType } from '@quatrain/storage';
1
2
  export declare class FileSystem {
2
3
  static prepare(folder: string): void;
3
4
  static makeFolder(folder: string): void;
4
5
  static removeFolder(folder: string, recursively?: boolean): void;
5
6
  static downloadFile(url: string, filepath: string): Promise<unknown>;
6
7
  static safeString(name: string): string;
7
- static uploadFile(filename: string, destination: string, mime?: string): Promise<unknown>;
8
+ /**
9
+ * Upload file to public URL and return meta data
10
+ * @param filename string
11
+ * @param meta
12
+ * @param mime
13
+ * @returns Promise
14
+ */
15
+ static uploadFile(filename: string, meta: FileType, mime?: string): Promise<FileType>;
16
+ /**
17
+ * Return meta data on given file
18
+ */
19
+ static getInfo: (file: string) => Promise<any>;
8
20
  }
package/lib/FileSystem.js CHANGED
@@ -1,45 +1,69 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.FileSystem = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
30
+ const node_fs_1 = __importDefault(require("node:fs"));
31
+ const node_path_1 = __importDefault(require("node:path"));
9
32
  const axios_1 = __importDefault(require("axios"));
10
33
  const Worker_1 = require("./Worker");
11
34
  const node_fetch_native_1 = __importDefault(require("node-fetch-native"));
35
+ const ffmpeg = __importStar(require("fluent-ffmpeg"));
12
36
  class FileSystem {
13
37
  static prepare(folder) {
14
38
  Worker_1.Worker.log(`Setting up process folder ${folder}`);
15
39
  this.removeFolder(folder);
16
- fs_1.default.mkdirSync(folder);
17
- fs_1.default.mkdirSync(folder + path_1.default.sep + 'images');
18
- fs_1.default.mkdirSync(folder + path_1.default.sep + 'vecto');
40
+ node_fs_1.default.mkdirSync(folder);
41
+ node_fs_1.default.mkdirSync(folder + node_path_1.default.sep + 'images');
42
+ node_fs_1.default.mkdirSync(folder + node_path_1.default.sep + 'vecto');
19
43
  }
20
44
  static makeFolder(folder) {
21
- fs_1.default.mkdirSync(folder);
45
+ node_fs_1.default.mkdirSync(folder);
22
46
  }
23
47
  static removeFolder(folder, recursively = true) {
24
- if (fs_1.default.existsSync(folder)) {
25
- fs_1.default.readdirSync(folder).forEach((element) => {
26
- const item = path_1.default.join(folder, element);
27
- if (fs_1.default.lstatSync(item).isDirectory()) {
48
+ if (node_fs_1.default.existsSync(folder)) {
49
+ node_fs_1.default.readdirSync(folder).forEach((element) => {
50
+ const item = node_path_1.default.join(folder, element);
51
+ if (node_fs_1.default.lstatSync(item).isDirectory()) {
28
52
  if (recursively !== true) {
29
53
  throw new Error(`Folder contains folder`);
30
54
  }
31
55
  this.removeFolder(item);
32
56
  }
33
57
  else {
34
- fs_1.default.unlinkSync(item);
58
+ node_fs_1.default.unlinkSync(item);
35
59
  }
36
60
  });
37
- fs_1.default.rmdirSync(folder);
61
+ node_fs_1.default.rmdirSync(folder);
38
62
  }
39
63
  }
40
64
  static async downloadFile(url, filepath) {
41
65
  try {
42
- const writer = fs_1.default.createWriteStream(filepath);
66
+ const writer = node_fs_1.default.createWriteStream(filepath);
43
67
  const response = await axios_1.default.get(url, {
44
68
  responseType: 'stream',
45
69
  });
@@ -82,13 +106,22 @@ class FileSystem {
82
106
  // }
83
107
  // })
84
108
  // }
85
- static uploadFile(filename, destination, mime = 'video/mp4') {
109
+ /**
110
+ * Upload file to public URL and return meta data
111
+ * @param filename string
112
+ * @param meta
113
+ * @param mime
114
+ * @returns Promise
115
+ */
116
+ static uploadFile(filename, meta, mime = 'video/mp4') {
117
+ // try to get more file metadata
118
+ meta = { ...meta, ...FileSystem.getInfo(filename) };
86
119
  return new Promise((resolve, reject) => {
87
120
  try {
88
121
  let done = 0; // total bytes uploaded
89
122
  let prev = 0; // latest value of done stored when % done was displayed
90
- const { size } = fs_1.default.statSync(filename);
91
- const readStream = fs_1.default.createReadStream(filename);
123
+ const { size } = node_fs_1.default.statSync(filename);
124
+ const readStream = node_fs_1.default.createReadStream(filename);
92
125
  const sizeMB = (size / (1024 * 1024)).toFixed(2);
93
126
  readStream.on('data', (data) => {
94
127
  done += data.length;
@@ -100,17 +133,17 @@ class FileSystem {
100
133
  }
101
134
  });
102
135
  Worker_1.Worker.info(`Uploading file ${filename} with size ${size} bytes`);
103
- (0, node_fetch_native_1.default)(destination, {
136
+ (0, node_fetch_native_1.default)(meta.uploadUrl, {
104
137
  method: 'PUT',
105
138
  mode: 'cors',
106
139
  duplex: 'half',
107
140
  body: readStream,
108
141
  headers: {
109
- 'Content-Type': mime,
142
+ 'Content-Type': meta.contentType || mime,
110
143
  'Content-length': String(size),
111
144
  },
112
145
  })
113
- .then((res) => resolve(res))
146
+ .then((res) => resolve({ ...meta, size, uploadUrl: undefined }))
114
147
  .catch((err) => reject(err));
115
148
  }
116
149
  catch (err) {
@@ -119,5 +152,31 @@ class FileSystem {
119
152
  }
120
153
  });
121
154
  }
155
+ /**
156
+ * Return meta data on given file
157
+ */
158
+ static getInfo = (file) => {
159
+ if (file.endsWith('.mp4') || file.endsWith('.insv')) {
160
+ return new Promise((resolve, reject) => ffmpeg.ffprobe(file, (err, metadata) => {
161
+ if (err) {
162
+ Worker_1.Worker.error(err);
163
+ reject(err);
164
+ }
165
+ Worker_1.Worker.debug(`ffprobe getInfo: ${JSON.stringify(metadata)}`);
166
+ const { width, height, duration, bit_rate: bitrate, nb_frames: nbFramees, } = metadata.streams[0];
167
+ const nb_frames = parseFloat(nbFramees);
168
+ const framerate = nb_frames / parseFloat(duration);
169
+ resolve({
170
+ width,
171
+ height,
172
+ framerate: framerate.toFixed(0),
173
+ duration: parseInt(duration),
174
+ bitrate,
175
+ });
176
+ }));
177
+ }
178
+ // Handle other cases silently
179
+ return new Promise((resolve) => resolve({}));
180
+ };
122
181
  }
123
182
  exports.FileSystem = FileSystem;
package/lib/Worker.d.ts CHANGED
@@ -10,5 +10,12 @@ export declare class Worker extends Core {
10
10
  * @return Promise
11
11
  */
12
12
  static execPromise: (command: string, args?: any[], cwd?: string) => Promise<any>;
13
+ /**
14
+ * Push an event to the backend endpoint, if available
15
+ * @param event string
16
+ * @param data
17
+ * @param ts timestamp
18
+ * @returns boolean
19
+ */
13
20
  static pushEvent(event: string, data?: {}, ts?: number): false | undefined;
14
21
  }
package/lib/Worker.js CHANGED
@@ -41,6 +41,13 @@ class Worker extends core_1.Core {
41
41
  });
42
42
  });
43
43
  };
44
+ /**
45
+ * Push an event to the backend endpoint, if available
46
+ * @param event string
47
+ * @param data
48
+ * @param ts timestamp
49
+ * @returns boolean
50
+ */
44
51
  static pushEvent(event, data = {}, ts = 0) {
45
52
  if (!this.endpoint) {
46
53
  Worker.warn(`Events endpoint is not set, can't send update!`);
@@ -56,8 +63,14 @@ class Worker extends core_1.Core {
56
63
  };
57
64
  axios_1.default
58
65
  .patch(Worker.endpoint, payload)
59
- .then((res) => Worker.info(`Event pushed to backend: ${res.statusText}`))
60
- .catch((err) => Worker.error(`Failed to push event to backend: ${err}`));
66
+ .then((res) => {
67
+ Worker.info(`Event pushed to backend: ${res.statusText}`);
68
+ return true;
69
+ })
70
+ .catch((err) => {
71
+ Worker.error(`Failed to push event to backend: ${err}`);
72
+ return false;
73
+ });
61
74
  }
62
75
  }
63
76
  exports.Worker = Worker;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/worker",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "description": "Container Worker helpers",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -12,6 +12,7 @@
12
12
  "license": "MIT",
13
13
  "devDependencies": {
14
14
  "@tsconfig/recommended": "^1.0.1",
15
+ "@types/fluent-ffmpeg": "^2",
15
16
  "@types/fs-extra": "^11.0.4",
16
17
  "@types/jest": "^27.0.3",
17
18
  "@types/node": "^22.9.0",
@@ -24,8 +25,9 @@
24
25
  "typescript": "^5.1.5"
25
26
  },
26
27
  "dependencies": {
27
- "@quatrain/core": "^1.1.11",
28
+ "@quatrain/core": "^1.1.14",
28
29
  "axios": "^1.7.7",
30
+ "fluent-ffmpeg": "^2.1.2",
29
31
  "fs-extra": "^11.2.0",
30
32
  "node-fetch-native": "^1.6.4"
31
33
  },