tools_batch_files 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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();