tools_batch_files 1.0.30 → 1.0.32
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 -1
- package/src/audioFn/audioBatch.js +107 -57
- package/utils/logger.js +44 -7
- package/utils/settleFiles.js +31 -0
- package/vocal_print/3600a.mp3 +0 -0
- package/vocal_print/800a.mp3 +0 -0
- package/vocal_print/mz.mp3 +0 -0
- package//347/202/271/346/210/221/346/211/271/351/207/217/344/270/212/344/274/240/345/233/276/347/211/207.bat +1 -1
- package//347/202/271/346/210/221/346/211/271/351/207/217/344/270/212/344/274/240/351/237/263/351/242/221.bat +3 -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.32",
|
4
4
|
"description": "批处理视频工具",
|
5
5
|
"keywords": [
|
6
6
|
"utils",
|
@@ -34,8 +34,10 @@
|
|
34
34
|
"files": [
|
35
35
|
"index.js",
|
36
36
|
"imgs",
|
37
|
+
"vocal_print",
|
37
38
|
"点我批量上传视频.bat",
|
38
39
|
"点我批量上传图片.bat",
|
40
|
+
"点我批量上传音频.bat",
|
39
41
|
"package.json",
|
40
42
|
"package-lock.json",
|
41
43
|
"utils",
|
@@ -1,11 +1,19 @@
|
|
1
|
-
|
2
|
-
const
|
1
|
+
#!/usr/bin/env node
|
2
|
+
const generateUniqueHash = require("../../utils/index");
|
3
|
+
const {
|
4
|
+
disposeError,
|
5
|
+
readExcel,
|
6
|
+
logger,
|
7
|
+
successLogger,
|
8
|
+
} = require("../../utils/logger");
|
3
9
|
|
4
10
|
const {
|
5
11
|
findFileInDir,
|
6
12
|
logFileSize,
|
7
13
|
ensureDirSync,
|
8
|
-
|
14
|
+
isExist,
|
15
|
+
readTxt,
|
16
|
+
} = require("../../utils/settleFiles");
|
9
17
|
const ffmpeg = require("fluent-ffmpeg");
|
10
18
|
const fs = require("fs");
|
11
19
|
const path = require("path");
|
@@ -15,7 +23,7 @@ const axios = require("axios");
|
|
15
23
|
const FormData = require("form-data");
|
16
24
|
|
17
25
|
//并发数量
|
18
|
-
const queueCount =
|
26
|
+
const queueCount = 10;
|
19
27
|
|
20
28
|
//起始任务下标
|
21
29
|
let taskIndex = 0;
|
@@ -39,12 +47,12 @@ const watermarkAudioPath = path.join(__dirname, "..", "vocal_print", "mz.mp3");
|
|
39
47
|
const longWatermarkAudioPath = path.join(
|
40
48
|
__dirname,
|
41
49
|
"..",
|
50
|
+
"..",
|
42
51
|
"vocal_print",
|
43
52
|
"800a.mp3"
|
44
53
|
);
|
45
54
|
|
46
55
|
const maxRetries = 1; // 最大重试次数
|
47
|
-
let retryCount = 0; // 当前重试次数
|
48
56
|
|
49
57
|
/**
|
50
58
|
* 声纹
|
@@ -259,9 +267,9 @@ const postData = (dataParams, indexFilePath) => {
|
|
259
267
|
|
260
268
|
logger("等待接口返回结果……");
|
261
269
|
|
262
|
-
// return axios.post("http://127.0.0.1:9999/upload/photo", formData, {
|
263
270
|
// return axios.post("http://192.168.102.61:9999/upload/sound", formData, {
|
264
|
-
return axios.post("http://192.168.101.149:9999/upload/sound", formData, {
|
271
|
+
// return axios.post("http://192.168.101.149:9999/upload/sound", formData, {
|
272
|
+
return axios.post("http://127.0.0.1:9999/upload/sound", formData, {
|
265
273
|
headers: {
|
266
274
|
"Content-Type": "multipart/form-data",
|
267
275
|
},
|
@@ -272,30 +280,42 @@ const postData = (dataParams, indexFilePath) => {
|
|
272
280
|
/**
|
273
281
|
* 接口重试机制
|
274
282
|
*/
|
275
|
-
async function postDataWithRetry(
|
283
|
+
async function postDataWithRetry(
|
284
|
+
dataParams,
|
285
|
+
indexFilePath,
|
286
|
+
index,
|
287
|
+
fileName,
|
288
|
+
hash
|
289
|
+
) {
|
290
|
+
let retryCount = 0; // 当前重试次数
|
291
|
+
|
276
292
|
while (retryCount < maxRetries) {
|
277
293
|
try {
|
278
294
|
const resData = await postData(dataParams, indexFilePath);
|
279
295
|
if (resData.data.code === 200) {
|
280
296
|
logger("请求成功!");
|
281
|
-
logger(resData.data);
|
297
|
+
logger(resData.data.code);
|
298
|
+
// 文件名和索引值
|
299
|
+
successLogger(hash, index, fileName);
|
282
300
|
fs.rmdirSync(indexFilePath, { recursive: true });
|
283
|
-
return;
|
301
|
+
return;
|
284
302
|
} else if (resData.data.code === 300) {
|
285
303
|
// 重复上传,不捕获此错误
|
286
304
|
logger(`第${index}条文件-${index}重复上传!`);
|
287
305
|
fs.rmdirSync(indexFilePath, { recursive: true });
|
288
|
-
return;
|
306
|
+
return;
|
289
307
|
} else {
|
290
308
|
// 其他错误,抛出异常
|
291
|
-
throw new Error(
|
309
|
+
throw new Error(
|
310
|
+
"请求code!==200:" + resData.data.code + resData.data.msg
|
311
|
+
);
|
292
312
|
}
|
293
313
|
} catch (error) {
|
294
314
|
logger(`请求失败,重试中... (${retryCount + 1}/${maxRetries})`);
|
295
315
|
logger(error);
|
296
316
|
retryCount++;
|
297
317
|
// 延时等待一段时间后再进行重试
|
298
|
-
await new Promise((resolve) => setTimeout(resolve, 100)); // 等待1秒
|
318
|
+
await new Promise((resolve) => setTimeout(resolve, 100)); // 等待0.1秒
|
299
319
|
}
|
300
320
|
}
|
301
321
|
// 如果达到最大重试次数仍然失败,则抛出异常
|
@@ -305,7 +325,7 @@ async function postDataWithRetry(dataParams, indexFilePath) {
|
|
305
325
|
/**
|
306
326
|
* 任务
|
307
327
|
*/
|
308
|
-
const task = async (row, index) => {
|
328
|
+
const task = async (row, index, hash) => {
|
309
329
|
try {
|
310
330
|
logger(
|
311
331
|
"**************************" + row.fileName + "**************************"
|
@@ -313,12 +333,11 @@ const task = async (row, index) => {
|
|
313
333
|
// Excel的列名分别为: fileName title keyword
|
314
334
|
let fileName = row.fileName;
|
315
335
|
const title = row.title;
|
336
|
+
const keyword = row.keyword;
|
316
337
|
// const keywordArr = row.keyword.split(",");
|
317
338
|
// const filteredArray = keywordArr.filter((item) => item.trim() !== "");
|
318
339
|
// const keyword = filteredArray.join(" ");
|
319
340
|
|
320
|
-
const keyword = row.keyword;
|
321
|
-
|
322
341
|
if (!fileName.includes(".")) {
|
323
342
|
fileName = row.fileName + ".mp3";
|
324
343
|
}
|
@@ -348,7 +367,6 @@ const task = async (row, index) => {
|
|
348
367
|
//index文件夹 output/0
|
349
368
|
const indexFilePath = path.join(workDir, "output", index + "");
|
350
369
|
|
351
|
-
const workStartTime = new Date();
|
352
370
|
await fs_asnyc.access(originFilePath, fs_asnyc.constants.F_OK);
|
353
371
|
logFileSize(originFilePath);
|
354
372
|
const dataParams = await getMetadata(
|
@@ -368,14 +386,9 @@ const task = async (row, index) => {
|
|
368
386
|
dataParams.duration
|
369
387
|
);
|
370
388
|
await archiveZip(fileName, indexFilePath, originFilePath);
|
371
|
-
const workEndTime = new Date();
|
372
|
-
const timeInSeconds = ((workEndTime - workStartTime) / 1000).toFixed(2);
|
373
|
-
|
374
|
-
logger(`第${index}条4090处理总时间:${timeInSeconds}秒`);
|
375
|
-
logger(`-------------------${new Date()}------------------`);
|
376
389
|
|
377
390
|
// 重试机制
|
378
|
-
await postDataWithRetry(dataParams, indexFilePath);
|
391
|
+
await postDataWithRetry(dataParams, indexFilePath, index, fileName, hash);
|
379
392
|
|
380
393
|
logger(
|
381
394
|
`----------------------------------------第${index}条结束---------------------------------end`
|
@@ -385,55 +398,92 @@ const task = async (row, index) => {
|
|
385
398
|
if (error.code === "ENOENT") {
|
386
399
|
logger(`音频文件 ${fileName} 不存在`);
|
387
400
|
} else {
|
388
|
-
logger("
|
401
|
+
logger("音频任务失败(最外层catch):" + error);
|
389
402
|
}
|
390
403
|
fs.rmdirSync(indexFilePath, { recursive: true });
|
391
|
-
disposeError(fileName);
|
404
|
+
disposeError(hash, { fileName, keyword, title });
|
392
405
|
|
393
406
|
//失败的时候,复制文件到错误文件夹中
|
394
|
-
const failPath = path.join(workDir, Error_Files_Dir, fileName);
|
395
|
-
moveFailFiles(originFilePath, failPath);
|
407
|
+
// const failPath = path.join(workDir, Error_Files_Dir, fileName);
|
408
|
+
// moveFailFiles(originFilePath, failPath);
|
409
|
+
}
|
410
|
+
};
|
411
|
+
|
412
|
+
const run = (index, data, hash) => {
|
413
|
+
try {
|
414
|
+
logger(
|
415
|
+
`run-------------------------------------第${index}条开始------------------------------------`
|
416
|
+
);
|
417
|
+
const row = data[index];
|
418
|
+
|
419
|
+
if (!row) {
|
420
|
+
taskIndex = 0;
|
421
|
+
logger("当前任务,最后一条已结束!");
|
422
|
+
|
423
|
+
// 是否存在错误列表? 存在的话,继续遍历
|
424
|
+
const errorExcelPath = path.join(workDir, `error${hash}.xlsx`);
|
425
|
+
if (isExist(errorExcelPath)) {
|
426
|
+
const jsonData2 = readExcel(errorExcelPath);
|
427
|
+
queue(taskIndex, jsonData2, hash);
|
428
|
+
} else {
|
429
|
+
logger("跑干了!");
|
430
|
+
}
|
431
|
+
|
432
|
+
return;
|
433
|
+
}
|
434
|
+
|
435
|
+
task(row, index)
|
436
|
+
.then(() => {
|
437
|
+
taskIndex++;
|
438
|
+
run(taskIndex, data, hash);
|
439
|
+
})
|
440
|
+
.catch((err) => {
|
441
|
+
throw new Error("task失败:" + err);
|
442
|
+
});
|
443
|
+
} catch (error) {
|
444
|
+
logger("捕获错误!" + error);
|
445
|
+
taskIndex++;
|
446
|
+
run(taskIndex, data, hash);
|
447
|
+
}
|
448
|
+
};
|
449
|
+
|
450
|
+
const queue = (taskIndex, jsonData, hash) => {
|
451
|
+
for (let i = 0; i < queueCount; i++) {
|
452
|
+
run(i + taskIndex, jsonData, hash);
|
396
453
|
}
|
397
454
|
};
|
398
455
|
|
399
456
|
const main = () => {
|
400
457
|
//当前任务hash
|
401
|
-
|
402
|
-
|
458
|
+
let hash = "";
|
459
|
+
let jsonData = [];
|
403
460
|
logger("音频批量任务任务开始---" + hash);
|
404
|
-
logger("当前目录: " + workDir + "
|
461
|
+
logger("当前目录: " + workDir + ";工作目录: " + exeDir);
|
405
462
|
|
406
|
-
|
463
|
+
// 读取success.txt,判断是否是 异常中断,
|
464
|
+
// 并根据success日志获取最后一行的hash,找到对应的error_hash_excel
|
407
465
|
|
408
|
-
const
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
const row = jsonData[index];
|
466
|
+
const successPath = path.join(workDir, "success.txt");
|
467
|
+
if (isExist(successPath)) {
|
468
|
+
const { loghash, lastItemIndex } = readTxt(successPath);
|
469
|
+
const errorExcelPath = path.join(workDir, `error${loghash}.xlsx`);
|
470
|
+
logger("成功日志存在,异常中断或者跑完了。");
|
414
471
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
})
|
424
|
-
.catch(() => {
|
425
|
-
taskIndex++;
|
426
|
-
run(taskIndex);
|
427
|
-
});
|
428
|
-
} catch (error) {
|
429
|
-
logger("捕获错误!" + error);
|
430
|
-
taskIndex++;
|
431
|
-
run(taskIndex);
|
472
|
+
hash = loghash;
|
473
|
+
taskIndex = lastItemIndex + 1; // lastItemIndex为最后一项,所有要+1
|
474
|
+
|
475
|
+
if (isExist(errorExcelPath)) {
|
476
|
+
jsonData = readExcel(errorExcelPath); // 数据来源于error excel
|
477
|
+
queue(taskIndex, jsonData, hash);
|
478
|
+
} else {
|
479
|
+
logger("跑干了!");
|
432
480
|
}
|
433
|
-
}
|
481
|
+
} else {
|
482
|
+
hash = generateUniqueHash().slice(0, 8);
|
483
|
+
logger("成功日志不存在,开始新任务");
|
434
484
|
|
435
|
-
|
436
|
-
|
485
|
+
jsonData = readExcel(excelDir);
|
486
|
+
queue(taskIndex, jsonData, hash);
|
437
487
|
}
|
438
488
|
};
|
439
489
|
|
package/utils/logger.js
CHANGED
@@ -13,17 +13,53 @@ const logger = (log) => {
|
|
13
13
|
});
|
14
14
|
};
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
);
|
22
|
-
fs.writeFileSync("
|
16
|
+
/**
|
17
|
+
* 成功日志
|
18
|
+
* @param {*} 日志内容 hash index fileName
|
19
|
+
*/
|
20
|
+
const successLogger = (hash, index, fileName) => {
|
21
|
+
console.log(log);
|
22
|
+
fs.writeFileSync("success.txt", hash + " " + index + " " + fileName + "\n", {
|
23
23
|
flag: "a",
|
24
24
|
});
|
25
25
|
};
|
26
26
|
|
27
|
+
//错误日志- xlsx
|
28
|
+
const disposeError = (hash, { fileName, keyword, title }) => {
|
29
|
+
// 构建 Excel 数据
|
30
|
+
const data = [[fileName, keyword, title]]; // 不包含表头
|
31
|
+
|
32
|
+
// 读取已存在的 Excel 文件
|
33
|
+
let existingData = [];
|
34
|
+
let existingWb;
|
35
|
+
try {
|
36
|
+
existingWb = XLSX.readFile(`error${hash}.xlsx`);
|
37
|
+
existingData = XLSX.utils.sheet_to_json(
|
38
|
+
existingWb.Sheets[existingWb.SheetNames[0]],
|
39
|
+
{ header: 1 }
|
40
|
+
);
|
41
|
+
} catch (error) {
|
42
|
+
logger("No existing file found, creating new one.");
|
43
|
+
// 如果文件不存在,添加表头
|
44
|
+
existingData.push(["fileName", "keyword", "title"]);
|
45
|
+
}
|
46
|
+
|
47
|
+
// 合并已有数据和新数据
|
48
|
+
const combinedData = existingData.concat(data);
|
49
|
+
|
50
|
+
// 创建新的 sheet
|
51
|
+
const newWs = XLSX.utils.aoa_to_sheet(combinedData);
|
52
|
+
|
53
|
+
// 创建新的 workbook
|
54
|
+
const wb = XLSX.utils.book_new();
|
55
|
+
|
56
|
+
// 将新的 sheet 添加到 workbook
|
57
|
+
XLSX.utils.book_append_sheet(wb, newWs, "Error Details");
|
58
|
+
|
59
|
+
// 保存 Excel 文件
|
60
|
+
XLSX.writeFile(wb, `error${hash}.xlsx`);
|
61
|
+
};
|
62
|
+
|
27
63
|
/**
|
28
64
|
* 读取Excel
|
29
65
|
* @param {*} path Excel路径
|
@@ -45,4 +81,5 @@ module.exports = {
|
|
45
81
|
readExcel,
|
46
82
|
logger,
|
47
83
|
disposeError,
|
84
|
+
successLogger,
|
48
85
|
};
|
package/utils/settleFiles.js
CHANGED
@@ -40,6 +40,19 @@ function ensureDirSync(dirpath) {
|
|
40
40
|
}
|
41
41
|
}
|
42
42
|
|
43
|
+
/**
|
44
|
+
* 判断文件是否存在
|
45
|
+
*/
|
46
|
+
function isExist(filePath) {
|
47
|
+
fs.access(filePath, fs.constants.F_OK, (err) => {
|
48
|
+
if (err) {
|
49
|
+
return false;
|
50
|
+
} else {
|
51
|
+
return true;
|
52
|
+
}
|
53
|
+
});
|
54
|
+
}
|
55
|
+
|
43
56
|
/**
|
44
57
|
* 上传失败后,存入新文件夹(手动创建)
|
45
58
|
*/
|
@@ -50,9 +63,27 @@ const moveFailFiles = (originFilePath, failPath) => {
|
|
50
63
|
}
|
51
64
|
};
|
52
65
|
|
66
|
+
//数组 item为:hash index fileName
|
67
|
+
function readTxt(path) {
|
68
|
+
try {
|
69
|
+
const data = fs.readFileSync(path, "utf-8");
|
70
|
+
const arr = data.split("\n").map((line) => line.trim()); // 删除每行两侧的空白符
|
71
|
+
const lastItem = arr[arr.length - 1];
|
72
|
+
|
73
|
+
const loghash = lastItem.split(" ")[0];
|
74
|
+
const lastItemIndex = lastItem.split(" ")[1];
|
75
|
+
return { loghash, lastItemIndex };
|
76
|
+
} catch (error) {
|
77
|
+
console.error("readErrorTxt函数出错:", error);
|
78
|
+
return {};
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
53
82
|
module.exports = {
|
54
83
|
findFileInDir,
|
55
84
|
logFileSize,
|
56
85
|
ensureDirSync,
|
57
86
|
moveFailFiles,
|
87
|
+
isExist,
|
88
|
+
readTxt,
|
58
89
|
};
|
Binary file
|
Binary file
|
Binary file
|