我要一个接一个地下载视频。
也就是说,第一个应该在第二个开始之前完全下载,第二个应该在第三个开始之前完全下载,依此类推。
我具有以下目录结构-
video-downloader
├── index.js
├── videos.js
├── package.json
{
"name": "video-downloader",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"download": "^7.1.0"
},
"scripts": {
"start": "node index"
}
}
const videos = [
{
url: 'https://video.com/lesson1.mp4',
name: 'Lesson 1',
},
{
url: 'https://video.com/lesson2.mp4',
name: 'Lesson 2',
},
.
.
.
{
url: 'https://video.com/lesson2.mp4',
name: 'Lesson 100',
}
]
const fs = require('fs')
const download = require('download')
const videos = require('./videos')
const OUTPUT_DIR = 'Downloads'
fs.mkdir(OUTPUT_DIR, () => {
main()
})
const main = () => {
videos.map((video, i) => {
console.log(`Downloaded file ${i + 1} of ${videos.length} (${video.name})`)
download(video.url).pipe(
fs.createWriteStream(`${OUTPUT_DIR}/${video.name}.mp4`),
)
})
}
这将并行地逐块下载视频。所有视频都立即下载,但没有一个在另一视频开始之前完成。
如何顺序下载?
我知道我应该使用类似http://caolan.github.io/async/的东西,但是它需要一个函数签名,并且我将videos
作为数组,所以我不确定该怎么做。
答案 0 :(得分:3)
您可以在标准的循环中使用await
关键字,事情将按顺序进行,并等待每次下载后再继续操作。
const fs = require('fs')
const download = require('download')
const videos = require('./videos')
const util = require('util')
const mkdirAsync = util.promisify(fs.mkdir)
const OUTPUT_DIR = 'Downloads'
const main = async () => {
await mkdirAsync(OUTPUT_DIR)
for (let i = 0; i < videos.length; i++) {
const video = videos[i]
const data = await download(video.url)
fs.writeFileSync(`${OUTPUT_DIR}/${video.name}.mp4`, data)
console.log(`Downloaded file ${i + 1} of ${videos.length} (${video.name})`)
}
}
main()
答案 1 :(得分:2)
您可以将.reduce
与promise顺序使用,如下所示:
const fs = require('fs')
const sh = require('shelljs')
const download = require('download')
const videos = require('./videos')
const OUTPUT_DIR = 'Downloads'
sh.mkdir('-p', OUTPUT_DIR)
videos = videos.reduce((acc, item) => {
return acc.then(() => {
return new Promise((resolve) => {
// Here you are using it as a Duplex Stream, not a promise,
// therefore, you must check when the stream emits the 'end' event
// so you can proceed further
let stream = download(video.url)
.pipe(fs.createWriteStream(`${OUTPUT_DIR}/${video.name}.mp4`));
stream.on('end', () => {
console.log(`stream done ${item}`);
resolve(item);
})
})
});
}, Promise.resolve());
// 'videos' is now a promise
videos.then((lastPromise) => {
// using reduce will return the last evaluated item(promise)
// but reaching the last one means the promises before that have been resolved
console.log('all files were downloaded');
})
答案 2 :(得分:1)
尝试异步等待。首先下载,然后在同步中编写。
const fs = require('fs');
const sh = require('shelljs');
const download = require('download');
const videos = require('./videos');
const OUTPUT_DIR = 'Downloads';
sh.mkdir('-p', OUTPUT_DIR);
videos.forEach(async (video, i) => {
console.log(`Downloading ${video.name}. Fil${i + 1}/${videos.length} - `);
const data = await download(video.url);
fs.writeFileSync(`${OUTPUT_DIR}/${video.name}.mp4`, data);
});