19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

YouTube動画をダウンロードするWebアプリを作る

Posted at

始めに

YouTube動画をダウンロードするにあたって、無料のWebサービスはありますが、怪しい広告が表示されたりして危なかったり、煩わしかったりします。
ライブラリを使えば自作も簡単にできますので、実装内容についてまとめました。
ここでは以下のものを使って実装しています。

  • Node.js
  • TypeScript
  • ytdl-core
  • Express
  • Heroku

ローカルでYouTube動画をダウンロードする

まず始めにローカルでYouTube動画をダウンロードできるようにします。

以下の記事を参考にして、スクリプトを書きました。ただしこちらではTypeScriptを使って実装しています(と言っても型定義全くないですけど。。)。

Node.jsでYoutube動画をDLして保存するytdl-coreを使ったみたメモ

download.ts
import ytdl from 'ytdl-core';
import path from 'path';
import fs from 'fs';

const BASE_URL = 'https://www.youtube.com/watch?v=';

const YOUTUBE_ID = 'bnc1NjaXXXX';

const url = `${BASE_URL}${YOUTUBE_ID}`;

const video = ytdl(url);

video.pipe(fs.createWriteStream(path.resolve(__dirname, `./tmp/${YOUTUBE_ID}.mp4`)));

video.on('end', () => {
  console.log('file downloaded.');
});

これでmp4ファイルがダウンロードされました。mp3はffmpegで変換する必要があるようなのでchild_processで変換します。

mp3に変換
import path from 'path';
import { exec } from 'child_process';

video.on('end', () => {
  const inputFilePath = path.resolve(__dirname, `./tmp/${YOUTUBE_ID}.mp4`);
  const outputFilePath = path.resolve(__dirname, `./tmp/${YOUTUBE_ID}.mp3`);
  // ffmpegでmp3に変換する。yオプションで上書きができる(これがないと、出力先にファイルが存在している場合は止まってしまう)
  exec(`ffmpeg -y -i ${inputFilePath} ${outputFilePath}`, (error, stdout, stderr) => {
    if (error) {
      console.error(error);
      return;
    }
    console.log(stdout);
    console.log(stderr);
  });
});

ExpressでYouTube動画をダウンロードするAPIを作る

ローカルでダウンロードできるようになったので、次はExpressでサーバーを立てて、API経由でダウンロードして動画または音声を返すAPIを作ります。
/api/youtube/bnc1NjaXXXX?fileType=mp4みたいに送ったら対象のYouTubeIdをmp4またはmp3でダウンロードするようにします。

server.ts
// Youtubeのダウンロード
app.get('/api/youtube/:youtubeId', (req, res) => {
  const { youtubeId } = req.params;
  const fileType = (req.query.fileType || 'mp4') as 'mp4' | 'mp3';

  const destFilePath = path.resolve(__dirname, `./tmp/${youtubeId}.mp4`);

  const url = `https://www.youtube.com/watch?v=${youtubeId}`;
  const stream = ytdl(url, { quality: 'highest' });

  stream.pipe(fs.createWriteStream(destFilePath));

  stream.on('error', (err) => {
    console.error(err);
    res.status(400).send('download error!');
  });

  stream.on('end', () => {
    console.log(`youtube file (${youtubeId}.mp4) downloaded.`);

    // mp4の場合はそのまま返す
    if (fileType === 'mp4') {
      res.download(destFilePath);
      return;
    }

    // mp3の場合は変換してから返す
    console.log('transform mp4 -> mp3.');
    const mp3FilePath = path.resolve(__dirname, `./tmp/${youtubeId}.mp3`);
    exec(`ffmpeg -y -i ${destFilePath} ${mp3FilePath}`, (err, stdout, stderr) => {
      if (err) {
        console.error(err);
        res.status(500).send('movie translation error!');
        return;
      }
      console.log(stdout);
      console.log(stderr);
      res.download(mp3FilePath);
    });
  });
});

フロント側のリクエストは以下のようにしました。ファイルのダウンロードは直接URL遷移してもできますが、エラーの場合だとエラーページが出てしまうので、一度blobで受け取るようにしました。(どうでも良いですが、fetch APIのエラーハンドリングは一々response.okをチェックしないといけないのは面倒ですね。。)

console.log('downloading...');
// ファイルダウンロード
fetch(`/api/youtube/${youtubeId}?fileType=${fileType}`)
  .then((response) => {
    if (!response.ok) {
      throw new Error('Network error');
    }
    return response.blob();
  })
  .then((blob) => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${youtubeId}.${fileType}`;
    document.body.appendChild(a);
    a.click();
    a.remove();
  })
  .finally(() => {
    console.log('finished.');
  });
});

Herokuにデプロイする

最後にHerokuにデプロイします。ExpressをHerokuにデプロイするやり方とほぼ同じですが、今回はffmpegを入れる必要があります。こちらに書かれていたbuildpackを使用しましたが、heroku-cliを使うのが面倒だったのでGUIで入れました。

Herokuでffmpegを使えるようにする

Herokuのアプリ画面に入り、SettingsのBuildpacksというセクションでbuildpackを2つ入れます。今までは自動でheroku/nodejsが使われていたと思いますが、2つ入れる必要があるので明記する必要があります。

スクリーンショット 2021-04-04 15.17.51.png

これで無事デプロイされて動作すれば完了です。

終わりに

以上がYouTube動画をダウンロードするWebアプリを作る流れでした。今回Node.jsでYouTube動画をダウンロードしましたが、音声付きだと画質は360pしか選べなくて少し残念でした。昔PythonでダウンロードしたときはフルHDでも普通にダウンロードできた気がしたんですけどね。。

今回作成したソースとHerokuアプリは以下に上がっております。興味がある方は見てください😄

19
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?