tools_batch_files 1.0.0 → 1.0.4

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/index.js CHANGED
@@ -1,72 +1,151 @@
1
+ const XLSX = require("xlsx");
1
2
  const ffmpeg = require("fluent-ffmpeg");
2
3
  const fs = require("fs");
3
4
  const path = require("path");
4
- const XLSX = require("xlsx");
5
- const FormData = require("form-data");
5
+ const fs_asnyc = require("fs").promises;
6
+ const archiver = require("archiver");
6
7
  const axios = require("axios");
7
8
  const generateUniqueHash = require("./utils/index");
8
9
 
9
- const hashOneTime = generateUniqueHash();
10
-
11
- // 源文件目录
12
- const videoFolderPath = "video";
13
- // 转码文件目录
14
- const videoTo264oFolderPath = "output/videoTo264";
15
- // 压缩后
16
- const outputFolderPath = "output/video";
17
-
18
- //转码后
19
- const outputTransitionCodecFolderPath = "output/videoTo264"
10
+ // 表格目录
11
+ const excelDir = path.join(__dirname, "excel", "excel.xlsx");
12
+ //水印
13
+ const watermarkImage = path.join(process.cwd(), "imgs", "miz-watermark.png");
14
+ // 截图数量
15
+ const SCREENSHOT_COUNT = 5;
16
+ const ORIGIN_FILE_DIR = "video";
17
+ const ZIP_VIDEO_DIR = "zip_video";
18
+ const SCREENSHOT_DIR = "screenshot";
19
+ const ZIP_WATERMARK_VIDEO_DIR = "zip_watermark_video";
20
+ const ZIP_SCREENSHOT_DIR = "screenshot_watermark";
21
+ const SOURCE_VIDEO_DIR = "source_video";
22
+
23
+ //并发数量
24
+ const queueCount = 1;
25
+
26
+ //任务开始序列
27
+ let taskIndex = 0;
20
28
 
21
- const screenshotsFlodar = "output";
22
- const screenshotsFlodarChild = "screenshots";
23
- // 5张截图保存目录
24
- const screenshotsDir = `${screenshotsFlodar}/${screenshotsFlodarChild}`;
29
+ /**
30
+ * 递归遍历文件夹,查找mp4文件
31
+ * @param {*} dir 文件夹路径
32
+ * @param {*} fileName 文件名称
33
+ * @returns string 匹配成功的文件路径
34
+ */
35
+ function findFileInDir(dir, fileName) {
36
+ const files = fs.readdirSync(dir);
37
+ for (const file of files) {
38
+ const filePath = path.join(dir, file);
39
+ const stat = fs.statSync(filePath);
40
+ if (stat.isDirectory()) {
41
+ const result = findFileInDir(filePath, fileName);
42
+ if (result) {
43
+ return result;
44
+ }
45
+ } else if (
46
+ file.startsWith(fileName) &&
47
+ (file.endsWith(".mp4") || file.endsWith(".mov"))
48
+ ) {
49
+ return filePath;
50
+ }
51
+ }
52
+ return null;
53
+ }
25
54
 
26
- //临时存储截图数组
27
- let filenames = [];
55
+ /**
56
+ * 确保目录存在,如果不存在则创建它
57
+ */
58
+ function ensureDirSync(dirpath) {
59
+ try {
60
+ if (!fs.existsSync(dirpath)) {
61
+ fs.mkdirSync(dirpath, { recursive: true });
62
+ logger(`目录创建成功:${dirpath}`);
63
+ }
64
+ } catch (err) {
65
+ logger(`创建目录时出错:${err}`);
66
+ throw err;
67
+ }
68
+ }
28
69
 
29
70
  /**
30
- * 压缩视频
71
+ * 检查文件是否存在
31
72
  */
32
- const batchVideoFile = (fileName) => {
33
- const inputFilePath = videoFolderPath + "/" + fileName;
73
+ function checkFileExistence(path) {
74
+ return new Promise((resolve, reject) => {
75
+ fs.access(path, fs.constants.F_OK, (err) => {
76
+ if (!err) {
77
+ logger("文件存在,可以访问");
78
+ resolve(true);
79
+ } else {
80
+ logger(`视频文件 ${path} 不存在`);
81
+ resolve(false);
82
+ }
83
+ });
84
+ });
85
+ }
34
86
 
35
- const outputFilePath = outputFolderPath + "/" + "zip-" + fileName;
87
+ //普通日志
88
+ const logger = (log, hash, err) => {
89
+ console.log(log);
90
+ fs.writeFileSync("log.txt", log + "\n", {
91
+ flag: "a",
92
+ });
93
+ };
94
+
95
+ //错误日志
96
+ const disposeError = (hash, err) => {
97
+ logger("---任务失败---", hash, err);
98
+ logger(
99
+ `******************************************************************end`
100
+ );
101
+ fs.writeFileSync("error.txt", err + "\n", {
102
+ flag: "a",
103
+ });
104
+ };
36
105
 
37
- const command = ffmpeg();
38
- const videoBitrate = 4000;
106
+ const readExcel = (path) => {
107
+ const workbook = XLSX.readFile(path);
39
108
 
40
- // 设置目标文件大小为50MB
41
- // const targetFileSize = 50 * 1024 * 1024;
109
+ // 获取第一个工作表(Sheet)
110
+ const firstSheetName = workbook.SheetNames[0];
111
+ const worksheet = workbook.Sheets[firstSheetName];
42
112
 
43
- // 获取原视频文件大小(bytes)
44
- // const inputFileSize = fs.statSync(inputFilePath).size;
113
+ // 将工作表转换为 JSON 对象
114
+ const jsonData = XLSX.utils.sheet_to_json(worksheet);
115
+ return jsonData;
116
+ };
45
117
 
46
- // 根据目标文件大小估算比特率
47
- // const videoBitrate = Math.floor((targetFileSize / inputFileSize) * 1000);
118
+ function logFileSize(path) {
119
+ const fileSize = fs.statSync(path).size / (1024 * 1024);
120
+ const formattedSize = fileSize.toFixed(2); // 保留两位小数
121
+ logger(`视频大小:${formattedSize}M`);
122
+ }
48
123
 
49
- // 创建 ffmpeg 实例
50
- // 输入视频文件
124
+ /**
125
+ * 压缩视频
126
+ * @param {*} fileName 文件名
127
+ * @param {*} outputFileDir 产物文件夹
128
+ * @param {*} inputFilePath 源文件路径
129
+ * @returns Promise
130
+ */
131
+ const compressVideo = (fileName, outputFileDir, inputFilePath) => {
132
+ // const inputFilePath = path.join(__dirname, "video", fileName);
133
+ const outputFilePath = path.join(
134
+ outputFileDir,
135
+ ZIP_VIDEO_DIR,
136
+ `zip-${fileName}`
137
+ );
138
+ const comand = ffmpeg(inputFilePath);
139
+
140
+ ensureDirSync(path.dirname(outputFilePath));
51
141
  return new Promise((resolve, reject) => {
52
- command
53
- .input(inputFilePath)
54
- // 设置视频尺寸为
55
- // .size('1280x720')
56
- // 设置视频编解码参数
57
- .videoCodec('libx264')
58
- // .videoCodec("mpeg4")
59
-
60
- // 设置视频比特率
61
- .videoBitrate(videoBitrate + "k")
62
- // 设置音频编解码参数
63
- // .audioCodec("aac")
64
- .audioCodec('libmp3lame')
65
- // 设置音频比特率
66
- // .audioBitrate('128k')
67
- // 设置输出文件路径
142
+ comand
143
+ .videoCodec("libx264")
144
+ .size("1280x?")
145
+ // .size("1280x720")
146
+
68
147
  .output(outputFilePath)
69
- // 开始处理
148
+
70
149
  .on("start", () => {
71
150
  logger("视频开始压缩……");
72
151
  })
@@ -75,58 +154,26 @@ const batchVideoFile = (fileName) => {
75
154
  resolve(outputFilePath);
76
155
  })
77
156
  .on("error", (err) => {
78
- reject(err);
79
157
  logger("视频压缩出错:", err);
158
+ reject(err);
80
159
  })
81
160
  .run();
82
161
  });
83
162
  };
84
163
 
85
164
  /**
86
- * 转码
165
+ * 生成5张截图
87
166
  */
88
- // const transitionCodec = (fileName) => {
89
- // const inputFilePath = videoFolderPath + "/" + fileName;
90
- // const outputFilePath = outputTransitionCodecFolderPath + "/" + fileName;
91
-
92
- // const command = ffmpeg(inputFilePath);
93
-
94
- // return new Promise((resolve, reject) => {
95
- // command
96
- // .input(inputFilePath)
97
- // // .videoCodec('libx264')
98
- // .videoCodec("mpeg4")
99
-
100
- // .output(outputFilePath)
101
- // .on("start", () => {
102
- // logger("视频开始转码……");
103
- // })
104
- // .on("end", () => {
105
- // logger("视频转码完成!");
106
- // const videoTo264Path = path.join("output", "videoTo264", fileName); // 转码后视频文件路径
107
-
108
- // resolve(videoTo264Path);
109
- // })
110
- // .on("error", (err) => {
111
- // reject(err);
112
- // logger("视频转码出错:", err);
113
- // })
114
- // .run();
115
- // });
116
- // }
117
-
118
- /**
119
- * 截图
120
- */
121
- const get5Screenshots = (fileName) => {
122
- const inputFilePath = videoFolderPath + "/" + fileName;
123
-
124
- const command = ffmpeg(inputFilePath);
167
+ const get5Screenshots = (fileName, outputFilePath, inputFilePath) => {
168
+ const folderPath = path.join(outputFilePath, SCREENSHOT_DIR); // 构建完整的目录路径
125
169
 
170
+ ensureDirSync(folderPath);
126
171
  return new Promise((resolve, reject) => {
127
- command
172
+ const screenshotsCommand = ffmpeg(inputFilePath);
173
+
174
+ screenshotsCommand
128
175
  .on("start", () => {
129
- logger("开始截图");
176
+ logger("开始从视频中截图……");
130
177
  })
131
178
  .on("end", (stdout, stderr) => {
132
179
  logger(inputFilePath + "截图完成!!!");
@@ -139,159 +186,281 @@ const get5Screenshots = (fileName) => {
139
186
 
140
187
  .screenshots({
141
188
  timemarks: [0, "25%", "50%", "75%", "90%"],
142
- folder: screenshotsDir,
143
- filename: `screenshots-at-%s-%i-seconds.png`, //hash或者随机字符
144
- size: '840x?'
145
- })
146
- .on("filenames", (filenamesArr) => {
147
- // 将截图文件名存储到临时数组中
148
- filenames.push(...filenamesArr);
189
+ folder: folderPath,
190
+ filename: `screenshots-%i.png`,
191
+ size: "840x?",
149
192
  });
150
193
  });
151
194
  };
152
195
 
153
196
  /**
154
- * 删除截图文件
197
+ * 视频打水印
155
198
  */
156
- const deleteScreenshots = () => {
157
- filenames.forEach((item) => {
158
- const filePath = path.join("output", "screenshots", item);
199
+ const watermarkVideo = (fileName, outputFileDir) => {
200
+ //用压缩后的视频作为输入源,增加效率
201
+ const inputFilePath = path.join(
202
+ outputFileDir,
203
+ ZIP_VIDEO_DIR,
204
+ `zip-${fileName}`
205
+ );
206
+ const outputFilePath = path.join(
207
+ outputFileDir,
208
+ ZIP_WATERMARK_VIDEO_DIR,
209
+ `zip-watermark-${fileName}`
210
+ );
211
+ const watermarkCommand = ffmpeg(inputFilePath);
212
+
213
+ ensureDirSync(path.dirname(outputFilePath));
214
+
215
+ return new Promise((resolve, reject) => {
216
+ watermarkCommand
217
+ .input(watermarkImage) // 添加水印图片作为第二个输入
159
218
 
160
- fs.unlinkSync(filePath);
219
+ .complexFilter([
220
+ "[0:v][1:v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2",
221
+ ])
222
+ .output(outputFilePath)
223
+ .on("start", () => {
224
+ logger("视频开始打水印……");
225
+ })
226
+ .on("end", () => {
227
+ logger("视频打水印完成!");
228
+ resolve(outputFilePath);
229
+ })
230
+ .on("error", (err) => {
231
+ logger("视频打水印出错:", err);
232
+ reject(err);
233
+ })
234
+ .run();
161
235
  });
162
- filenames = [];
163
- }
236
+ };
164
237
 
165
238
  /**
166
- * 失败逻辑和 记录错误日志
239
+ * 截图水印,根据截图打水印
167
240
  */
168
- const updateFail = (err) => {
169
- logger('xxxxx数据上传失败xxxxx: ' + err);
170
- logger(`******************************************************************end`)
171
- deleteScreenshots();
172
- return Promise.reject();
173
- }
241
+ const watermarkScreenshots = (indexFilePath) => {
242
+ //存放水印截图的文件夹
243
+ const inputDir = path.join(indexFilePath, SCREENSHOT_DIR);
244
+ const outputDir = path.join(indexFilePath, ZIP_SCREENSHOT_DIR);
245
+ ensureDirSync(outputDir);
246
+
247
+ return new Promise((resolve, reject) => {
248
+ fs.readdir(inputDir, (err, files) => {
249
+ if (err) {
250
+ logger("读取截图文件夹出错: " + err);
251
+ return;
252
+ } else {
253
+ files.forEach((file, index) => {
254
+ if (path.extname(file) === ".png") {
255
+ const inputFile = path.join(inputDir, file);
256
+ const outputFile = path.join(outputDir, file);
257
+
258
+ const watermarkScreenshotsComand = ffmpeg(inputFile);
259
+ watermarkScreenshotsComand
260
+ .input(watermarkImage)
261
+ .complexFilter([
262
+ "[0:v][1:v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2",
263
+ ])
264
+ .output(outputFile)
265
+ .on("error", (err) => {
266
+ logger("截图添加水印出错: ", err);
267
+ reject();
268
+ })
269
+ .on("end", () => {
270
+ logger("截图水印添加完成: " + outputFile);
271
+ if (index + 1 === SCREENSHOT_COUNT) {
272
+ resolve();
273
+ }
274
+ })
275
+ .run();
276
+ } else {
277
+ logger("截图不是png文件,无法添加图片水印!");
278
+ reject();
279
+ }
280
+ });
281
+ }
282
+ });
283
+ });
284
+ };
174
285
 
175
286
  /**
176
- * 成功逻辑和 记录普通日志
287
+ * 打包物料
177
288
  */
178
- const updateSuccess = (id) => {
179
- deleteScreenshots();
180
- logger("数据上传成功!");
181
- logger("id = " + id);
182
- logger(`******************************************************************end`)
183
- }
289
+ const archiveZip = (fileName, inputPath) => {
290
+ const sourceVideoPath = path.join(__dirname, "video", fileName);
291
+ const zipDir = path.join(inputPath, "zip");
292
+
293
+ ensureDirSync(zipDir);
294
+ // create a file to stream archive data to.
295
+ const zipStream = fs.createWriteStream(path.join(zipDir, "package.zip"));
296
+ const archive = archiver("zip", {
297
+ zlib: { level: 9 }, // Sets the compression level.
298
+ });
299
+
300
+ return new Promise((resolve, reject) => {
301
+ // listen for all archive data to be written
302
+ // 'close' event is fired only when a file descriptor is involved
303
+ zipStream.on("close", function () {
304
+ logger("压缩数据:" + archive.pointer() + " total bytes");
305
+ logger(
306
+ "完成归档archiver has been finalized and the output file descriptor has closed."
307
+ );
308
+ resolve();
309
+ });
310
+
311
+ // good practice to catch warnings (ie stat failures and other non-blocking errors)
312
+ archive.on("warning", function (err) {
313
+ if (err.code === "ENOENT") {
314
+ logger("压缩-warning:" + err);
315
+ } else {
316
+ // throw error
317
+ throw err;
318
+ }
319
+ });
320
+
321
+ // good practice to catch this error explicitly
322
+ archive.on("error", function (err) {
323
+ logger("压缩失败!" + err);
324
+ reject();
325
+ });
326
+
327
+ archive.pipe(zipStream);
328
+
329
+ const directories = [
330
+ ZIP_VIDEO_DIR,
331
+ SCREENSHOT_DIR,
332
+ ZIP_WATERMARK_VIDEO_DIR,
333
+ ZIP_SCREENSHOT_DIR,
334
+ ];
335
+
336
+ directories.forEach((dir) => {
337
+ const dirPath = path.join(inputPath, dir);
338
+ archive.directory(dirPath, dir);
339
+ });
340
+
341
+ archive.file(sourceVideoPath, {
342
+ name: path.join(SOURCE_VIDEO_DIR, fileName),
343
+ });
344
+ // 完成归档
345
+ archive.finalize();
346
+ });
347
+ };
184
348
 
185
349
  /**
186
- * 拼接数据
187
- * @param {number} type 1:压缩+截图 2:仅截图
188
- * @param {object} options path路径
350
+ * 获取 元数据
189
351
  */
190
- const concatData = (
191
- type,
192
- { title, keyword, videoFilePath, outputVideoFilePath, screenshotsDir }
193
- ) => {
194
- const formData = new FormData();
195
- const formatKeyword = keyword.split(",").join(" ");
196
-
197
- if (type === 1) {
198
- formData.append("zip_video", fs.createReadStream(outputVideoFilePath));
199
- }
200
- // else {
201
- // formData.append("zip_video", fs.createReadStream(videoFilePath));
202
- // }
203
-
204
- formData.append("title", title);
205
- formData.append("keyword", formatKeyword);
206
- formData.append("source_video", fs.createReadStream(videoFilePath));
207
-
208
- fs.readdirSync(screenshotsDir).forEach((item, index) => {
209
- formData.append(
210
- `screenshot${index + 1}`,
211
- fs.createReadStream(`${screenshotsDir}/${item}`)
212
- );
352
+ const getMetadata = async (fileName, indexFilePath) => {
353
+ const inputFilePath = path.join(__dirname, "video", fileName);
354
+ //第一张截图
355
+ const photoInputPath = path.join(
356
+ indexFilePath,
357
+ SCREENSHOT_DIR,
358
+ "screenshots-1.png"
359
+ );
360
+
361
+ const videoMetadataComand = ffmpeg(inputFilePath);
362
+ const photoMetadataComand = ffmpeg(photoInputPath);
363
+ const metaDataParams = {
364
+ videoWidth: "",
365
+ videoHeight: "",
366
+ videoSize: "",
367
+ videoDuration: "",
368
+ videoId: "",
369
+ pr: "",
370
+ photoWidth: "",
371
+ photoHeight: "",
372
+ };
373
+ await new Promise((resolve, reject) => {
374
+ videoMetadataComand.ffprobe(function (err, metadata) {
375
+ const videoStream = metadata.streams.find(
376
+ (s) => s.codec_type === "video"
377
+ );
378
+ const formatStream = metadata.format;
379
+
380
+ metaDataParams.videoWidth = videoStream.width;
381
+ metaDataParams.videoHeight = videoStream.height;
382
+ metaDataParams.videoDuration = videoStream.duration;
383
+ metaDataParams.videoSize = formatStream.size;
384
+ resolve();
385
+ });
386
+ });
387
+
388
+ await new Promise((resolve, reject) => {
389
+ photoMetadataComand.ffprobe(function (err, metadata) {
390
+ const photoStream = metadata.streams.find(
391
+ (s) => s.codec_type === "video"
392
+ );
393
+
394
+ metaDataParams.photoWidth = photoStream.width;
395
+ metaDataParams.photoHeight = photoStream.height;
396
+ resolve();
397
+ });
213
398
  });
214
399
 
215
- return postData(formData);
400
+ return metaDataParams;
216
401
  };
217
402
 
218
403
  /**
219
- * 数据传输
404
+ * 接口
220
405
  */
221
406
  const postData = (data) => {
222
407
  logger("等待接口返回结果……");
223
408
 
224
- return axios
225
- .post("https://designer-api.51miz.com/designer/CallBack/uploadVideoData", data, {
409
+ return axios.post(
410
+ "https://designer-api.51miz.com/designer/CallBack/uploadVideoData",
411
+ data,
412
+ {
226
413
  headers: {
227
414
  "Content-Type": "multipart/form-data",
228
415
  },
229
- })
230
- .then((res) => {
231
- console.log(res.data);
232
- if (res.data.status == 200) {
233
- updateSuccess(res.data.id)
234
-
235
- } else {
236
- logger('xxxxx数据上传失败xxxxx: ');
237
- logger(`******************************************************************end`)
238
- deleteScreenshots();
239
- return Promise.reject();
240
- }
241
- })
242
- .catch((err) => {
243
- logger('xxxxx数据上传失败xxxxx: ' + err);
244
- logger(`******************************************************************end`)
245
- deleteScreenshots();
246
- return Promise.reject();
247
- })
416
+ }
417
+ );
248
418
  };
249
419
 
250
- //处理错误信息
251
- const disposeError = (hash, err) => {
252
- logger('任务失败---', hash, err);
253
- fs.writeFileSync(hash + '-error.txt', err + '\n', {
254
- flag: 'a'
255
- })
256
- fs.writeFileSync('error.txt', err + '\n', {
257
- flag: 'a'
258
- })
259
- }
260
-
261
- //处理错误信息
262
- const logger = (log) => {
263
- console.log(log);
264
- fs.writeFileSync('log.txt', log + '\n', {
265
- flag: 'a'
266
- })
267
- }
268
-
269
420
  /**
270
- * 脚本开始前清空截图文件夹
421
+ * 任务
271
422
  */
272
- const clearDirectoryContents = (dirPath) => {
423
+ const task = async (row, index) => {
424
+ logger(
425
+ "**************************" + row.fileName + "**************************"
426
+ );
427
+ // Excel的列名分别为: fileName title keyword
428
+ const fileName = row.fileName;
429
+ // const originFilePath = path.join(__dirname, "video", fileName); // 源视频文件路径
430
+ const originFilePath = findFileInDir(
431
+ path.join(__dirname, ORIGIN_FILE_DIR),
432
+ fileName
433
+ ); // 源视频文件路径
434
+ console.log("originFilePath");
435
+ console.log(originFilePath);
436
+
437
+ //index文件夹 output/0
438
+ const indexFilePath = path.join(__dirname, "output", index + "");
439
+
273
440
  try {
274
- const files = fs.readdirSync(dirPath); // 读取目录中的所有文件和目录
275
-
276
- if (files.length > 0) {
277
- files.forEach(function (filename) {
278
- const filePath = path.join(dirPath, filename);
279
- // const fileStat = fs.statSync(filePath);
280
-
281
- // if (fileStat.isDirectory()) {
282
- // // 如果是目录,则递归清空目录
283
- // clearDirectoryContents(filePath);
284
- // // 删除目录本身
285
- // fs.rmdirSync(filePath);
286
- // } else {
287
- // 如果是文件,直接删除
288
- fs.unlinkSync(filePath);
289
- logger("截图文件夹已清空。")
290
- // }
291
- });
292
- }
441
+ await fs_asnyc.access(originFilePath, fs_asnyc.constants.F_OK);
442
+ logFileSize(originFilePath);
443
+ await compressVideo(fileName, indexFilePath, originFilePath);
444
+ await get5Screenshots(fileName, indexFilePath, originFilePath);
445
+ await watermarkVideo(fileName, indexFilePath);
446
+ await watermarkScreenshots(indexFilePath);
447
+ await archiveZip(fileName, indexFilePath);
448
+ const dataParams = await getMetadata(fileName, indexFilePath);
449
+ console.log("dataParams");
450
+ console.log(dataParams);
451
+
452
+ // await postData(dataParams);
453
+ logger(
454
+ `----------------------------------------第${index}条结束---------------------------------end`
455
+ );
293
456
  } catch (error) {
294
- console.error('清空截图文件夹失败!', error);
457
+ // 可以约定code,来表示不同的错误信息
458
+ if (error.code === "ENOENT") {
459
+ logger(`视频文件 ${fileName} 不存在`);
460
+ } else {
461
+ logger("视频处理失败", error.message);
462
+ }
463
+ disposeError(hash, fileName);
295
464
  }
296
465
  };
297
466
 
@@ -302,97 +471,22 @@ const transitionExcelToJSON = () => {
302
471
  //当前任务hash
303
472
  const hashOrigin = generateUniqueHash();
304
473
  const hash = hashOrigin.slice(0, 8);
305
- logger('任务开始---' + hash);
306
- // 读取 Excel 文件
307
- const workbook = XLSX.readFile("excel/demo-video.xlsx");
308
-
309
- // 获取第一个工作表(Sheet)
310
- const firstSheetName = workbook.SheetNames[0];
311
- const worksheet = workbook.Sheets[firstSheetName];
312
-
313
- // 将工作表转换为 JSON 对象
314
- const jsonData = XLSX.utils.sheet_to_json(worksheet);
315
-
316
- let taskIndex = 1680;
317
-
318
- const task = (row) => {
319
- logger("**************************" + row.fileName + "**************************");
320
- clearDirectoryContents(screenshotsDir);
321
- return new Promise((resolve, reject) => {
322
- const fileName = row.fileName; // Excel的列名分别为: fileName title keyword
323
- const title = row.title;
324
- const keyword = row.keyword;
325
-
326
- const videoFilePath = path.join(videoFolderPath, fileName); // 视频文件路径
327
-
328
- // 检查视频文件是否存在
329
- fs.access(videoFilePath, fs.constants.F_OK, (err) => {
330
- if (!err) {
331
- const fileSize = fs.statSync(videoFilePath).size / (1024 * 1024);
332
- logger("视频大小" + fileSize + 'M');
333
-
334
- //如果原视频 < 50M ,那么不压缩
335
- // if (fileSize > 50) {
336
-
337
- Promise.all([batchVideoFile(fileName), get5Screenshots(fileName)])
338
- .then(([outputVideoFilePath]) => {
339
- console.log("视频处理结束……成功");
340
- concatData(1, {
341
- title,
342
- keyword,
343
- videoFilePath,
344
- outputVideoFilePath,
345
- screenshotsDir,
346
- }).then(() => {
347
- console.log('concatData成功');
348
- resolve();
349
- }).catch((reason) => {
350
- disposeError(hash, fileName);
351
- logger("压缩+截图失败" + reason);
352
- reject();
353
- });
354
- })
355
- .catch((reason) => {
356
- disposeError(hash, fileName);
357
- logger("All失败" + reason);
358
- reject();
359
- });
360
-
361
- // } else {
362
- // logger("<50M,不压缩");
363
- // get5Screenshots(fileName).then(() => {
364
- // concatData(2, {
365
- // title,
366
- // keyword,
367
- // videoFilePath,
368
- // outputVideoFilePath: '',
369
- // screenshotsDir,
370
- // }).then(() => {
371
- // resolve();
372
- // }).catch((reason) => {
373
- // disposeError(hash, fileName);
374
- // logger("仅截图 失败" + reason);
375
- // });
376
- // });
377
- // }
378
- } else {
379
- logger(`视频文件 ${fileName} 不存在`);
380
- resolve();
381
- }
382
- });
383
- })
384
- }
474
+ logger("任务开始---" + hash);
475
+ logger("当前目录: " + __dirname);
476
+ logger("工作目录: " + process.cwd());
385
477
 
478
+ const jsonData = readExcel(excelDir);
386
479
 
387
480
  const run = (index) => {
388
- logger(`----------------------------------------第${index}条----------------------------------------`)
389
- logger(`----------------------------------------${new Date()}----------------------------------------`)
390
-
391
481
  const row = jsonData[index];
392
482
  if (!row) {
393
483
  return;
394
484
  }
395
- task(row)
485
+ logger(
486
+ `----------------------------------------第${index}条开始------------------------------------`
487
+ );
488
+ logger(`-------------------${new Date()}------------------`);
489
+ task(row, index)
396
490
  .then(() => {
397
491
  taskIndex++;
398
492
  run(taskIndex);
@@ -400,13 +494,12 @@ const transitionExcelToJSON = () => {
400
494
  .catch(() => {
401
495
  taskIndex++;
402
496
  run(taskIndex);
403
- })
404
- }
497
+ });
498
+ };
405
499
 
406
- for (let i = 0; i < 1; i++) {
500
+ for (let i = 0; i < queueCount; i++) {
407
501
  run(i);
408
502
  }
409
-
410
503
  };
411
504
 
412
505
  transitionExcelToJSON();