Node.jsでYoutubeの動画ファイルをごにょごにょって話で調べるとけっこう色々なライブラリが出てきます。
今回は、更新が比較的新しいのでメンテナンスされていることに期待出来そうな、ytdl-core
というモジュールを使ってみます。使ったみた雰囲気だとffmpegを利用しないでもある程度利用できそうでした。
ちなみにコマンドラインツール版のytdlもあります。
あと、自分の動画で試してます。
環境
- Node.js 10.11.0
- npm 6.4.1
- macOS Mojave 10.4
インストール
npm i ytdl-core
DLのみ
const fs = require('fs');
const ytdl = require('ytdl-core');
const BASE_PATH = `https://www.youtube.com/watch?v=`;
const youtubeId = `9CHiwJhx3qw`; //DLするYoutube動画のID(urlのv=の後ろの部分11桁)
const url = BASE_PATH+youtubeId;
ytdl(url).pipe(fs.createWriteStream(`${youtubeId}.mp4`));
プログレス表示と動画の情報取得
DLが完了した際のイベントを取得したい時は以下のように'end'
のイベントでハンドリングできます。
こちらのサンプルコード二つを参考にしています。
https://github.com/fent/node-ytdl-core/blob/master/example/progress.js
https://github.com/fent/node-ytdl-core/blob/master/example/get_info.js
今回はreadline
も表示用に使います。
npm i readline
const fs = require('fs');
const ytdl = require('ytdl-core');
const readline = require('readline'); //表示用途
const BASE_PATH = `https://www.youtube.com/watch?v=`;
const youtubeId = `9CHiwJhx3qw`; //DLするYoutube動画のID(urlのv=の後ろの部分11桁)
const url = BASE_PATH+youtubeId;
const video = ytdl(url,{filter: (format) => format.container === 'mp4' });
let starttime;
video.pipe(fs.createWriteStream(`${youtubeId}.mp4`));
video.once('response', () => starttime = Date.now());
video.on('progress', (chunkLength, downloaded, total) => {
const floatDownloaded = downloaded / total;
const downloadedMinutes = (Date.now() - starttime) / 1000 / 60;
readline.cursorTo(process.stdout, 0);
process.stdout.write(`${(floatDownloaded * 100).toFixed(2)}% downloaded`);
process.stdout.write(`(${(downloaded / 1024 / 1024).toFixed(2)}MB of ${(total / 1024 / 1024).toFixed(2)}MB)\n`);
process.stdout.write(`running for: ${downloadedMinutes.toFixed(2)}minutes`);
process.stdout.write(`, estimated time left: ${(downloadedMinutes / floatDownloaded - downloadedMinutes).toFixed(2)}minutes `);
readline.moveCursor(process.stdout, 0, -1);
});
video.on('end', () => {
process.stdout.write('\n\n');
//DLしたYoutube動画の情報
ytdl.getInfo(youtubeId, (err, info) => {
if (err) throw err;
console.log('\n動画情報もろもろ');
console.log(info.player_response.videoDetails);
console.log('\n動画タイトル');
console.log(info.player_response.videoDetails.title);
console.log('\n秒数');
console.log(info.player_response.videoDetails.lengthSeconds);
console.log('\nサムネイル');
console.log(info.player_response.videoDetails.thumbnail);
});
});
結果はこんな感じ
$ node app.js
動画情報もろもろ
{ videoId: '9CHiwJhx3qw',
title: '【検証】うんこボタンであのイタズラは成功するか!?【予想外の展開】',
lengthSeconds: '288',
keywords: [ 'iot', 'iotlt', 'うんこボタン', 'ドッキリ', 'イタズラ', '電子工作' ],
channelId: 'UC42TOX3Ff7H0iORoPoBkAcg',
isCrawlable: true,
thumbnail: { thumbnails: [ [Object], [Object], [Object], [Object] ] },
viewCount: '298',
author: 'どっとすたぢお',
isLiveContent: false }
動画タイトル
【検証】うんこボタンであのイタズラは成功するか!?【予想外の展開】
秒数
288
サムネイル
{ thumbnails:
[ { url:
'https://i.ytimg.com/vi/9CHiwJhx3qw/hqdefault.jpg?sqp=-oaymwEiCKgBEF5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLAS-n8-TmsSRbr_gbKFLAuBY22Rkg',
width: 168,
height: 94 },
{ url:
'https://i.ytimg.com/vi/9CHiwJhx3qw/hqdefault.jpg?sqp=-oaymwEiCMQBEG5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLA0WQFxu5lN1nHd3S4qYabeCvioKA',
width: 196,
height: 110 },
{ url:
'https://i.ytimg.com/vi/9CHiwJhx3qw/hqdefault.jpg?sqp=-oaymwEjCPYBEIoBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLA3j-N0ahl91bywiKcv7vGOiD_3Pw',
width: 246,
height: 138 },
{ url:
'https://i.ytimg.com/vi/9CHiwJhx3qw/hqdefault.jpg?sqp=-oaymwEjCNACELwBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLBL4Tit-bNE3WbNMitKo2TdGrMu-A',
width: 336,
height: 188 } ] }
サムネイルが取れるの面白いですよね。
その他
ほんとはmp4じゃなくて音源だけのmp3を撮りたかったけどffmpegが必要っぽいとのことと、READMEを見る限りhighestaudio
やaudioonly
なども指定できるっぽいけど指定してDLされたファイルが壊れてしまう現象になった(謎)のでとりあえずmp4で試してみました。
バイナリが壊れる現象はオプションの指定の仕方が良くないような気がするので時間があれば再チャレンジしてみたい気持ち