tools_batch_files 1.0.19 → 1.0.21
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/package.json +3 -2
- package/src/photoBatch.js +119 -42
- package/src/photoBatchBack.js +528 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "tools_batch_files",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.21",
|
4
4
|
"description": "批处理视频工具",
|
5
5
|
"keywords": [
|
6
6
|
"utils",
|
@@ -11,7 +11,8 @@
|
|
11
11
|
"main": "index.js",
|
12
12
|
"bin": {
|
13
13
|
"tbf": "./index.js",
|
14
|
-
"tbfp": "./src/photoBatch.js"
|
14
|
+
"tbfp": "./src/photoBatch.js",
|
15
|
+
"tbfb": "./src/photoBatchBack.js"
|
15
16
|
},
|
16
17
|
"scripts": {
|
17
18
|
"test": "echo \"Error: no test specified\" && exit 1",
|
package/src/photoBatch.js
CHANGED
@@ -35,10 +35,10 @@ const ZIP_FILES_DIR = "zip";
|
|
35
35
|
const expandedName = ".jpg";
|
36
36
|
|
37
37
|
//并发数量
|
38
|
-
const queueCount =
|
38
|
+
const queueCount = 50;
|
39
39
|
|
40
40
|
//起始任务下标
|
41
|
-
let taskIndex =
|
41
|
+
let taskIndex = 88943;
|
42
42
|
|
43
43
|
const readExcel = (path) => {
|
44
44
|
const workbook = XLSX.readFile(path);
|
@@ -100,6 +100,39 @@ function findFileInDir(dir, fileName) {
|
|
100
100
|
return null;
|
101
101
|
}
|
102
102
|
|
103
|
+
// function findFileInDir(dir, fileName) {
|
104
|
+
// return new Promise((resolve, reject) => {
|
105
|
+
// fs.readdir(dir, (err, files) => {
|
106
|
+
// if (err) {
|
107
|
+
// reject(err);
|
108
|
+
// return;
|
109
|
+
// }
|
110
|
+
|
111
|
+
// // 遍历目录中的文件和子目录
|
112
|
+
// for (const file of files) {
|
113
|
+
// const filePath = path.join(dir, file);
|
114
|
+
// fs.stat(filePath, (err, stat) => {
|
115
|
+
// if (err) {
|
116
|
+
// reject(err); // 如果获取文件状态出错,直接reject
|
117
|
+
// return;
|
118
|
+
// }
|
119
|
+
// if (stat.isDirectory()) {
|
120
|
+
// // 如果是目录,递归调用findFileInDir
|
121
|
+
// findFileInDir(filePath, fileName)
|
122
|
+
// .then(resolve) // 如果找到了目标文件,将结果resolve
|
123
|
+
// .catch(reject); // 如果在子目录中出错,将错误reject
|
124
|
+
// } else if (file.startsWith(fileName) && file.endsWith(expandedName)) {
|
125
|
+
// resolve(filePath); // 如果找到了目标文件,将结果resolve
|
126
|
+
// }
|
127
|
+
// });
|
128
|
+
// }
|
129
|
+
|
130
|
+
// // 如果遍历完了所有文件和子目录仍未找到目标文件,resolve一个null表示未找到
|
131
|
+
// resolve(null);
|
132
|
+
// });
|
133
|
+
// });
|
134
|
+
// }
|
135
|
+
|
103
136
|
/**
|
104
137
|
* 生成预览图 indexFilePath: output/0
|
105
138
|
* originFilePath E:\workspace\图片测试\photos\abc222.png
|
@@ -273,32 +306,39 @@ const getMetadata = async (
|
|
273
306
|
|
274
307
|
await new Promise((resolve, reject) => {
|
275
308
|
photoMetadataComand.ffprobe(function (err, metadata) {
|
276
|
-
console.log("metadata");
|
277
|
-
console.log(JSON.stringify(metadata));
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
309
|
+
// console.log("metadata");
|
310
|
+
// console.log(JSON.stringify(metadata));
|
311
|
+
if (metadata) {
|
312
|
+
const formatStream = metadata.format;
|
313
|
+
const photoStream = metadata.streams.find(
|
314
|
+
(s) => s.codec_type === "video"
|
315
|
+
);
|
316
|
+
|
317
|
+
metaDataParams.width = photoStream.width;
|
318
|
+
metaDataParams.height = photoStream.height;
|
319
|
+
// metaDataParams.format = formatStream.format_name;
|
320
|
+
metaDataParams.format = "jpg";
|
321
|
+
metaDataParams.size = formatStream.size;
|
289
322
|
|
290
|
-
|
323
|
+
resolve();
|
324
|
+
} else {
|
325
|
+
reject(err);
|
326
|
+
}
|
291
327
|
});
|
292
328
|
});
|
293
329
|
await new Promise((resolve, reject) => {
|
294
330
|
photoPreviewMetadataComand.ffprobe(function (err, metadata) {
|
295
|
-
|
296
|
-
|
297
|
-
|
331
|
+
if (metadata) {
|
332
|
+
const photoStream = metadata.streams.find(
|
333
|
+
(s) => s.codec_type === "video"
|
334
|
+
);
|
298
335
|
|
299
|
-
|
300
|
-
|
301
|
-
|
336
|
+
metaDataParams.common_width = photoStream.width;
|
337
|
+
metaDataParams.common_height = photoStream.height;
|
338
|
+
resolve();
|
339
|
+
} else {
|
340
|
+
reject(err);
|
341
|
+
}
|
302
342
|
});
|
303
343
|
});
|
304
344
|
|
@@ -332,7 +372,7 @@ const postData = (dataParams, indexFilePath) => {
|
|
332
372
|
headers: {
|
333
373
|
"Content-Type": "multipart/form-data",
|
334
374
|
},
|
335
|
-
timeout:
|
375
|
+
timeout: 300000,
|
336
376
|
});
|
337
377
|
};
|
338
378
|
|
@@ -356,11 +396,18 @@ const task = async (row, index) => {
|
|
356
396
|
fileName = row.fileName + expandedName;
|
357
397
|
}
|
358
398
|
|
399
|
+
const getPathStartTime = new Date();
|
359
400
|
// 源图片文件夹路径
|
360
|
-
const originFilePath = findFileInDir(
|
401
|
+
const originFilePath = await findFileInDir(
|
361
402
|
path.join(workDir, ORIGIN_FILE_DIR),
|
362
403
|
fileName
|
363
404
|
);
|
405
|
+
const getPathEndTime = new Date();
|
406
|
+
const timeInSeconds = ((getPathEndTime - getPathStartTime) / 1000).toFixed(2);
|
407
|
+
|
408
|
+
logger(`第${index}条Path路径搜索时间:${timeInSeconds}秒`);
|
409
|
+
logger(`-------------------${new Date()}------------------`);
|
410
|
+
|
364
411
|
console.log("originFilePath:" + originFilePath);
|
365
412
|
console.log("fileName:" + fileName);
|
366
413
|
|
@@ -373,6 +420,7 @@ const task = async (row, index) => {
|
|
373
420
|
const indexFilePath = path.join(workDir, "output", index + "");
|
374
421
|
|
375
422
|
try {
|
423
|
+
const workStartTime = new Date();
|
376
424
|
await fs_asnyc.access(originFilePath, fs_asnyc.constants.F_OK);
|
377
425
|
logFileSize(originFilePath);
|
378
426
|
await PriviewPhoto(indexFilePath, originFilePath, fileName);
|
@@ -388,10 +436,20 @@ const task = async (row, index) => {
|
|
388
436
|
keyword,
|
389
437
|
}
|
390
438
|
);
|
391
|
-
|
392
|
-
|
439
|
+
const workEndTime = new Date();
|
440
|
+
const timeInSeconds = ((workEndTime - workStartTime) / 1000).toFixed(2);
|
393
441
|
|
442
|
+
logger(`第${index}条4090处理总时间:${timeInSeconds}秒`);
|
443
|
+
logger(`-------------------${new Date()}------------------`);
|
444
|
+
|
445
|
+
const postStartTime = new Date();
|
394
446
|
const resData = await postData(dataParams, indexFilePath);
|
447
|
+
const postEndTime = new Date();
|
448
|
+
const timeInSeconds1 = ((postEndTime - postStartTime) / 1000).toFixed(2);
|
449
|
+
|
450
|
+
logger(`第${index}条接口处理总时间:${timeInSeconds1}秒`);
|
451
|
+
logger(`-------------------${new Date()}------------------`);
|
452
|
+
|
395
453
|
if (resData.data.code === 200) {
|
396
454
|
logger("请求成功!");
|
397
455
|
logger(resData.data.code);
|
@@ -432,23 +490,42 @@ const transitionExcelToJSON = () => {
|
|
432
490
|
const jsonData = readExcel(excelDir);
|
433
491
|
|
434
492
|
const run = (index) => {
|
435
|
-
|
436
|
-
|
437
|
-
|
493
|
+
try {
|
494
|
+
logger(
|
495
|
+
`run-------------------------------------第${index}条开始------------------------------------`
|
496
|
+
);
|
497
|
+
const readExcelStartTime = new Date();
|
498
|
+
const row = jsonData[index];
|
499
|
+
|
500
|
+
const readExcelEndTime = new Date();
|
501
|
+
const timeInSeconds = (
|
502
|
+
(readExcelEndTime - readExcelStartTime) /
|
503
|
+
1000
|
504
|
+
).toFixed(2);
|
505
|
+
|
506
|
+
logger(`第${index}条Excel搜索时间:${timeInSeconds}秒`);
|
507
|
+
logger(`-------------------${new Date()}------------------`);
|
508
|
+
if (!row) {
|
509
|
+
return;
|
510
|
+
}
|
511
|
+
logger(
|
512
|
+
`----------------------------------------第${index}条task开始--------------------------------`
|
513
|
+
);
|
514
|
+
logger(`-------------------${new Date()}------------------`);
|
515
|
+
task(row, index)
|
516
|
+
.then(() => {
|
517
|
+
taskIndex++;
|
518
|
+
run(taskIndex);
|
519
|
+
})
|
520
|
+
.catch(() => {
|
521
|
+
taskIndex++;
|
522
|
+
run(taskIndex);
|
523
|
+
});
|
524
|
+
} catch (error) {
|
525
|
+
logger("捕获错误!" + error);
|
526
|
+
taskIndex++;
|
527
|
+
run(taskIndex);
|
438
528
|
}
|
439
|
-
logger(
|
440
|
-
`----------------------------------------第${index}条开始------------------------------------`
|
441
|
-
);
|
442
|
-
logger(`-------------------${new Date()}------------------`);
|
443
|
-
task(row, index)
|
444
|
-
.then(() => {
|
445
|
-
taskIndex++;
|
446
|
-
run(taskIndex);
|
447
|
-
})
|
448
|
-
.catch(() => {
|
449
|
-
taskIndex++;
|
450
|
-
run(taskIndex);
|
451
|
-
});
|
452
529
|
};
|
453
530
|
|
454
531
|
for (let i = 0; i < queueCount; i++) {
|
@@ -0,0 +1,528 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
const XLSX = require("xlsx");
|
3
|
+
const ffmpeg = require("fluent-ffmpeg");
|
4
|
+
const fs = require("fs");
|
5
|
+
const path = require("path");
|
6
|
+
const fs_asnyc = require("fs").promises;
|
7
|
+
const archiver = require("archiver");
|
8
|
+
const axios = require("axios");
|
9
|
+
const generateUniqueHash = require("../utils/index");
|
10
|
+
const FormData = require("form-data");
|
11
|
+
|
12
|
+
//执行目录
|
13
|
+
const exeDir = __dirname;
|
14
|
+
//当前工作目录
|
15
|
+
const workDir = process.cwd();
|
16
|
+
|
17
|
+
// 表格目录
|
18
|
+
const excelDir = path.join(workDir, "excel", "excel.xlsx");
|
19
|
+
//水印
|
20
|
+
const watermarkImage = path.join(__dirname, "..", "imgs", "picWater.png");
|
21
|
+
|
22
|
+
// 截图数量
|
23
|
+
const SCREENSHOT_COUNT = 5;
|
24
|
+
const ORIGIN_FILE_DIR = "photos";
|
25
|
+
const PHOTO_PREVIEW_DIR = "preview_photo";
|
26
|
+
const ZIP_VIDEO_DIR = "zip_video";
|
27
|
+
const ZIP_VIDEO_DIR_400 = "small_video";
|
28
|
+
const SCREENSHOT_DIR = "preview_photo";
|
29
|
+
const SCREENSHOT_WATERMARK_DIR = "screenshots_watermark";
|
30
|
+
const ZIP_WATERMARK_VIDEO_DIR = "zip_watermark_video";
|
31
|
+
const ZIP_SCREENSHOT_WM_DIR = "preview_watermark_photo";
|
32
|
+
const SOURCE_PHOTO_DIR = "source_photo";
|
33
|
+
const ZIP_FILES_DIR = "zip";
|
34
|
+
|
35
|
+
const expandedName = ".jpg";
|
36
|
+
|
37
|
+
//并发数量
|
38
|
+
const queueCount = 50;
|
39
|
+
|
40
|
+
//起始任务下标
|
41
|
+
let taskIndex = 146451;
|
42
|
+
|
43
|
+
const readExcel = (path) => {
|
44
|
+
const workbook = XLSX.readFile(path);
|
45
|
+
|
46
|
+
// 获取第一个工作表(Sheet)
|
47
|
+
const firstSheetName = workbook.SheetNames[0];
|
48
|
+
const worksheet = workbook.Sheets[firstSheetName];
|
49
|
+
|
50
|
+
// 将工作表转换为 JSON 对象
|
51
|
+
const jsonData = XLSX.utils.sheet_to_json(worksheet);
|
52
|
+
return jsonData;
|
53
|
+
};
|
54
|
+
|
55
|
+
function logFileSize(path) {
|
56
|
+
const fileSize = fs.statSync(path).size / (1024 * 1024);
|
57
|
+
const formattedSize = fileSize.toFixed(2); // 保留两位小数
|
58
|
+
logger(`图片大小:${formattedSize}M`);
|
59
|
+
}
|
60
|
+
|
61
|
+
//普通日志
|
62
|
+
const logger = (log, hash, err) => {
|
63
|
+
console.log(log);
|
64
|
+
fs.writeFileSync("logBack.txt", log + "\n", {
|
65
|
+
flag: "a",
|
66
|
+
});
|
67
|
+
};
|
68
|
+
|
69
|
+
//错误日志
|
70
|
+
const disposeError = (err) => {
|
71
|
+
logger("---任务失败---", err);
|
72
|
+
logger(
|
73
|
+
`******************************************************************end`
|
74
|
+
);
|
75
|
+
fs.writeFileSync("error.txt", err + "\n", {
|
76
|
+
flag: "a",
|
77
|
+
});
|
78
|
+
};
|
79
|
+
|
80
|
+
/**
|
81
|
+
* 递归遍历文件夹,查找文件
|
82
|
+
* @param {*} dir 文件夹路径
|
83
|
+
* @param {*} fileName 文件名称
|
84
|
+
* @returns string 匹配成功的文件路径
|
85
|
+
*/
|
86
|
+
function findFileInDir(dir, fileName) {
|
87
|
+
const files = fs.readdirSync(dir);
|
88
|
+
for (const file of files) {
|
89
|
+
const filePath = path.join(dir, file);
|
90
|
+
const stat = fs.statSync(filePath);
|
91
|
+
if (stat.isDirectory()) {
|
92
|
+
const result = findFileInDir(filePath, fileName);
|
93
|
+
if (result) {
|
94
|
+
return result;
|
95
|
+
}
|
96
|
+
} else if (file.startsWith(fileName) && file.endsWith(expandedName)) {
|
97
|
+
return filePath;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return null;
|
101
|
+
}
|
102
|
+
|
103
|
+
// function findFileInDir(dir, fileName) {
|
104
|
+
// return new Promise((resolve, reject) => {
|
105
|
+
// fs.readdir(dir, (err, files) => {
|
106
|
+
// if (err) {
|
107
|
+
// reject(err);
|
108
|
+
// return;
|
109
|
+
// }
|
110
|
+
|
111
|
+
// // 遍历目录中的文件和子目录
|
112
|
+
// for (const file of files) {
|
113
|
+
// const filePath = path.join(dir, file);
|
114
|
+
// fs.stat(filePath, (err, stat) => {
|
115
|
+
// if (err) {
|
116
|
+
// reject(err); // 如果获取文件状态出错,直接reject
|
117
|
+
// return;
|
118
|
+
// }
|
119
|
+
// if (stat.isDirectory()) {
|
120
|
+
// // 如果是目录,递归调用findFileInDir
|
121
|
+
// findFileInDir(filePath, fileName)
|
122
|
+
// .then(resolve) // 如果找到了目标文件,将结果resolve
|
123
|
+
// .catch(reject); // 如果在子目录中出错,将错误reject
|
124
|
+
// } else if (file.startsWith(fileName) && file.endsWith(expandedName)) {
|
125
|
+
// resolve(filePath); // 如果找到了目标文件,将结果resolve
|
126
|
+
// }
|
127
|
+
// });
|
128
|
+
// }
|
129
|
+
|
130
|
+
// // 如果遍历完了所有文件和子目录仍未找到目标文件,resolve一个null表示未找到
|
131
|
+
// resolve(null);
|
132
|
+
// });
|
133
|
+
// });
|
134
|
+
// }
|
135
|
+
|
136
|
+
/**
|
137
|
+
* 生成预览图 indexFilePath: output/0
|
138
|
+
* originFilePath E:\workspace\图片测试\photos\abc222.png
|
139
|
+
*/
|
140
|
+
const PriviewPhoto = (indexFilePath, originFilePath, fileName) => {
|
141
|
+
//存放预览图图的文件夹
|
142
|
+
const outputDir = path.join(indexFilePath, SCREENSHOT_DIR);
|
143
|
+
ensureDirSync(outputDir);
|
144
|
+
|
145
|
+
const outputFile = path.join(outputDir, fileName);
|
146
|
+
|
147
|
+
return new Promise((resolve, reject) => {
|
148
|
+
const watermarkScreenshotsComand = ffmpeg(originFilePath);
|
149
|
+
watermarkScreenshotsComand
|
150
|
+
.size("1280x?")
|
151
|
+
.output(outputFile)
|
152
|
+
.on("error", (err) => {
|
153
|
+
logger("截图预览图出错: " + err);
|
154
|
+
reject();
|
155
|
+
})
|
156
|
+
.on("end", () => {
|
157
|
+
logger("预览图完成: " + outputFile);
|
158
|
+
resolve();
|
159
|
+
})
|
160
|
+
.run();
|
161
|
+
});
|
162
|
+
};
|
163
|
+
|
164
|
+
/**
|
165
|
+
* 生成水印预览图
|
166
|
+
*/
|
167
|
+
const watermarkPriviewPhoto = (indexFilePath, originFilePath, fileName) => {
|
168
|
+
//存放水印截图的文件夹
|
169
|
+
const outputDir = path.join(indexFilePath, ZIP_SCREENSHOT_WM_DIR);
|
170
|
+
const inputDir = path.join(indexFilePath, SCREENSHOT_DIR, fileName);
|
171
|
+
ensureDirSync(outputDir);
|
172
|
+
|
173
|
+
const outputFile = path.join(outputDir, fileName);
|
174
|
+
|
175
|
+
return new Promise((resolve, reject) => {
|
176
|
+
const watermarkScreenshotsComand = ffmpeg(inputDir);
|
177
|
+
watermarkScreenshotsComand
|
178
|
+
.input(watermarkImage)
|
179
|
+
.complexFilter("overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2")
|
180
|
+
.output(outputFile)
|
181
|
+
.on("error", (err) => {
|
182
|
+
logger("截图添加水印出错: " + err);
|
183
|
+
reject();
|
184
|
+
})
|
185
|
+
.on("end", () => {
|
186
|
+
logger("截图水印添加完成: " + outputFile);
|
187
|
+
resolve();
|
188
|
+
})
|
189
|
+
.run();
|
190
|
+
});
|
191
|
+
};
|
192
|
+
|
193
|
+
/**
|
194
|
+
* 确保目录存在,如果不存在则创建它
|
195
|
+
*/
|
196
|
+
function ensureDirSync(dirpath) {
|
197
|
+
try {
|
198
|
+
if (!fs.existsSync(dirpath)) {
|
199
|
+
fs.mkdirSync(dirpath, { recursive: true });
|
200
|
+
logger(`目录创建成功:${dirpath}`);
|
201
|
+
}
|
202
|
+
} catch (err) {
|
203
|
+
logger(`创建目录时出错:${err}`);
|
204
|
+
throw err;
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
/**
|
209
|
+
* 打包物料
|
210
|
+
*/
|
211
|
+
const archiveZip = (fileName, inputPath, originFilePath) => {
|
212
|
+
const zipDir = path.join(inputPath, "zip");
|
213
|
+
const timestamp = new Date().getTime();
|
214
|
+
|
215
|
+
ensureDirSync(zipDir);
|
216
|
+
const zipStream = fs.createWriteStream(
|
217
|
+
path.join(zipDir, `package${timestamp}.zip`)
|
218
|
+
);
|
219
|
+
const archive = archiver("zip", {
|
220
|
+
zlib: { level: 9 },
|
221
|
+
});
|
222
|
+
|
223
|
+
return new Promise((resolve, reject) => {
|
224
|
+
zipStream.on("close", function () {
|
225
|
+
logger("压缩数据:" + archive.pointer() + " total bytes");
|
226
|
+
logger(
|
227
|
+
"完成归档archiver has been finalized and the output file descriptor has closed."
|
228
|
+
);
|
229
|
+
resolve();
|
230
|
+
});
|
231
|
+
|
232
|
+
archive.on("warning", function (err) {
|
233
|
+
if (err.code === "ENOENT") {
|
234
|
+
logger("压缩-warning:" + err);
|
235
|
+
} else {
|
236
|
+
throw err;
|
237
|
+
}
|
238
|
+
});
|
239
|
+
|
240
|
+
archive.on("error", function (err) {
|
241
|
+
logger("压缩失败!" + err);
|
242
|
+
reject();
|
243
|
+
});
|
244
|
+
|
245
|
+
archive.pipe(zipStream);
|
246
|
+
const directories = [ZIP_SCREENSHOT_WM_DIR, SCREENSHOT_DIR];
|
247
|
+
|
248
|
+
directories.forEach((dir) => {
|
249
|
+
const dirPath = path.join(inputPath, dir);
|
250
|
+
archive.directory(dirPath, dir);
|
251
|
+
});
|
252
|
+
|
253
|
+
archive.file(originFilePath, {
|
254
|
+
name: path.join(SOURCE_PHOTO_DIR, fileName),
|
255
|
+
});
|
256
|
+
// 完成归档
|
257
|
+
archive.finalize();
|
258
|
+
});
|
259
|
+
};
|
260
|
+
|
261
|
+
/**
|
262
|
+
* 获取 元数据
|
263
|
+
*/
|
264
|
+
const getMetadata = async (
|
265
|
+
fileName,
|
266
|
+
indexFilePath,
|
267
|
+
originFilePath,
|
268
|
+
{ rowFileName, title, keyword }
|
269
|
+
) => {
|
270
|
+
//源图片数据
|
271
|
+
const photoMetadataComand = ffmpeg(originFilePath);
|
272
|
+
//预览图数据
|
273
|
+
const photoInputPath = path.join(indexFilePath, SCREENSHOT_DIR, fileName);
|
274
|
+
const photoPreviewMetadataComand = ffmpeg(photoInputPath);
|
275
|
+
|
276
|
+
const metaDataParams = {
|
277
|
+
photo_id: rowFileName,
|
278
|
+
width: "",
|
279
|
+
height: "",
|
280
|
+
format: "",
|
281
|
+
size: "",
|
282
|
+
pr: 160,
|
283
|
+
dpi: 0,
|
284
|
+
is_government: 0,
|
285
|
+
common_width: "",
|
286
|
+
common_height: "",
|
287
|
+
dujia: 0,
|
288
|
+
xiaoxiang: 0,
|
289
|
+
title,
|
290
|
+
keyword,
|
291
|
+
en_keyword: "",
|
292
|
+
// preview_path: "",
|
293
|
+
// markImage_path: "",
|
294
|
+
// photo_path: "",
|
295
|
+
// common_image_path: "",
|
296
|
+
// en_keyword: "",
|
297
|
+
plate_id: 3,
|
298
|
+
transform_plate_id: 3,
|
299
|
+
tag_id: 47,
|
300
|
+
userid: 1003,
|
301
|
+
username: "美好景象",
|
302
|
+
demand_kind: 3,
|
303
|
+
source_from: 71,
|
304
|
+
file: "",
|
305
|
+
};
|
306
|
+
|
307
|
+
await new Promise((resolve, reject) => {
|
308
|
+
photoMetadataComand.ffprobe(function (err, metadata) {
|
309
|
+
// console.log("metadata");
|
310
|
+
// console.log(JSON.stringify(metadata));
|
311
|
+
if (metadata) {
|
312
|
+
const formatStream = metadata.format;
|
313
|
+
const photoStream = metadata.streams.find(
|
314
|
+
(s) => s.codec_type === "video"
|
315
|
+
);
|
316
|
+
|
317
|
+
metaDataParams.width = photoStream.width;
|
318
|
+
metaDataParams.height = photoStream.height;
|
319
|
+
// metaDataParams.format = formatStream.format_name;
|
320
|
+
metaDataParams.format = "jpg";
|
321
|
+
metaDataParams.size = formatStream.size;
|
322
|
+
|
323
|
+
resolve();
|
324
|
+
} else {
|
325
|
+
reject(err);
|
326
|
+
}
|
327
|
+
});
|
328
|
+
});
|
329
|
+
await new Promise((resolve, reject) => {
|
330
|
+
photoPreviewMetadataComand.ffprobe(function (err, metadata) {
|
331
|
+
if (metadata) {
|
332
|
+
const photoStream = metadata.streams.find(
|
333
|
+
(s) => s.codec_type === "video"
|
334
|
+
);
|
335
|
+
|
336
|
+
metaDataParams.common_width = photoStream.width;
|
337
|
+
metaDataParams.common_height = photoStream.height;
|
338
|
+
resolve();
|
339
|
+
} else {
|
340
|
+
reject(err);
|
341
|
+
}
|
342
|
+
});
|
343
|
+
});
|
344
|
+
|
345
|
+
return metaDataParams;
|
346
|
+
};
|
347
|
+
|
348
|
+
/**
|
349
|
+
* 接口
|
350
|
+
*/
|
351
|
+
const postData = (dataParams, indexFilePath) => {
|
352
|
+
const formData = new FormData();
|
353
|
+
|
354
|
+
const zipFiles = fs
|
355
|
+
.readdirSync(path.join(indexFilePath, ZIP_FILES_DIR))
|
356
|
+
.find((file) => file.endsWith(".zip"));
|
357
|
+
|
358
|
+
const packageZip = path.join(indexFilePath, ZIP_FILES_DIR, zipFiles);
|
359
|
+
|
360
|
+
formData.append("file", fs.createReadStream(packageZip));
|
361
|
+
for (const key in dataParams) {
|
362
|
+
if (Object.hasOwnProperty.call(dataParams, key)) {
|
363
|
+
const value = dataParams[key];
|
364
|
+
formData.append(key, value);
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
logger("等待接口返回结果……");
|
369
|
+
|
370
|
+
// return axios.post("http://192.168.102.61:9999/upload/photo", formData, {
|
371
|
+
return axios.post("http://127.0.0.1:9999/upload/photo", formData, {
|
372
|
+
headers: {
|
373
|
+
"Content-Type": "multipart/form-data",
|
374
|
+
},
|
375
|
+
timeout: 300000,
|
376
|
+
});
|
377
|
+
};
|
378
|
+
|
379
|
+
/**
|
380
|
+
* 任务
|
381
|
+
*/
|
382
|
+
const task = async (row, index) => {
|
383
|
+
logger(
|
384
|
+
"**************************" + row.fileName + "**************************"
|
385
|
+
);
|
386
|
+
// Excel的列名分别为: fileName title keyword
|
387
|
+
// 表格中文件名无后缀,遂手动添加写死为mp4
|
388
|
+
let fileName = row.fileName;
|
389
|
+
const rowFileName = row.fileName;
|
390
|
+
const title = row.title;
|
391
|
+
const keywordArr = row.keyword.split(",");
|
392
|
+
const filteredArray = keywordArr.filter((item) => item.trim() !== "");
|
393
|
+
const keyword = filteredArray.join(" ");
|
394
|
+
|
395
|
+
if (!fileName.includes(".")) {
|
396
|
+
fileName = row.fileName + expandedName;
|
397
|
+
}
|
398
|
+
|
399
|
+
const getPathStartTime = new Date();
|
400
|
+
// 源图片文件夹路径
|
401
|
+
const originFilePath = await findFileInDir(
|
402
|
+
path.join(workDir, ORIGIN_FILE_DIR),
|
403
|
+
fileName
|
404
|
+
);
|
405
|
+
const getPathEndTime = new Date();
|
406
|
+
const timeInSeconds = ((getPathEndTime - getPathStartTime) / 1000).toFixed(2);
|
407
|
+
|
408
|
+
logger(`第${index}条Path路径搜索时间:${timeInSeconds}秒`);
|
409
|
+
logger(`-------------------${new Date()}------------------`);
|
410
|
+
|
411
|
+
console.log("originFilePath:" + originFilePath);
|
412
|
+
console.log("fileName:" + fileName);
|
413
|
+
|
414
|
+
if (!originFilePath) {
|
415
|
+
logger(`图片文件 ${fileName} 不存在`);
|
416
|
+
return;
|
417
|
+
}
|
418
|
+
|
419
|
+
//index文件夹 output/0
|
420
|
+
const indexFilePath = path.join(workDir, "output", index + "");
|
421
|
+
|
422
|
+
try {
|
423
|
+
const workStartTime = new Date();
|
424
|
+
await fs_asnyc.access(originFilePath, fs_asnyc.constants.F_OK);
|
425
|
+
logFileSize(originFilePath);
|
426
|
+
await PriviewPhoto(indexFilePath, originFilePath, fileName);
|
427
|
+
await watermarkPriviewPhoto(indexFilePath, originFilePath, fileName);
|
428
|
+
await archiveZip(fileName, indexFilePath, originFilePath);
|
429
|
+
const dataParams = await getMetadata(
|
430
|
+
fileName,
|
431
|
+
indexFilePath,
|
432
|
+
originFilePath,
|
433
|
+
{
|
434
|
+
rowFileName,
|
435
|
+
title,
|
436
|
+
keyword,
|
437
|
+
}
|
438
|
+
);
|
439
|
+
const workEndTime = new Date();
|
440
|
+
const timeInSeconds = ((workEndTime - workStartTime) / 1000).toFixed(2);
|
441
|
+
|
442
|
+
logger(`第${index}条4090处理总时间:${timeInSeconds}秒`);
|
443
|
+
logger(`-------------------${new Date()}------------------`);
|
444
|
+
|
445
|
+
const postStartTime = new Date();
|
446
|
+
const resData = await postData(dataParams, indexFilePath);
|
447
|
+
const postEndTime = new Date();
|
448
|
+
const timeInSeconds1 = ((postEndTime - postStartTime) / 1000).toFixed(2);
|
449
|
+
|
450
|
+
logger(`第${index}条接口处理总时间:${timeInSeconds1}秒`);
|
451
|
+
logger(`-------------------${new Date()}------------------`);
|
452
|
+
|
453
|
+
if (resData.data.code === 200) {
|
454
|
+
logger("请求成功!");
|
455
|
+
logger(resData.data.code);
|
456
|
+
console.log(resData.data);
|
457
|
+
//删除文件夹
|
458
|
+
fs.rmdirSync(indexFilePath, { recursive: true });
|
459
|
+
} else {
|
460
|
+
throw new Error("请求失败!" + resData.data.msg);
|
461
|
+
}
|
462
|
+
|
463
|
+
logger(
|
464
|
+
`----------------------------------------第${index}条结束---------------------------------end`
|
465
|
+
);
|
466
|
+
} catch (error) {
|
467
|
+
// 可以约定code,来表示不同的错误信息
|
468
|
+
if (error.code === "ENOENT") {
|
469
|
+
logger(`图片文件 ${fileName} 不存在`);
|
470
|
+
} else {
|
471
|
+
logger("图片任务处理失败:" + error);
|
472
|
+
logger(error);
|
473
|
+
}
|
474
|
+
fs.rmdirSync(indexFilePath, { recursive: true });
|
475
|
+
disposeError(fileName);
|
476
|
+
}
|
477
|
+
};
|
478
|
+
|
479
|
+
/**
|
480
|
+
* 解析Excel数据
|
481
|
+
*/
|
482
|
+
const transitionExcelToJSON = () => {
|
483
|
+
//当前任务hash
|
484
|
+
const hashOrigin = generateUniqueHash();
|
485
|
+
const hash = hashOrigin.slice(0, 8);
|
486
|
+
logger("图片批量任务任务开始---" + hash);
|
487
|
+
logger("当前目录: " + workDir);
|
488
|
+
logger("工作目录: " + __dirname);
|
489
|
+
|
490
|
+
const jsonData = readExcel(excelDir);
|
491
|
+
|
492
|
+
const run = (index) => {
|
493
|
+
try {
|
494
|
+
logger(
|
495
|
+
`run-------------------------------------倒序第${index}条开始------------------------------------`
|
496
|
+
);
|
497
|
+
const row = jsonData[index];
|
498
|
+
|
499
|
+
logger(`-------------------${new Date()}------------------`);
|
500
|
+
if (!row) {
|
501
|
+
return;
|
502
|
+
}
|
503
|
+
|
504
|
+
task(row, index)
|
505
|
+
.then(() => {
|
506
|
+
taskIndex--;
|
507
|
+
run(taskIndex);
|
508
|
+
})
|
509
|
+
.catch(() => {
|
510
|
+
taskIndex--;
|
511
|
+
run(taskIndex);
|
512
|
+
});
|
513
|
+
} catch (error) {
|
514
|
+
logger("捕获错误!" + error);
|
515
|
+
taskIndex--;
|
516
|
+
run(taskIndex);
|
517
|
+
}
|
518
|
+
};
|
519
|
+
|
520
|
+
for (let i = jsonData.length; i > 0; i--) {
|
521
|
+
run(i);
|
522
|
+
}
|
523
|
+
for (let i = 0; i < queueCount; i++) {
|
524
|
+
run(taskIndex - i);
|
525
|
+
}
|
526
|
+
};
|
527
|
+
|
528
|
+
transitionExcelToJSON();
|