tools_batch_files 1.0.31 → 1.0.33

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tools_batch_files",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
4
4
  "description": "批处理视频工具",
5
5
  "keywords": [
6
6
  "utils",
@@ -1,11 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  const generateUniqueHash = require("../../utils/index");
3
- const { disposeError, readExcel, logger } = require("../../utils/logger");
3
+ const {
4
+ disposeError,
5
+ readExcel,
6
+ logger,
7
+ successLogger,
8
+ } = require("../../utils/logger");
4
9
 
5
10
  const {
6
11
  findFileInDir,
7
12
  logFileSize,
8
13
  ensureDirSync,
14
+ isExist,
15
+ readTxt,
9
16
  } = require("../../utils/settleFiles");
10
17
  const ffmpeg = require("fluent-ffmpeg");
11
18
  const fs = require("fs");
@@ -193,10 +200,8 @@ const archiveZip = (fileName, inputPath, originFilePath) => {
193
200
  * 获取 元数据
194
201
  */
195
202
  const getMetadata = async (
196
- fileName,
197
- indexFilePath,
198
203
  originFilePath,
199
- { rowFileName, title, keyword }
204
+ { rowFileName, title, keyword, index }
200
205
  ) => {
201
206
  //源音频数据
202
207
  const photoMetadataComand = ffmpeg(originFilePath);
@@ -214,6 +219,7 @@ const getMetadata = async (
214
219
  duration: "",
215
220
  tag_ids: "3",
216
221
  source_from: "sound_1",
222
+ anotherId: rowFileName + index,
217
223
  };
218
224
 
219
225
  await new Promise((resolve, reject) => {
@@ -261,8 +267,8 @@ const postData = (dataParams, indexFilePath) => {
261
267
  logger("等待接口返回结果……");
262
268
 
263
269
  // 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, {
265
- return axios.post("http://127.0.0.1:9999/upload/sound", formData, {
270
+ // return axios.post("http://127.0.0.1:9999/upload/sound", formData, {
271
+ return axios.post("http://192.168.101.149:9999/upload/sound", formData, {
266
272
  headers: {
267
273
  "Content-Type": "multipart/form-data",
268
274
  },
@@ -273,7 +279,13 @@ const postData = (dataParams, indexFilePath) => {
273
279
  /**
274
280
  * 接口重试机制
275
281
  */
276
- async function postDataWithRetry(dataParams, indexFilePath, index) {
282
+ async function postDataWithRetry(
283
+ dataParams,
284
+ indexFilePath,
285
+ index,
286
+ fileName,
287
+ hash
288
+ ) {
277
289
  let retryCount = 0; // 当前重试次数
278
290
 
279
291
  while (retryCount < maxRetries) {
@@ -281,24 +293,25 @@ async function postDataWithRetry(dataParams, indexFilePath, index) {
281
293
  const resData = await postData(dataParams, indexFilePath);
282
294
  if (resData.data.code === 200) {
283
295
  logger("请求成功!");
284
- logger(resData.data);
296
+ logger(resData.data.code);
297
+ // 文件名和索引值
298
+ successLogger(hash, index, fileName);
285
299
  fs.rmdirSync(indexFilePath, { recursive: true });
286
- return; // 请求成功,结束循环
300
+ return;
287
301
  } else if (resData.data.code === 300) {
288
302
  // 重复上传,不捕获此错误
289
303
  logger(`第${index}条文件-${index}重复上传!`);
290
304
  fs.rmdirSync(indexFilePath, { recursive: true });
291
- return; // 结束循环
305
+ return;
292
306
  } else {
293
- // 其他错误,抛出异常
294
- throw new Error("请求失败!" + resData.data);
307
+ logger(`请求失败,重试中... (${retryCount + 1}/${maxRetries})`);
308
+ logger(`请求code!==200: ${resData.data.code}${resData.data.msg}`);
309
+ // 延时等待一段时间后再进行重试
310
+ await new Promise((resolve) => setTimeout(resolve, 100)); // 等待0.1秒
311
+ retryCount++;
295
312
  }
296
313
  } catch (error) {
297
- logger(`请求失败,重试中... (${retryCount + 1}/${maxRetries})`);
298
- logger(error);
299
- retryCount++;
300
- // 延时等待一段时间后再进行重试
301
- await new Promise((resolve) => setTimeout(resolve, 100)); // 等待1秒
314
+ throw new Error("重试机制错误!" + error);
302
315
  }
303
316
  }
304
317
  // 如果达到最大重试次数仍然失败,则抛出异常
@@ -308,20 +321,22 @@ async function postDataWithRetry(dataParams, indexFilePath, index) {
308
321
  /**
309
322
  * 任务
310
323
  */
311
- const task = async (row, index) => {
324
+ const task = async (row, index, hash) => {
325
+ //index文件夹 output/0
326
+ const indexFilePath = path.join(workDir, "output", index + "");
327
+ let fileName = row.fileName;
328
+ const rowFileName = row.fileName;
329
+ const title = row.title;
330
+ const keyword = row.keyword;
312
331
  try {
313
332
  logger(
314
333
  "**************************" + row.fileName + "**************************"
315
334
  );
316
335
  // Excel的列名分别为: fileName title keyword
317
- let fileName = row.fileName;
318
- const title = row.title;
319
336
  // const keywordArr = row.keyword.split(",");
320
337
  // const filteredArray = keywordArr.filter((item) => item.trim() !== "");
321
338
  // const keyword = filteredArray.join(" ");
322
339
 
323
- const keyword = row.keyword;
324
-
325
340
  if (!fileName.includes(".")) {
326
341
  fileName = row.fileName + ".mp3";
327
342
  }
@@ -342,27 +357,21 @@ const task = async (row, index) => {
342
357
  logger(`-------------------${new Date()}------------------`);
343
358
 
344
359
  logger("原文件路径:" + originFilePath);
360
+ logger(`第${index}条原文件路径:${originFilePath}`);
345
361
 
346
362
  if (!originFilePath) {
347
- logger(`音频文件 ${fileName} 不存在`);
363
+ logger(`第${index}条音频文件 ${fileName} 不存在`);
348
364
  return;
349
365
  }
350
366
 
351
- //index文件夹 output/0
352
- const indexFilePath = path.join(workDir, "output", index + "");
353
-
354
- const workStartTime = new Date();
355
367
  await fs_asnyc.access(originFilePath, fs_asnyc.constants.F_OK);
356
- logFileSize(originFilePath);
357
- const dataParams = await getMetadata(
358
- fileName,
359
- indexFilePath,
360
- originFilePath,
361
- {
362
- title,
363
- keyword,
364
- }
365
- );
368
+ logFileSize(originFilePath, index);
369
+ const dataParams = await getMetadata(originFilePath, {
370
+ rowFileName,
371
+ title,
372
+ keyword,
373
+ index,
374
+ });
366
375
  await wavAudio(indexFilePath, originFilePath, fileName);
367
376
  await watermarkAudio(
368
377
  indexFilePath,
@@ -371,14 +380,9 @@ const task = async (row, index) => {
371
380
  dataParams.duration
372
381
  );
373
382
  await archiveZip(fileName, indexFilePath, originFilePath);
374
- const workEndTime = new Date();
375
- const timeInSeconds = ((workEndTime - workStartTime) / 1000).toFixed(2);
376
-
377
- logger(`第${index}条4090处理总时间:${timeInSeconds}秒`);
378
- logger(`-------------------${new Date()}------------------`);
379
383
 
380
384
  // 重试机制
381
- await postDataWithRetry(dataParams, indexFilePath, index);
385
+ await postDataWithRetry(dataParams, indexFilePath, index, fileName, hash);
382
386
 
383
387
  logger(
384
388
  `----------------------------------------第${index}条结束---------------------------------end`
@@ -388,55 +392,92 @@ const task = async (row, index) => {
388
392
  if (error.code === "ENOENT") {
389
393
  logger(`音频文件 ${fileName} 不存在`);
390
394
  } else {
391
- logger("音频任务处理失败:" + error);
395
+ logger("音频任务失败(最外层catch):" + error);
392
396
  }
393
397
  fs.rmdirSync(indexFilePath, { recursive: true });
394
- disposeError(fileName);
398
+ disposeError(hash, { fileName, keyword, title });
395
399
 
396
400
  //失败的时候,复制文件到错误文件夹中
397
- const failPath = path.join(workDir, Error_Files_Dir, fileName);
398
- moveFailFiles(originFilePath, failPath);
401
+ // const failPath = path.join(workDir, Error_Files_Dir, fileName);
402
+ // moveFailFiles(originFilePath, failPath);
399
403
  }
400
404
  };
401
405
 
402
- const main = () => {
403
- //当前任务hash
404
- const hashOrigin = generateUniqueHash();
405
- const hash = hashOrigin.slice(0, 8);
406
- logger("音频批量任务任务开始---" + hash);
407
- logger("当前目录: " + workDir + "工作目录: " + __dirname);
406
+ const run = (index, data, hash) => {
407
+ try {
408
+ logger(
409
+ `run-------------------------------------第${index}条开始------------------------------------`
410
+ );
411
+ const row = data[index];
408
412
 
409
- const jsonData = readExcel(excelDir);
413
+ if (!row) {
414
+ taskIndex = 0;
415
+ logger("当前任务,最后一条已结束!");
410
416
 
411
- const run = (index) => {
412
- try {
413
- logger(
414
- `run-------------------------------------第${index}条开始------------------------------------`
415
- );
416
- const row = jsonData[index];
417
-
418
- if (!row) {
419
- logger("最后一条已结束!");
420
- return;
417
+ // 是否存在错误列表? 存在的话,继续遍历
418
+ const errorExcelPath = path.join(workDir, `error${hash}.xlsx`);
419
+ if (isExist(errorExcelPath)) {
420
+ const jsonData2 = readExcel(errorExcelPath);
421
+ queue(taskIndex, jsonData2, hash);
422
+ } else {
423
+ logger("跑干了!");
421
424
  }
422
- task(row, index)
423
- .then(() => {
424
- taskIndex++;
425
- run(taskIndex);
426
- })
427
- .catch(() => {
428
- taskIndex++;
429
- run(taskIndex);
430
- });
431
- } catch (error) {
432
- logger("捕获错误!" + error);
433
- taskIndex++;
434
- run(taskIndex);
425
+
426
+ return;
435
427
  }
436
- };
437
428
 
429
+ task(row, index, hash)
430
+ .then(() => {
431
+ taskIndex++;
432
+ run(taskIndex, data, hash);
433
+ })
434
+ .catch((err) => {
435
+ throw new Error("task失败:" + err);
436
+ });
437
+ } catch (error) {
438
+ logger("捕获错误!" + error);
439
+ taskIndex++;
440
+ run(taskIndex, data, hash);
441
+ }
442
+ };
443
+
444
+ const queue = (taskIndex, jsonData, hash) => {
438
445
  for (let i = 0; i < queueCount; i++) {
439
- run(i + taskIndex);
446
+ run(i + taskIndex, jsonData, hash);
447
+ }
448
+ };
449
+
450
+ const main = () => {
451
+ //当前任务hash
452
+ let hash = "";
453
+ let jsonData = [];
454
+ logger("》》》》》》》》》》音频批量任务任务开始《《《《《《《《《《" + hash);
455
+ logger("当前目录: " + workDir + ";工作目录: " + exeDir);
456
+
457
+ // 读取success.txt,判断是否是 异常中断,
458
+ // 并根据success日志获取最后一行的hash,找到对应的error_hash_excel
459
+
460
+ const successPath = path.join(workDir, "success.txt");
461
+ if (isExist(successPath)) {
462
+ const { loghash, lastItemIndex } = readTxt(successPath);
463
+ const errorExcelPath = path.join(workDir, `error${loghash}.xlsx`);
464
+ logger("成功日志存在,异常中断或者跑完了。");
465
+
466
+ hash = loghash;
467
+ taskIndex = lastItemIndex + 1; // lastItemIndex为最后一项,所有要+1
468
+
469
+ if (isExist(errorExcelPath)) {
470
+ jsonData = readExcel(errorExcelPath); // 数据来源于error excel
471
+ queue(taskIndex, jsonData, hash);
472
+ } else {
473
+ logger("跑干了!");
474
+ }
475
+ } else {
476
+ hash = generateUniqueHash().slice(0, 8);
477
+ logger("成功日志不存在,开始新任务");
478
+
479
+ jsonData = readExcel(excelDir);
480
+ queue(taskIndex, jsonData, hash);
440
481
  }
441
482
  };
442
483
 
package/utils/logger.js CHANGED
@@ -13,17 +13,53 @@ const logger = (log) => {
13
13
  });
14
14
  };
15
15
 
16
- //错误日志
17
- const disposeError = (err) => {
18
- logger("---任务失败---" + err);
19
- logger(
20
- `******************************************************************end`
21
- );
22
- fs.writeFileSync("error.txt", err + "\n", {
16
+ /**
17
+ * 成功日志
18
+ * @param {*} 日志内容 hash index fileName
19
+ */
20
+ const successLogger = (hash, index, fileName) => {
21
+ console.log(fileName);
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
  };
@@ -19,10 +19,10 @@ function findFileInDir(dir, fileName) {
19
19
  return null;
20
20
  }
21
21
 
22
- function logFileSize(path) {
22
+ function logFileSize(path, index) {
23
23
  const fileSize = fs.statSync(path).size / (1024 * 1024);
24
24
  const formattedSize = fileSize.toFixed(2); // 保留两位小数
25
- logger(`音频大小:${formattedSize}M`);
25
+ logger(`第${index}条音频大小:${formattedSize}M`);
26
26
  }
27
27
 
28
28
  /**
@@ -40,6 +40,33 @@ function ensureDirSync(dirpath) {
40
40
  }
41
41
  }
42
42
 
43
+ /**
44
+ * 判断文件是否存在
45
+ */
46
+ function isExist(filePath) {
47
+ try {
48
+ fs.accessSync(filePath, fs.constants.F_OK);
49
+ console.log("存在");
50
+ return true;
51
+ } catch (err) {
52
+ console.log("错了");
53
+ console.error(err);
54
+ return false;
55
+ }
56
+ }
57
+ // function isExist(filePath) {
58
+ // fs.access(filePath, fs.constants.F_OK, (err) => {
59
+ // if (err) {
60
+ // console.log(err);
61
+
62
+ // return false;
63
+ // } else {
64
+ // console.log(555);
65
+ // return true;
66
+ // }
67
+ // });
68
+ // }
69
+
43
70
  /**
44
71
  * 上传失败后,存入新文件夹(手动创建)
45
72
  */
@@ -50,9 +77,29 @@ const moveFailFiles = (originFilePath, failPath) => {
50
77
  }
51
78
  };
52
79
 
80
+ //数组 item为:hash index fileName
81
+ function readTxt(path) {
82
+ try {
83
+ const data = fs.readFileSync(path, "utf-8");
84
+ const arr = data.split("\n").map((line) => line.trim()); // 删除每行两侧的空白符
85
+ const filteredArray = arr.filter((item) => item !== ""); //去除空项
86
+
87
+ const lastItem = filteredArray[filteredArray.length - 1];
88
+
89
+ const loghash = lastItem.split(" ")[0];
90
+ const lastItemIndex = parseInt(lastItem.split(" ")[1]);
91
+ return { loghash, lastItemIndex };
92
+ } catch (error) {
93
+ console.error("readErrorTxt函数出错:", error);
94
+ return {};
95
+ }
96
+ }
97
+
53
98
  module.exports = {
54
99
  findFileInDir,
55
100
  logFileSize,
56
101
  ensureDirSync,
57
102
  moveFailFiles,
103
+ isExist,
104
+ readTxt,
58
105
  };