動画ダウンロードツール youtube-dl のフォークである yt-dlp を使ってみる


🍈はじめに

ひさしぶりに youtube-dl (2021.06.06) を使ったらダウンロード速度が 80KB/s 程度ですごく遅い。
ネット環境のせいかと思ったらそうでもないらしい。
この GitHub Issue によると、修正されるまでは youtube-dl フォークの yt-dlp を使ったほうがいいみたい。

なので yt-dlp をインストールして使ってみる。

Table 1. 環境
App Version

Debian

10 (WSL)

yt-dlp

2021.12.01

Pythonツールについて
Windows のパスや文字エンコード、コマンドプロンプトと相性が悪い。
よって Windows 環境ではなく、 WSL の中でインストールするのがいい。

使用前の注意事項

違法ダウンロードや著作権侵害など、法に触れないよう気をつけてください。
推しの動画は Youtube などの動画プラットフォーム上で再生するのが一番いい。
再生数や広告収入を増やしたり、コメントつけたりして応援しようね!

🚀インストール

WSL 環境下でインストールしている。
Example 1. yt-dlp インストール
バイナリをダウンロード
cd /usr/local/bin
sudo curl \
    -SsLO https://github.com/yt-dlp/yt-dlp/releases/download/2021.12.01/yt-dlp
curl -SsL https://github.com/yt-dlp/yt-dlp/releases/download/2021.12.01/SHA2-256SUMS \
    | grep 'yt-dlp$' \
    | sha256sum --check
yt-dlp: OK

sudo chmod a+rx yt-dlp
バージョン確認
yt-dlp --version
2021.12.01

また、推奨オプションである ffmpeg もインストールしておく。

Example 2. ffmpeg インストール
sudo apt update
sudo apt install ffmpeg

🎙️使い方

ダウンロードしたり情報取得したりする方法は、ほぼ youtube-dl と同じ。
ただし、いくつかのオプションは廃止予定または非推奨になっている。

Example 3. 基本
動画ダウンロード
yt-dlp https://<VIDEO_URL>
ダウンロード先ディレクトリを指定
yt-dlp --paths '/path/to/download/dir' https://<VIDEO_URL>
動画のメタデータを利用してファイルパスを指定
yt-dlp --output '~/video/%(artist)s/%(title)s.%(ext)s' https://<VIDEO_URL>

以下、よく使いそうなオプションを抜粋。

シミュレーション・テスト

設定を確認するときによく使うオプション。

Option Desc

--simulate

動画のダウンロードはせず、他すべての書き込みもしない。

--skip-download

動画のダウンロードはしない。

--verbose

実行時の詳細情報を表示する。
設定変更やエラー発生時の確認に利用する。

情報取得

Option Desc

--print <TEMPLATE>

Output Template の各フィールド名または書式を利用して動画の情報を表示する。
複数回の指定可能。

--list-formats

指定可能なフォーマットの一覧を表示する。

上記オプションを利用すると、自動的に --simulate モードとみなされる。
Example 4. --print の使用例
動画タイトル
yt-dlp --print title https://www.youtube.com/watch?v=S8dmq5YIUoc
Kizuna AI - AIAIAI (feat. 中田ヤスタカ)【Official Music Video】

yt-dlp --print track https://www.youtube.com/watch?v=S8dmq5YIUoc
AIAIAI (feat. 中田ヤスタカ)
作者名
yt-dlp --print '%(artist,creator,uploader)s' https://www.youtube.com/watch?v=S8dmq5YIUoc
Kizuna AI (キズナアイ)
チャンネル名
yt-dlp --print channel https://www.youtube.com/watch?v=S8dmq5YIUoc
A.I.Channel

ダウンロードする

Option Desc

--paths <[TYPES:]PATH>

ダウンロード先のパスを指定する。
TYPES では temp を指定して一時ダウンロード先を指定できる。

--output <[TYPES:]TEMPLATE>

出力ファイルパスを指定する。
Output Template 構文を利用できる。

--format <FORMAT>

動画フォーマットを指定する。

--write-thumbnail

サムネイル画像を一緒にダウンロードする。
--skip-download オプションを同時指定すると、
サムネイルのみダウンロードできる。

--embed-metadata
or --add-metadata

動画ファイルにメタデータを埋め込む。

--batch-file <FILE>

1行ごとに URL を列挙したファイルを読み込み、それぞれダウンロードする。
ハイフン(-)を指定すると標準入力から読み込む。

--datebefore DATE ,
--dateafter DATE

動画投稿日の以前/以降でフィルタリングする。
書式は YYYYMMDD または
(now|today)[+-][0-9](day|week|month|year)(s)?

ダウンロードURL
プレイリストの URL を指定すれば、各動画をそれぞれダウンロードできる。
--paths と --output

次のような使い分けをすればいいと思う。

--paths

ダウンロード先のベースディレクトリ(~/MyVideo とか)を指定。

--output

各動画によって異なる情報(タイトルとか投稿日とか)を用いるディレクトリ・ファイルパスを指定。

Example 5. ダウンロード実行例
ダウンロードしたファイル名に動画タイトルと投稿日を利用
yt-dlp --output '%(title)s_%(upload_date)s.%(ext)s' $VIDEO_URL
プレイリストにある各動画をダウンロード
yt-dlp \
    --output '%(uploader)s/%(title)s.%(ext)s' \
    https://www.youtube.com/playlist?list=PL0bHKk6wuUGLWGipKSf0dFrpuzDitERqD
日付でフィルタリング
yt-dlp \    (1)
    --dateafter '20200101' \
    --datebefore '20200601' \
    https://www.youtube.com/playlist?list=PL0bHKk6wuUGLWGipKSf0dFrpuzDitERqD
1 2020/01/012020/06/01 までに投稿された動画をダウンロードする。
高画質な動画に設定し、投稿者ごとにフォルダ分けする
yt-dlp \
    --format best \    (1)
    --output '%(uploader)s/%(title)s.%(ext)s' \     (2)
    $VIDEO_URL
1 フォーマットで高画質な動画(音声含む)に設定。
2 <投稿者>/<タイトル>.<拡張子> ファイルとして出力する。
URLリストを読み込んでそれぞれダウンロード
yt-dlp --batch-file download.list

# Specify the line range (1-10 lines)
sed --quiet '1, 10p' download.list | yt-dlp --batch-file -

フォーマット指定について

よく使いそうなものを一部抜粋。
詳細は README#Format Selection を参照。
また、フィルタリングについては README#Filtering Formats を参照。

Table 2. フォーマット指定の例
Format Desc

bestvideo*+bestaudio/best

最高品質の動画と音声をそれぞれダウンロードした後にマージする[1]
最高品質の動画がない場合、高画質な音声あり動画(best)をダウンロードする。
(デフォルト値)

bestvideo*

最高品質の動画をダウンロード。音声が含まれる場合もある[2]

bestaudio

最高品質の音声のみをダウンロード。

best

音声ありの動画の中で高画質なものをダウンロードする。

ID 番号

yt-dlp --list-formats で確認できるフォーマットの ID 番号を直接指定できる。

最高品質のものは動画と音声が別れている。
Table 3. フォーマット指定で使える演算子
Operator Desc

/

フォーマットの優先順位をつける。
左側に指定したフォーマットほど優先度が高い。

,

同じ動画で複数のフォーマットをダウンロードしたいときに使う。

+

動画と音声のフォーマットを個別に指定して、
ダウンロード後にマージさせる[1]

Post Processing

Option Desc

--merge-output-format <FORMAT>

動画と音声をマージするときのコンテナフォーマットを指定する(mkv, mp4, ogg, webm, flv)。
もちろん、マージする必要がなければ無効。

--remux-video <FORMAT>

動画を別のコンテナフォーマットに変換する。
mp4, mkv, webm, avi, mp3, opus, etc…​)

--exec <COMMAND>

yt-dlp による処理完了後に実行するコマンドを指定する。
引数として Output Template 構文を利用できる。
(複数回の指定・実行が可能)

🔬高度な機能

Output Template とメタデータの変更方法について説明。

Output Template

--output--exec オプションで利用できるテンプレート。
動画のタイトルやチャンネル名などを取得してファイルパスに利用することができる。

yt-dlp では Output Template が強化されており、フォーマットの指定が便利になっている。
詳しくは README を参照。

基本の書式は %(FIELD_NAME)FORMAT_TYPE となる。

Example 6. Output Template サンプル
https://www.youtube.com/watch?v=BaW_jenozKc の場合の例
'%(title)s.%(ext)s'         # -> youtube-dl test video "'/\ä↭𝕐.webm
'%(upload_date>%Y-%m-%d)s'  # -> 2012-10-02
'%(creator)s'               # -> NA  (欠損値)
'%(uploader)s'              # -> Philipp Hagemeister
'%(creator,uploader)s'      # -> Philipp Hagemeister

# Compare by format type
'%(channel)s'      # -> Philipp Hagemeister
'%(channel)j'      # -> "Philipp Hagemeister"
'%(channel)q'      # -> 'Philipp Hagemeister'
'%(tags)s'         # -> ['youtube-dl']
'%(tags)j'         # -> ["youtube-dl"]
'%(tags)q'         # -> '['"'"'youtube-dl'"'"']'

Table 4. フィールド(一部抜粋)
Variable Desc

title

動画のタイトル

creator

動画の作者名

channel

動画をアップロードしたチャンネル名

ext

動画ファイル拡張子

upload_date

アップロード日(YYYYMMDD

Table 5. フォーマット型(一部抜粋)
Type Desc

s

文字列として変換。

d

符号付き整数(10進法)。

f

浮動小数点数。

j

JSON 形式の値に変換。

q

必要ならシェルのためにクォーテーションがつけられる[3]

文字数制限
たとえば %(title).50s のように .<数値> を挟めば文字数上限を設定できる。
(参考: Handle Long filenames in default template and temporary files · Issue #1136 · yt-dlp/yt-dlp · GitHub

メタデータの変更

yt-dlp が取得したメタデータは --parse-metadata--replace-in-metadata オプションを使って修正・変更することができる。
これらのオプションで修正・変更したメタデータは Output Template で使われる。

--parse-metadata FROM:TO
Desc

FROM

元々のメタデータから抽出される、変更前の値。
フィールド名または Output Template 構文で指定する。

:

区切り文字。

TO

FROM の値から各フィールドを抽出するパターンを指定。
指定されたフィールドは抽出された値で更新される。
パターンには Output Template 構文や python の名前付きグループ[4]を用いた正規表現を使用する。

python 正規表現
re --- 正規表現操作 — Python 3.10.0b2 ドキュメントを参照。
名前付きグループの書式は (?P<name>…​) となる。
Example 7. --parse-metadata の例
元のメタデータ
yt-dlp --print 'title' --print 'artist' S8dmq5YIUoc
Kizuna AI - AIAIAI (feat. 中田ヤスタカ)【Official Music Video】
Kizuna AI (キズナアイ)
<code>title</code> フィールドから <code>artist</code> と <code>title</code> の値を抽出して更新
yt-dlp \
    --parse-metadata 'title:%(artist)s - %(title)s' \    (1) (2)
    --print 'title' --print 'artist' S8dmq5YIUoc
AIAIAI (feat. 中田ヤスタカ)【Official Music Video】
Kizuna AI

yt-dlp \
    --parse-metadata 'title:(?P<artist>.+?) - (?P<title>.+?) .*' \   (1) (3)
    --print 'title' --print 'artist' S8dmq5YIUoc
AIAIAI
Kizuna AI
1 動画タイトルからアーティスト名とタイトル名を分離抽出して、それぞれのフィールドを更新している。
2 Output Template 構文を利用。
3 python の正規表現を利用。
<code>upload_date</code> と <code>title</code> を組み合わせた文字列で <code>title</code> 値を更新
yt-dlp \
    --parse-metadata '%(upload_date)s_%(title)s:%(title)s' \    (1)
    --print 'title' S8dmq5YIUoc
20190329_Kizuna AI - AIAIAI (feat. 中田ヤスタカ)【Official Music Video】
1 タイトルに投稿日を追加させる修正。
複数の重ね合わせが可能
yt-dlp \
    --parse-metadata 'title:(?P<artist>.+?) - (?P<title>.+?) .*' \
    --parse-metadata '%(upload_date)s@%(artist)s@%(title)s:%(title)s' \
    --print 'title' S8dmq5YIUoc
20190329@Kizuna AI@AIAIAI
新しいフィールドを追加
yt-dlp \
    --parse-metadata 'artist:%(new_item)s' \
    --print 'new_item' S8dmq5YIUoc
Kizuna AI (キズナアイ)
埋め込みメタデータの値を変更したい
対象フィールド名に接頭辞 meta_ をつけて修正すればいい。
詳しくは README#Modifying Metadata を参照。

⚙️設定ファイル

いつも使うオプションは設定ファイルに記述しておくと便利。

設定ファイルの配置場所は候補がいくつかあるけど、とりあえず ~/.config/yt-dlp/config ファイルに記述すればよさそう。

オプションの優先度
yt-dlp コマンドに直接オプションを指定したほうが優先される。
Example 8. yt-dlp の設定ファイル例

設定の書式はオプションごとに改行したリストになる。

~/.config/yt-dlp/config
### Default configuration

# Modify metadata   (1)
# variables
--parse-metadata '%(creator,uploader,channel)s:%(mod_creator)s'
# for embedding     (2)
--parse-metadata '%(track,title)s:%(meta_title)s'
--parse-metadata '%(upload_date>%Y-%m-%d)s:%(meta_date)s'
--parse-metadata '%(artist,mod_creator)s:%(meta_artist)s'
--parse-metadata '%(album_artist,channel)s:%(meta_album_artist)s'
--parse-metadata '%(track_number|1)s:%(meta_track)s'
--parse-metadata '%(description).500s:%(meta_description)s'
--parse-metadata 'Please show description:%(meta_synopsis)s'

# Download base directory
--paths "/mnt/d/video/yt-dlp"   (3)

# Save file path
--output '%(mod_creator)s/%(meta_date)s@%(meta_title)s/%(meta_title)s.%(ext)s'

# To be referenced from Windows
--windows-filenames     (4)

# With thumbnail image
--write-thumbnail       (5)
--output 'thumbnail:%(mod_creator)s/%(meta_date)s@%(meta_title)s/cover.%(ext)s'

# Embed metadata
--add-metadata

# Video Format
--format 'bestvideo+bestaudio/best' (6)

# Post Processing
# Export metadata in same directory (7)
--exec "jq --null-input --sort-keys '{ title: %(title)j, id: %(id)j, date: %(meta_date)j, tags: %(tags|[])j, url: %(webpage_url)j, artist: %(meta_artist)j,  channel: %(channel)j, channel_id: %(channel_id)j }' > \"$(dirname %(filepath)q)/%(id)s.info.json\""
1 動画のメタデータを変更。
2 埋め込み用メタデータの値を修正している。
3 出力先ルートディレクトリを指定。
4 Windows と共有するのでファイル名に互換性をもたせる。
5 サムネイル画像も一緒にダウンロード。
また、画像ファイル名が cover.<ext> になるように指定。
6 動画フォーマットを指定。
指定方法やフィルタリングについては README#Format Selection を参照。
7 ダウンロード処理実行後に jq コマンドを通して[5]メタデータの一部を出力している。
メタデータ

--write-info-json オプションを使うとメタデータを出力してくれるんだけど、あらゆる情報が大量に出力される(4MB 以上になったりする)。
そのためメタデータの一部だけを抽出するのに --exec オプションを利用している。

……ただ、Linuxなら[6] tmpfs なディレクトリに --wirte-info-json で書き出した後に jq で抽出したほうがよさそう……。

🛠️トラブルシューティング

Output Template 周りのエラー

だいたい 末尾のフォーマット型のつけ忘れ が原因。
まずエラーが起こったらつけ忘れを疑うべき。

❌つけ忘れ!!!
--output '%(upload_date) %(title).%(ext)'
⭕ヨシ!
--output '%(upload_date)s %(title)s.%(ext)s'

‘python’: No such file or directory

エラー
yt-dlp --version
/usr/bin/env: ‘python’: No such file or directory
原因
python3しかない
which python    # Nothing!
which python2   # Nothing!
which python3
/usr/bin/python3
対策

update-alternatives コマンドで python/usr/bin/python3 を参照するように設定すればいい。

sudo update-alternatives --install /usr/local/bin/python python /usr/bin/python3 40
update-alternatives: using /usr/bin/python3 to provide /usr/local/bin/python (python) in auto mode

update-alternatives --query python
Name: python
Link: /usr/local/bin/python
Status: auto
Best: /usr/bin/python3
Value: /usr/bin/python3

Alternative: /usr/bin/python3
Priority: 40
単にシンボリックリンクを張るのでも解決するが、alternatives システムを利用することが推奨される。

1. マージするには ffmpeg が必要。
2. 絶対に音声を含みたくない場合は、末尾の * を取り除く。
3. 文字列に含まれる記号によってはとんでもないことになる……。
4. グループの名前がフィールド名に相当する。
5. jq コマンドを通すと Unicode 符号をいい感じに解釈してくれる。
6. WSL では tmpfs の実態がメモリではなくファイルになってしまうので残念。