tools_batch_files 1.0.0

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/error.txt ADDED
@@ -0,0 +1,140 @@
1
+ 城市高楼建筑封顶施工航拍 (9).mp4
2
+ 福建福州台江万达广场金融中心夜景航拍 (10).mp4
3
+ 福建泉州城市夜景东海CBD夜景灯光航拍 (11)~1.mp4
4
+ 广东澳门城市风光澳门塔航拍 (1).mp4
5
+ 广东东莞城市CBD鸿福路高楼航拍 (9).mp4
6
+ 广东佛山千灯湖城市风光航拍 (1).mp4.baiduyun.p.downloading
7
+ 广东佛山千灯湖城市风光航拍 (1).mp4.baiduyun.p.downloading
8
+ 广东佛山千灯湖城市风光航拍 (13).mp4.baiduyun.p.downloading
9
+ 广东佛山千灯湖城市风光航拍 (14).mp4
10
+ 广东佛山千灯湖城市风光航拍 (15).mp4
11
+ 广东佛山千灯湖城市风光航拍 (17).mp4
12
+ 广东佛山千灯湖城市风光航拍 (3).mp4
13
+ 广东佛山千灯湖城市风光航拍 (13).mp4.baiduyun.p.downloading
14
+ 广东佛山千灯湖城市风光航拍 (14).mp4
15
+ 广东佛山千灯湖城市风光航拍 (15).mp4
16
+ 广东佛山千灯湖城市风光航拍 (17).mp4
17
+ 广东佛山千灯湖城市风光航拍 (3).mp4
18
+ 广东佛山千灯湖城市风光航拍 (13).mp4.baiduyun.p.downloading
19
+ 广东惠州市政府大楼航拍 (13).mp4
20
+ 广东惠州市政府大楼航拍 (14).mp4
21
+ 广东惠州市政府大楼航拍 (15).mp4
22
+ 广东惠州市政府大楼航拍 (3).mp4
23
+ 广东惠州市政府大楼航拍 (6).mp4
24
+ 广东惠州市政府大楼航拍 (9).mp4
25
+ 广东惠州市政府航拍 (1).mp4
26
+ 广东惠州西湖泗洲塔航拍 (12).mp4
27
+ 广东湛江人民广场人民大会堂航拍 (1).mp4
28
+ 广东湛江人民广场人民大会堂航拍 (10).mp4
29
+ 广东湛江人民广场人民大会堂航拍 (11).mp4
30
+ 广东湛江人民广场人民大会堂航拍 (13).mp4
31
+ 广东湛江人民广场人民大会堂航拍 (14).mp4
32
+ 广东湛江人民广场人民大会堂航拍 (15).mp4
33
+ 广东湛江人民广场人民大会堂航拍 (16).mp4
34
+ 广东湛江人民广场人民大会堂航拍 (2).mp4
35
+ 广东湛江人民广场人民大会堂航拍 (3).mp4
36
+ 广东湛江人民广场人民大会堂航拍 (4).mp4
37
+ 广东湛江人民广场人民大会堂航拍 (6).mp4
38
+ 广东湛江人民广场人民大会堂航拍 (7).mp4
39
+ 广东肇庆七星山5A景区星湖航拍 (4).mp4
40
+ 广东肇庆星湖景区夜景航拍 (5).mp4
41
+ 广东中山城市夜景灯光航拍 (2).mp4
42
+ 广东中山市政府办公大楼航拍 (1).mp4
43
+ 广东中山市政府办公大楼航拍 (2).mp4
44
+ 广东中山市政府办公大楼航拍 (4).mp4
45
+ 广东中山市政府办公大楼航拍 (5).mp4
46
+ 广东中山市政府办公大楼航拍 (6).mp4
47
+ 广东中山市政府办公大楼航拍 (7).mp4
48
+ 广东中山市政府办公大楼航拍 (8).mp4
49
+ 广东中山市政府办公大楼航拍 (9).mp4
50
+ 广东中山市政府航拍 (3).mp4
51
+ 广东中山市政府航拍 (4).mp4
52
+ 广东中山市政府航拍 (8).mp4
53
+ 广东中山市政府航拍 (9).mp4
54
+ 广东中山市政府建筑航拍 (1).mp4
55
+ 广东中山市政府建筑航拍 (2).mp4
56
+ 广东中山市政府建筑航拍 (3).mp4
57
+ 广西北海北部湾广场航拍 (1).mp4
58
+ 航拍河南新乡市市政府 (4).mp4
59
+ 航拍衡阳莲湖广场.mp4
60
+ 航拍洛阳开元湖洛阳市政府夜景 (6).mp4
61
+ 航拍阳朔龙脊山.mp4
62
+ 航拍阳朔西街古塔.mp4
63
+ 河北邯郸丛台公园航拍 (3).mp4
64
+ 河北石家庄城市风光建设航拍 (48).mp4
65
+ 河南许昌市委市政府航拍 (1).mp4
66
+ 河南许昌市委市政府航拍 (2).mp4
67
+ 河南许昌市委市政府航拍 (3).mp4
68
+ 河南许昌市委市政府航拍 (5).mp4
69
+ 河南许昌市委市政府航拍 (6).mp4
70
+ 河南许昌市委市政府航拍 (8).mp4
71
+ 河南许昌市政府航拍 (1).mp4
72
+ 河南许昌市政府航拍 (15).mp4
73
+ 河南许昌市政府航拍 (17).mp4
74
+ 河南许昌市政府航拍 (7).mp4
75
+ 河南许昌市政府航拍 (9).mp4
76
+ 湖南湘潭大桥夜景交通航拍 (6).mp4
77
+ 江南水乡乌镇5A景区航拍 (2).mp4
78
+ 江南水乡乌镇5A景区航拍 (3).mp4
79
+ 江南水乡乌镇5A景区航拍 (5).mp4
80
+ 江苏常州城市风光地标建筑航拍 (101).mp4
81
+ 江苏淮安城市风光周恩来故居航拍 (1)~1.mp4
82
+ 江苏淮安城市风光周恩来故居航拍 (10)~1.mp4
83
+ 江苏淮安城市风光周恩来故居航拍 (13)~1.mp4
84
+ 江苏淮安城市风光周恩来故居航拍 (2)~1.mp4
85
+ 江苏淮安城市风光周恩来故居航拍 (3)~1.mp4
86
+ 江苏淮安城市风光周恩来故居航拍 (6)~1.mp4
87
+ 江苏淮安周恩来故里5A景区航拍 (1).mp4
88
+ 江苏淮安周恩来故里5A景区航拍 (12).mp4
89
+ 江苏淮安周恩来故里5A景区航拍 (13).mp4
90
+ 江苏淮安周恩来故里5A景区航拍 (2).mp4
91
+ 江苏淮安周恩来故里5A景区航拍 (4).mp4
92
+ 江苏淮安周恩来故里5A景区航拍 (9).mp4
93
+ 江苏苏州观前街步行街航拍 (2).mp4
94
+ 江苏宿迁城市风光大剧院体育馆图书馆市政府航拍 (23).mp4
95
+ 江苏宿迁城市风光大剧院体育馆图书馆市政府航拍 (34).mp4
96
+ 江苏宿迁城市风光大剧院体育馆图书馆市政府航拍 (38).mp4
97
+ 江苏宿迁城市风光大剧院体育馆图书馆市政府航拍 (41).mp4
98
+ 江苏宿迁城市风光大剧院体育馆图书馆市政府航拍 (54).mp4
99
+ 江苏宿迁市政府航拍 (10).mp4
100
+ 江苏宿迁市政府航拍 (11).mp4
101
+ 江苏宿迁市政府航拍 (13).mp4
102
+ 江苏宿迁市政府航拍 (3).mp4
103
+ 江苏宿迁市政府航拍 (7).mp4
104
+ 江苏徐州电视塔地标建筑航拍 (1).mp4
105
+ 江苏徐州电视塔地标建筑航拍 (7).mp4
106
+ 江苏徐州汉文化园航拍 (46).mp4
107
+ 江苏扬州东关历史文化旅游区航拍 (11).mp4
108
+ 江苏扬州瘦西湖5A景区 (6).mp4
109
+ 江苏扬州瘦西湖5A景区航拍 (1).mp4
110
+ 山东东营区政府航拍 (1).mp4
111
+ 山东东营区政府航拍 (2).mp4
112
+ 山东东营市政府航拍 (10).mp4
113
+ 山东东营市政府航拍 (14).mp4
114
+ 山东东营市政府航拍 (16).mp4
115
+ 山东东营市政府航拍 (18).mp4
116
+ 山东东营市政府航拍 (4).mp4
117
+ 山东青岛北站夜景灯光航拍 (1).mp4
118
+ 山东泰安泰山市政府中轴线航拍 (3).mp4
119
+ 寺庙下雨素材苏州北寺塔实拍 (41).mp4
120
+ 寺庙下雨素材苏州北寺塔实拍 (42).mp4
121
+ 寺庙下雨素材苏州北寺塔实拍 (92).mp4
122
+ 苏州周庄古镇5A景区江南水乡航拍 (3).mp4
123
+ 天津城市风光航拍 (33).mp4
124
+ 夏日树枝树叶植物实拍 (9).mp4
125
+ 云南昆明金殿4A景区航拍 (13).mp4
126
+ 浙江杭州城市风光航拍 (8).mp4
127
+ 浙江杭州西湖全景大景航拍 (12).mp4
128
+ 浙江宁波城市夜幕降临夜景灯光航拍 (5).mp4
129
+ 浙江宁波天一阁博物馆5A景区航拍 (22).mp4
130
+ 浙江绍兴城市夜景灯光交通航拍 (33).mp4
131
+ 浙江台州市政府航拍 (1).mp4
132
+ 浙江台州市政府航拍 (2).mp4
133
+ 浙江台州市政府航拍 (4).mp4
134
+ 浙江台州市政府航拍 (7).mp4
135
+ 浙江台州市政府航拍 (9).mp4
136
+ 中国蚌埠古民居博览园航拍 (14).mp4
137
+ 中国蚌埠古民居博览园航拍 (15).mp4
138
+ 珠海澳门城市风光航拍 (9).mp4
139
+ 祖国大好河山安徽滁州琅琊山景区航拍 (27).mp4
140
+ 祖国大好河山肇庆鼎湖山5A景区蝴蝶湖航拍 (7).mp4
Binary file
Binary file
package/filterFail.js ADDED
@@ -0,0 +1,40 @@
1
+ const fs = require('fs');
2
+ const readline = require('readline');
3
+
4
+ //上传失败的文件汇总到 txt中,脚本跑完后,统一便利再上传。
5
+
6
+ const logFilePath = 'log.txt';
7
+
8
+ // 创建 readline 接口实例
9
+ const rl = readline.createInterface({
10
+ input: fs.createReadStream(logFilePath),
11
+ output: process.stdout,
12
+ terminal: false
13
+ });
14
+
15
+ // 匹配视频文件名,和id = undefined
16
+ const filenameRegex = /.*\*\*\*([^*]+)\*\*\*/;
17
+ const idUndefinedRegex = /id = undefined/;
18
+
19
+ let currentFileName = '';
20
+
21
+ rl.on('line', (line) => {
22
+ // 检查是否是文件名行
23
+ if (line.includes('**************************') && !line.includes('end')) {
24
+ const match = filenameRegex.exec(line);
25
+ if (match && match[1]) {
26
+ currentFileName = match[1].trim(); // 提取并保存当前文件名
27
+ }
28
+ }
29
+
30
+ // 检查id是否未定义
31
+ if (idUndefinedRegex.test(line) && currentFileName) {
32
+ console.log(`找到undefined ID对应的文件名: ${currentFileName}`);
33
+ // 你可以在这里执行进一步操作,例如存储文件名
34
+ fs.appendFileSync('undefined-ids.txt', `${currentFileName}\n`);
35
+ }
36
+ });
37
+
38
+ rl.on('close', () => {
39
+ console.log('Finished reading file.');
40
+ });
package/index.js ADDED
@@ -0,0 +1,412 @@
1
+ const ffmpeg = require("fluent-ffmpeg");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const XLSX = require("xlsx");
5
+ const FormData = require("form-data");
6
+ const axios = require("axios");
7
+ const generateUniqueHash = require("./utils/index");
8
+
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"
20
+
21
+ const screenshotsFlodar = "output";
22
+ const screenshotsFlodarChild = "screenshots";
23
+ // 5张截图保存目录
24
+ const screenshotsDir = `${screenshotsFlodar}/${screenshotsFlodarChild}`;
25
+
26
+ //临时存储截图数组
27
+ let filenames = [];
28
+
29
+ /**
30
+ * 压缩视频
31
+ */
32
+ const batchVideoFile = (fileName) => {
33
+ const inputFilePath = videoFolderPath + "/" + fileName;
34
+
35
+ const outputFilePath = outputFolderPath + "/" + "zip-" + fileName;
36
+
37
+ const command = ffmpeg();
38
+ const videoBitrate = 4000;
39
+
40
+ // 设置目标文件大小为50MB
41
+ // const targetFileSize = 50 * 1024 * 1024;
42
+
43
+ // 获取原视频文件大小(bytes)
44
+ // const inputFileSize = fs.statSync(inputFilePath).size;
45
+
46
+ // 根据目标文件大小估算比特率
47
+ // const videoBitrate = Math.floor((targetFileSize / inputFileSize) * 1000);
48
+
49
+ // 创建 ffmpeg 实例
50
+ // 输入视频文件
51
+ 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
+ // 设置输出文件路径
68
+ .output(outputFilePath)
69
+ // 开始处理
70
+ .on("start", () => {
71
+ logger("视频开始压缩……");
72
+ })
73
+ .on("end", () => {
74
+ logger("视频压缩完成!");
75
+ resolve(outputFilePath);
76
+ })
77
+ .on("error", (err) => {
78
+ reject(err);
79
+ logger("视频压缩出错:", err);
80
+ })
81
+ .run();
82
+ });
83
+ };
84
+
85
+ /**
86
+ * 转码
87
+ */
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);
125
+
126
+ return new Promise((resolve, reject) => {
127
+ command
128
+ .on("start", () => {
129
+ logger("开始截图");
130
+ })
131
+ .on("end", (stdout, stderr) => {
132
+ logger(inputFilePath + "截图完成!!!");
133
+ resolve();
134
+ })
135
+ .on("error", (err) => {
136
+ logger(inputFilePath + "截图出错:", err);
137
+ reject(err);
138
+ })
139
+
140
+ .screenshots({
141
+ 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);
149
+ });
150
+ });
151
+ };
152
+
153
+ /**
154
+ * 删除截图文件
155
+ */
156
+ const deleteScreenshots = () => {
157
+ filenames.forEach((item) => {
158
+ const filePath = path.join("output", "screenshots", item);
159
+
160
+ fs.unlinkSync(filePath);
161
+ });
162
+ filenames = [];
163
+ }
164
+
165
+ /**
166
+ * 失败逻辑和 记录错误日志
167
+ */
168
+ const updateFail = (err) => {
169
+ logger('xxxxx数据上传失败xxxxx: ' + err);
170
+ logger(`******************************************************************end`)
171
+ deleteScreenshots();
172
+ return Promise.reject();
173
+ }
174
+
175
+ /**
176
+ * 成功逻辑和 记录普通日志
177
+ */
178
+ const updateSuccess = (id) => {
179
+ deleteScreenshots();
180
+ logger("数据上传成功!");
181
+ logger("id = " + id);
182
+ logger(`******************************************************************end`)
183
+ }
184
+
185
+ /**
186
+ * 拼接数据
187
+ * @param {number} type 1:压缩+截图 2:仅截图
188
+ * @param {object} options path路径
189
+ */
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
+ );
213
+ });
214
+
215
+ return postData(formData);
216
+ };
217
+
218
+ /**
219
+ * 数据传输
220
+ */
221
+ const postData = (data) => {
222
+ logger("等待接口返回结果……");
223
+
224
+ return axios
225
+ .post("https://designer-api.51miz.com/designer/CallBack/uploadVideoData", data, {
226
+ headers: {
227
+ "Content-Type": "multipart/form-data",
228
+ },
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
+ })
248
+ };
249
+
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
+ /**
270
+ * 脚本开始前清空截图文件夹
271
+ */
272
+ const clearDirectoryContents = (dirPath) => {
273
+ 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
+ }
293
+ } catch (error) {
294
+ console.error('清空截图文件夹失败!', error);
295
+ }
296
+ };
297
+
298
+ /**
299
+ * 解析Excel数据
300
+ */
301
+ const transitionExcelToJSON = () => {
302
+ //当前任务hash
303
+ const hashOrigin = generateUniqueHash();
304
+ 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
+ }
385
+
386
+
387
+ const run = (index) => {
388
+ logger(`----------------------------------------第${index}条----------------------------------------`)
389
+ logger(`----------------------------------------${new Date()}----------------------------------------`)
390
+
391
+ const row = jsonData[index];
392
+ if (!row) {
393
+ return;
394
+ }
395
+ task(row)
396
+ .then(() => {
397
+ taskIndex++;
398
+ run(taskIndex);
399
+ })
400
+ .catch(() => {
401
+ taskIndex++;
402
+ run(taskIndex);
403
+ })
404
+ }
405
+
406
+ for (let i = 0; i < 1; i++) {
407
+ run(i);
408
+ }
409
+
410
+ };
411
+
412
+ transitionExcelToJSON();