Typescript - 从 URL 下载文件时如何显示百分比?

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

我目前遇到的问题是,保存文件时,它只是说,

The "val" argument must be an instance of Readable, Iterable, or AsyncIterable. Received an instance of WriteStream
。另外,这里是它的示例日志:

[INFO] Retrieved video: 'Title'.
[INFO] Retrieved download URL: 'https://...'
[ERROR] An error occurred during download: The "val" argument must be an instance of Readable, Iterable, or AsyncIterable. Received an instance of WriteStream
undefined
[INFO] Video downloaded successfully.
node:events:491
      throw er; // Unhandled 'error' event
      ^

Error [ERR_STREAM_DESTROYED]: Cannot call pipe after a stream was destroyed
    at new NodeError (node:internal/errors:393:5)
    at destroy (node:internal/streams/pipeline:58:44)
    at finishImpl (node:internal/streams/pipeline:199:23)
    at finish (node:internal/streams/pipeline:186:5)
    at pump (node:internal/streams/pipeline:141:5)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Emitted 'error' event on Transform instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_STREAM_DESTROYED'
}

我期望下载文件时的日志类似于

[INFO] Downloading [=======     ] 70%
。如果node-fetch与此不兼容,您可以使用其他模块,例如http或https模块。

async download_video(video_id: string): Promise<void> {
  try {
    const fetchVideo = await this.get_video(video_id);
    console.log(
      `[INFO] Retrieved video: '${fetchVideo.title}' by ${fetchVideo.user.name} (@${fetchVideo.user.username}).`,
    );

    const fetchFileUrl = await fetch(fetchVideo.fileUrl);
    const parseJson = await fetchFileUrl.json();
    const downloadUrl = parseJson[0].src.download;
    console.log(`[INFO] Retrieved download URL: '${downloadUrl}'`);

    const response = await fetch(`https:${downloadUrl}`);

    const contentLength = parseInt(
      response.headers.get("content-length") ?? "0",
      10,
    );

    const sanitizedTitle = fetchVideo.title.replace(/[\\/:"*?<>|]/g, "");
    const filename = `${sanitizedTitle}.${fetchVideo.file.mime.split("/")[1]}`;

    let downloadedBytes = 0;

    await pipeline(
      response.body as unknown as stream.Readable,
      new stream.PassThrough()
        .on("finish", () => {
          console.log(`[INFO] Video downloaded successfully.`);
        })
        .on("error", (err) => {
          console.error(
            `[ERROR] An error occurred during saving video: ${err.message}`,
          );
        })
        .pipe(fs.createWriteStream(filename)),
      new stream.Transform({
        transform(chunk, _encoding, callback) {
          downloadedBytes += chunk.length;
          const percent = Math.round((downloadedBytes / contentLength) * 100);
          const progress =
            "[" + "=".repeat(percent / 5) + " ".repeat(20 - percent / 5) + "]";
          process.stdout.clearLine?.(0);
          process.stdout.cursorTo?.(0);
          process.stdout.write(`[INFO] Downloading ${progress} ${percent}%`);
          callback(null, chunk);
        },
      }),
    );
  } catch (err: any) {
    console.error(`[ERROR] An error occurred during download: ${err.message}`);
  }
}
typescript percentage node-fetch
© www.soinside.com 2019 - 2024. All rights reserved.