@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.
- package/lib/FileSystem.d.ts +13 -1
- package/lib/FileSystem.js +78 -19
- package/lib/Worker.d.ts +7 -0
- package/lib/Worker.js +15 -2
- package/package.json +4 -2
package/lib/FileSystem.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
8
|
-
const
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
45
|
+
node_fs_1.default.mkdirSync(folder);
|
|
22
46
|
}
|
|
23
47
|
static removeFolder(folder, recursively = true) {
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
const item =
|
|
27
|
-
if (
|
|
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
|
-
|
|
58
|
+
node_fs_1.default.unlinkSync(item);
|
|
35
59
|
}
|
|
36
60
|
});
|
|
37
|
-
|
|
61
|
+
node_fs_1.default.rmdirSync(folder);
|
|
38
62
|
}
|
|
39
63
|
}
|
|
40
64
|
static async downloadFile(url, filepath) {
|
|
41
65
|
try {
|
|
42
|
-
const writer =
|
|
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
|
-
|
|
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 } =
|
|
91
|
-
const readStream =
|
|
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)(
|
|
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(
|
|
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) =>
|
|
60
|
-
|
|
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.
|
|
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.
|
|
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
|
},
|