我正在尝试从我有权访问的 API 下载视频。这应该循环遍历从 API 调用返回的所有视频,将它们保存到光盘,使用 ffmpeg 验证来自 API 的元数据(此步骤是必要的,因为 API 有时返回不正确的信息),然后保存归属信息如果没有错误则继续。但是,下面代码的输出很简单:
[]
Download Done: 0
Saved 'Owner: Anthony �; Owner URL: https://www.pexels.com/@inspiredimages' to animals.txt
13
0
Download Done: 1
Saved 'Owner: PMA; Owner URL: https://www.pexels.com/@pma-1470250' to animals.txt
35
1
Download Done: 2
Saved 'Owner: Pressmaster; Owner URL: https://www.pexels.com/@pressmaster' to animals.txt
65
2
Download Done: 3
Saved 'Owner: Ruvim Miksanskiy; Owner URL: https://www.pexels.com/@digitech' to animals.txt
75
3
没有错误,没有退出代码。只是停止运行。我已经在脑子里重复了这个过程几次,但我不明白为什么它只被调用了四次。有人知道我可以在哪里尝试故障排除吗?
代码在这里:
require("dotenv").config();
const axios = require("axios");
const concat = require("ffmpeg-concat");
const fluent = require("fluent-ffmpeg");
const fs = require("fs");
const PEXELS_API_KEY = process.env.PEXELS_API_KEY;
const SUBTOPIC = "animals";
const URLBase = `https://api.pexels.com/videos/search?query=${SUBTOPIC}&per_page=80&size=medium&orientation=landscape`;
let rVideos;
let videosToConcat = [];
let duration = 0;
let current = 0;
const fetchVideos = async () => {
const response = await axios.get(URLBase, {
headers: {
Authorization: PEXELS_API_KEY,
},
});
return response.data.videos;
};
const writeVideoToDisc = async (videoObj) => {
let found = false;
videoObj.forEach(async (file, index) => {
if (
found === false &&
file.quality === "hd" &&
file.width === 1920 &&
file.height === 1080 &&
file.file_type === "video/mp4"
) {
found = true;
let writer = fs.createWriteStream("raw/" + current + ".mp4");
let streamResponse = await axios({
url: rVideos[current].video_files[index].link,
method: "get",
responseType: "stream",
});
streamResponse.data.pipe(writer);
writer.on("finish", () => {
console.log(`Download Done: ${current}`);
fluent.ffprobe(`./raw/${current}.mp4`, (err, metadata) => {
if (err) {
console.error(err);
} else {
if (
metadata.streams[0].width !== 1920 ||
metadata.streams[0].height !== 1080
) {
fs.unlink(`./raw/${current}.mp4`, (err) => {
if (err) throw err;
console.log("File deleted!");
});
} else {
duration += rVideos[current].duration;
videosToConcat.push(`./raw/${current}.mp4`);
fs.appendFile(
`./attribution/${SUBTOPIC}.txt`,
`Owner: ${rVideos[current].user.name}; Owner URL: ${rVideos[current].user.url} \n`,
function (err) {
if (err) throw err;
console.log(
`Saved 'Owner: ${rVideos[current].user.name}; Owner URL: ${rVideos[current].user.url}' to ${SUBTOPIC}.txt`
);
if (duration < 600) {
console.log(duration);
console.log(current);
current++;
writeVideoToDisc(rVideos[current].video_files);
}
}
);
}
}
});
});
writer.on("error", () => console.error("Error while dowloading video"));
}
});
};
const main = async () => {
rVideos = await fetchVideos();
console.log(rVideos.length);
await writeVideoToDisc(rVideos[current].video_files);
console.log(videosToConcat);
// concat videos together
};
main();
您的脚本的主要问题似乎与 forEach 循环中如何处理异步操作有关。这可能会导致操作未按顺序完成的情况,这似乎会导致脚本行为不可预测。此外,还需要解决错误处理和循环终止方面的潜在问题。这是脚本的修订版本,其中包含一些建议的更改:
异步处理:将 forEach 循环替换为 for 循环,以确保异步操作在继续下一个视频之前以正确的顺序完成。
错误处理:正确处理错误至关重要,尤其是在处理文件操作和网络请求时。这包括处理流响应、文件写入和元数据提取中的错误。
循环终止和进度跟踪:在继续递归调用或移至下一个视频之前检查条件,确保循环正确终止。
这是修改后的代码:
require("dotenv").config();
const axios = require("axios");
const fluent = require("fluent-ffmpeg");
const fs = require("fs");
const PEXELS_API_KEY = process.env.PEXELS_API_KEY;
const SUBTOPIC = "animals";
const URLBase = `https://api.pexels.com/videos/search?query=${SUBTOPIC}&per_page=80&size=medium&orientation=landscape`;
const fetchVideos = async () => {
const response = await axios.get(URLBase, {
headers: { Authorization: PEXELS_API_KEY },
});
return response.data.videos;
};
const writeVideoToDisc = async (videoObj, current) => {
for (let index = 0; index < videoObj.length; index++) {
const file = videoObj[index];
if (file.quality === "hd" && file.width === 1920 && file.height === 1080 && file.file_type === "video/mp4") {
try {
const path = `./raw/${current}.mp4`;
const writer = fs.createWriteStream(path);
const streamResponse = await axios({
url: file.link, method: "get", responseType: "stream"
});
streamResponse.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on("finish", resolve);
writer.on("error", reject);
});
console.log(`Download Done: ${current}`);
const metadata = await new Promise((resolve, reject) => {
fluent.ffprobe(path, (err, metadata) => {
if (err) return reject(err);
resolve(metadata);
});
});
if (metadata.streams[0].width !== 1920 || metadata.streams[0].height !== 1080) {
fs.unlinkSync(path);
console.log("File deleted due to incorrect metadata!");
} else {
const attributionText = `Owner: ${videoObj.user.name}; Owner URL: ${videoObj.user.url} \n`;
fs.appendFileSync(`./attribution/${SUBTOPIC}.txt`, attributionText);
console.log(`Saved '${attributionText}' to ${SUBTOPIC}.txt`);
}
} catch (error) {
console.error(`Error processing video ${current}: ${error}`);
}
break; // Exit the loop after processing the first valid file
}
}
};
const main = async () => {
const rVideos = await fetchVideos();
console.log(rVideos.length);
for (let i = 0; i < rVideos.length; i++) {
await writeVideoToDisc(rVideos[i].video_files, i);
}
};
main();
此版本可确保按顺序处理每个视频,这有助于更可预测地管理应用程序的流程。此外,对异步操作使用同步循环有助于维护执行顺序和错误处理。
希望这有帮助!