尝试使用递归,为什么我的代码只下载了4个视频并退出?

问题描述 投票:0回答:1

我正在尝试从我有权访问的 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();
javascript ffmpeg node.js-fs
1个回答
0
投票

您的脚本的主要问题似乎与 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();

此版本可确保按顺序处理每个视频,这有助于更可预测地管理应用程序的流程。此外,对异步操作使用同步循环有助于维护执行顺序和错误处理。

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.