MacでYoutube Liveストリーミングを保存するyoutube-dlスクリプト

youtube-dl is a small command-line program to download videos from YouTube.com and a few more sites. It requires the Python interpreter (2.6, 2.7, or 3.3+), and it is not platform specific. It should work in your Unix box, in Windows or in Mac OS X. It is released to the public domain, which means you can modify it, redistribute it or use it however you like.
http://rg3.github.io/youtube-dl/

Pythonは久しぶりなので全く分かりませんでしたw
のでメモ書きのみ。まぁPythonが分からなくても出来ますけどw
なお、作業はOS X Mavericks 10.9.1で行いました。

$ python --version
Python 2.7.5

必要なもの

多分ffmpegが要ると思います。適宜入れてください。
私はNHK語学講座のラジオ番組ストリーミングを取得するRubyスクリプトgogakuondemand.rb(v1804_1 2018/5/5更新版) - 別館 子子子子子子(ねこのここねこ)はてブロ部で行ったのと同様に

$ brew install ffmpeg --with-openssl --with-rtmpdump --with-libvorbis

としてインストールしました。

$ ffmpeg -version
ffmpeg version 2.1.3
built on Feb 11 2014 17:26:59 with Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
configuration: --prefix=/usr/local/Cellar/ffmpeg/2.1.3 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-nonfree --enable-hardcoded-tables --enable-avresample --enable-vda --cc=clang --host-cflags= --host-ldflags= --enable-libx264 --enable-libfaac --enable-libmp3lame --enable-libxvid --enable-libvorbis --enable-librtmp --enable-openssl
libavutil      52. 48.101 / 52. 48.101
libavcodec     55. 39.101 / 55. 39.101
libavformat    55. 19.104 / 55. 19.104
libavdevice    55.  5.100 / 55.  5.100
libavfilter     3. 90.100 /  3. 90.100
libavresample   1.  1.  0 /  1.  1.  0
libswscale      2.  5.101 /  2.  5.101
libswresample   0. 17.104 /  0. 17.104
libpostproc    52.  3.100 / 52.  3.100

インストールの前に

どうやらpipというPythonのパッケージ管理システム(PerlでのCPANRubyでのrubygemsなどに相当)でインストールできるらしいので、これを使えるようにしましょう。
検索すると「setuptoolsというものを入れてからpipを入れろ」という記事が目に入りましたが、今年1/15のありがたい記事が見つかりました。

ちなみに

pip 1.5.1からsetuptoolsのインストールが要らなくなりました。get-pip.pyが自動的に入れてくれます。
pipの使い方 (2014/1バージョン) — そこはかとなく書くよん。

この記事に従って作業を行います。

pipインストーラスクリプトをダウンロード

https://raw.github.com/pypa/pip/master/contrib/get-pip.py
をダウンロードします。

sudo権限で実行
$ sudo python get-pip.py 
Downloading/unpacking pip
  Downloading pip-1.5.2-py2.py3-none-any.whl (1.2MB): 1.2MB downloaded
Installing collected packages: pip
Successfully installed pip
Cleaning up...

これでpipがインストールされました。

pipでyoutube-dlをインストール

(pipで指定するのはハイフンでは無くアンダースコアのyoutube_dlなので注意)

$ sudo pip install --upgrade youtube_dl
Downloading/unpacking youtube-dl
  Downloading youtube_dl-2014.02.10.tar.gz (296kB): 296kB downloaded
  Running setup.py (path:/private/tmp/pip_build_root/youtube-dl/setup.py) egg_info for package youtube-dl
    
Installing collected packages: youtube-dl
  Running setup.py install for youtube-dl
    
    Installing youtube-dl script to /usr/local/bin
Successfully installed youtube-dl
Cleaning up...

インストールされた場所は

$ which youtube-dl
/usr/local/bin/youtube-dl

Youtubeダウンロード

youtube-dlスクリプトは通常のYoutubeビデオはダウンロードできると思います。(試しません)
早速、今回の目的であるYoutube Liveビデオをダウンロードしましょう。
今日やっているLiveとして

DOMMUNE 2014/02/11 - YouTube
http://www.youtube.com/watch?v=gu0qlPLOlk0

があったので、これをダウンロードします。
URLでもidentifierでも良いようですので、identifierを指定してみます。

$ youtube-dl gu0qlPLOlk0
[youtube] Setting language
[youtube] gu0qlPLOlk0: Downloading webpage
[youtube] gu0qlPLOlk0: Downloading video info webpage
[youtube] gu0qlPLOlk0: Extracting video information
[youtube] gu0qlPLOlk0: Downloading formats manifest
[download] Destination: DOMMUNE 2014_02_11-gu0qlPLOlk0.mp4
ffmpeg version 2.1.3 Copyright (c) 2000-2013 the FFmpeg developers
  built on Feb 11 2014 17:26:59 with Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/2.1.3 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-nonfree --enable-hardcoded-tables --enable-avresample --enable-vda --cc=clang --host-cflags= --host-ldflags= --enable-libx264 --enable-libfaac --enable-libmp3lame --enable-libxvid --enable-libvorbis --enable-librtmp --enable-openssl
  libavutil      52. 48.101 / 52. 48.101
  libavcodec     55. 39.101 / 55. 39.101
  libavformat    55. 19.104 / 55. 19.104
  libavdevice    55.  5.100 / 55.  5.100
  libavfilter     3. 90.100 /  3. 90.100
  libavresample   1.  1.  0 /  1.  1.  0
  libswscale      2.  5.101 /  2.  5.101
  libswresample   0. 17.104 /  0. 17.104
  libpostproc    52.  3.100 / 52.  3.100
[hls,applehttp @ 0x7ff5b4816800] Estimating duration from bitrate, this may be inaccurate
Input #0, hls,applehttp, from 'http://www.youtube.com/api/manifest/hls_playlist/id/gu0qlPLOlk0.1/itag/95/source/yt_live_broadcast/ratebypass/yes/live/1/cmbypass/yes/newshard/yes/hls_chunk_host/www.youtube.com/gir/yes/dg_shard/gu0qlPLOlk0.1_95/playlist_type/LIVE/maudio/1/cp/U0hYR1FQUV9KUENOOF9JSlVHOmlXYjlGWEZTWk1X/pmbypass/yes/fexp/926535,932293,930102,916625,937417,913434,936910,936913/sver/3/upn/lDdyFi5cVU4/ip/211.124.238.31/ipbits/8/expire/1392153656/sparams/ip,ipbits,expire,id,itag,source,ratebypass,live,cmbypass,newshard,hls_chunk_host,gir,dg_shard,playlist_type,maudio,cp,pmbypass/signature/0566DA06F609DB4B8987AA699B4528720340F33C.57D4079FDBF63A2B5672FFE766A69163BE5DEC32/key/dg_yt0/file/index.m3u8':
  Duration: 00:00:00.12, start: 2065.000000, bitrate: 248 kb/s
  Program 0 
    Metadata:
      variant_bitrate : 0
    Stream #0:0: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 90k tbn, 60 tbc
    Stream #0:1: Audio: aac ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 264 kb/s
Output #0, mp4, to 'DOMMUNE 2014_02_11-gu0qlPLOlk0.mp4.part':
  Metadata:
    encoder         : Lavf55.19.104
    Stream #0:0: Video: h264 ([33][0][0][0] / 0x0021), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 90k tbn, 90k tbc
    Stream #0:1: Audio: aac ([64][0][0][0] / 0x0040), 48000 Hz, stereo, 264 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame=  139 fps=0.0 q=-1.0 size=    1396kB time=00:00:04.60 bitrate=2485.5kbits/s
frame=  190 fps=189 q=-1.0 size=    1945kB time=00:00:06.33 bitrate=2516.2kbits/s
frame=  299 fps=115 q=-1.0 size=    2852kB time=00:00:10.01 bitrate=2333.1kbits/s
frame=  400 fps=129 q=-1.0 size=    3928kB time=00:00:13.38 bitrate=2404.3kbits/s
frame=  448 fps= 81 q=-1.0 size=    4329kB time=00:00:15.00 bitrate=2363.3kbits/s
frame=  494 fps= 82 q=-1.0 size=    4788kB time=00:00:16.53 bitrate=2372.2kbits/s
frame=  538 fps= 82 q=-1.0 size=    5225kB time=00:00:18.00 bitrate=2378.1kbits/s
frame=  577 fps= 81 q=-1.0 size=    5632kB time=00:00:19.30 bitrate=2390.4kbits/s
frame=  589 fps= 77 q=-1.0 size=    5754kB time=00:00:19.70 bitrate=2392.5kbits/s
frame=  597 fps= 57 q=-1.0 size=    5806kB time=00:00:20.01 bitrate=2376.2kbits/s
(後略)

保存ファイル名を指定しなかったので「タイトル-identifier.mp4.part」の形式で保存されました。

ダウンロード中断

いつまで経っても番組が終わらないw*1ので、ctrl-cで中断します。

frame=39090 fps= 30 q=-1.0 size=  351823kB time=00:21:51.70 bitrate=2197.2kbits/s
frame=39188 fps= 30 q=-1.0 size=  352253kB time=00:21:55.01 bitrate=2194.4kbits/s
frame=39245 fps= 30 q=-1.0 size=  352591kB time=00:21:56.90 bitrate=2193.4kbits/s
frame=39332 fps= 30 q=-1.0 size=  353054kB time=00:21:59.80 bitrate=2191.4kbits/s    
ERROR: Interrupted by user
$ frame=39336 fps= 30 q=-1.0 Lsize=  354197kB time=00:22:00.00 bitrate=2198.2kbits/s    
video:312256kB audio:41250kB subtitle:0 global headers:0kB muxing overhead 0.195321%
Received signal 2: terminating.

中断したので、動画ファイルは「DOMMUNE 2014_02_11-gu0qlPLOlk0.mp4.part」のままです。この「.part」拡張子を削除すれば、動画ファイルとして扱えるので再生可能です。

↑と書きましたが、「q」で終了してくれます。しかもctrl-cだとファイルが壊れる場合がありますorz

高解像度の動画を取得

Youtube Liveは複数解像度を提供している場合があります。確認しましょう。

$ youtube-dl --list-formats gu0qlPLOlk0
[youtube] Setting language
[youtube] gu0qlPLOlk0: Downloading webpage
[youtube] gu0qlPLOlk0: Downloading video info webpage
[youtube] gu0qlPLOlk0: Extracting video information
[youtube] gu0qlPLOlk0: Downloading formats manifest
[info] Available formats for gu0qlPLOlk0:
format code extension resolution  note 
151         mp4       72p         HLS  (worst)
132         mp4       240p        HLS 
92          mp4       240p        HLS 
93          mp4       360p        HLS 
94          mp4       480p        HLS 
95          mp4       720p        HLS  (best)

では解像度720pのbestを指定してダウンロードしましょう。

$ youtube-dl --format best gu0qlPLOlk0
[youtube] Setting language
[youtube] gu0qlPLOlk0: Downloading webpage
[youtube] gu0qlPLOlk0: Downloading video info webpage
[youtube] gu0qlPLOlk0: Extracting video information
[youtube] gu0qlPLOlk0: Downloading formats manifest
[download] DOMMUNE 2014_02_11-gu0qlPLOlk0.mp4 has already been downloaded

おっと既にダウンロードしてるよ、と言ってます。
ファイル名を変更してから再度実行。

$ youtube-dl --format best gu0qlPLOlk0
[youtube] Setting language
[youtube] gu0qlPLOlk0: Downloading webpage
[youtube] gu0qlPLOlk0: Downloading video info webpage
[youtube] gu0qlPLOlk0: Extracting video information
[youtube] gu0qlPLOlk0: Downloading formats manifest
[download] Destination: DOMMUNE 2014_02_11-gu0qlPLOlk0.mp4
ffmpeg version 2.1.3 Copyright (c) 2000-2013 the FFmpeg developers
  built on Feb 11 2014 17:26:59 with Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/2.1.3 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-nonfree --enable-hardcoded-tables --enable-avresample --enable-vda --cc=clang --host-cflags= --host-ldflags= --enable-libx264 --enable-libfaac --enable-libmp3lame --enable-libxvid --enable-libvorbis --enable-librtmp --enable-openssl
  libavutil      52. 48.101 / 52. 48.101
  libavcodec     55. 39.101 / 55. 39.101
  libavformat    55. 19.104 / 55. 19.104
  libavdevice    55.  5.100 / 55.  5.100
  libavfilter     3. 90.100 /  3. 90.100
  libavresample   1.  1.  0 /  1.  1.  0
  libswscale      2.  5.101 /  2.  5.101
  libswresample   0. 17.104 /  0. 17.104
  libpostproc    52.  3.100 / 52.  3.100
[hls,applehttp @ 0x7f986c007800] Estimating duration from bitrate, this may be inaccurate
Input #0, hls,applehttp, from 'http://www.youtube.com/api/manifest/hls_playlist/id/gu0qlPLOlk0.1/itag/95/source/yt_live_broadcast/ratebypass/yes/live/1/cmbypass/yes/newshard/yes/hls_chunk_host/www.youtube.com/gir/yes/dg_shard/gu0qlPLOlk0.1_95/maudio/1/pmbypass/yes/playlist_type/LIVE/cp/U0hYR1FRTl9KUENOOF9JS1JJOlREWVFETnRyRmtl/upn/FYw27UoOISc/sver/3/fexp/931319,919112,927905,905024,930102,929428,916626,937417,913434,936910,936913/ip/211.124.238.31/ipbits/8/expire/1392160856/sparams/ip,ipbits,expire,id,itag,source,ratebypass,live,cmbypass,newshard,hls_chunk_host,gir,dg_shard,maudio,pmbypass,playlist_type,cp/signature/6C817167FD61D118008CDB910E28D3280253FDF7.62CC4CA953C834F15C75C98A619BA588AE410157/key/dg_yt0/file/index.m3u8':
  Duration: 00:00:00.14, start: 7270.000000, bitrate: 212 kb/s
  Program 0 
    Metadata:
      variant_bitrate : 0
    Stream #0:0: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 90k tbn, 60 tbc
    Stream #0:1: Audio: aac ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 248 kb/s
Output #0, mp4, to 'DOMMUNE 2014_02_11-gu0qlPLOlk0.mp4.part':
  Metadata:
    encoder         : Lavf55.19.104
    Stream #0:0: Video: h264 ([33][0][0][0] / 0x0021), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 90k tbn, 90k tbc
    Stream #0:1: Audio: aac ([64][0][0][0] / 0x0040), 48000 Hz, stereo, 248 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame=  150 fps=0.0 q=-1.0 size=     912kB time=00:00:05.01 bitrate=1491.0kbits/s
frame=  299 fps=161 q=-1.0 size=    1826kB time=00:00:10.00 bitrate=1495.1kbits/s
frame=  422 fps=179 q=-1.0 size=    2577kB time=00:00:14.10 bitrate=1497.1kbits/s
frame=  448 fps= 86 q=-1.0 size=    2719kB time=00:00:15.01 bitrate=1483.1kbits/s
frame=  506 fps= 88 q=-1.0 size=    3105kB time=00:00:16.93 bitrate=1502.0kbits/s
frame=  597 fps= 55 q=-1.0 size=    3636kB time=00:00:20.01 bitrate=1488.7kbits/s
frame=  639 fps= 57 q=-1.0 size=    3964kB time=00:00:21.41 bitrate=1516.0kbits/s
frame=  746 fps= 44 q=-1.0 size=    4557kB time=00:00:25.00 bitrate=1493.1kbits/s
frame=  816 fps= 46 q=-1.0 size=    5053kB time=00:00:27.33 bitrate=1514.4kbits/s
frame=  895 fps= 42 q=-1.0 size=    5480kB time=00:00:30.01 bitrate=1495.6kbits/s
frame=  945 fps= 43 q=-1.0 size=    5829kB time=00:00:31.66 bitrate=1507.9kbits/s
frame= 1044 fps= 39 q=-1.0 size=    6396kB time=00:00:35.00 bitrate=1496.6kbits/s
frame= 1120 fps= 42 q=-1.0 size=    6912kB time=00:00:37.53 bitrate=1508.5kbits/s
frame= 1193 fps= 38 q=-1.0 size=    7320kB time=00:00:40.02 bitrate=1498.3kbits/s
frame= 1248 fps= 39 q=-1.0 size=    7708kB time=00:00:41.83 bitrate=1509.3kbits/s
frame= 1330 fps= 41 q=-1.0 size=    8185kB time=00:00:44.56 bitrate=1504.5kbits/s
frame= 1342 fps= 37 q=-1.0 size=    8242kB time=00:00:45.01 bitrate=1499.9kbits/s
frame= 1491 fps= 35 q=-1.0 size=    9159kB time=00:00:50.00 bitrate=1500.4kbits/s
frame= 1533 fps= 36 q=-1.0 size=    9465kB time=00:00:51.40 bitrate=1508.5kbits/s
frame= 1617 fps= 37 q=-1.0 size=    9961kB time=00:00:54.20 bitrate=1505.4kbits/s    
(ctrl-c)
ERROR: Interrupted by user
$ frame= 1639 fps= 35 q=-1.0 Lsize=   10127kB time=00:00:55.01 bitrate=1508.0kbits/s    
video:8379kB audio:1719kB subtitle:0 global headers:0kB muxing overhead 0.296599%
Received signal 2: terminating.

どうやら今回は、指定してなくてもbestをダウンロードしてたようですw

複数解像度の同時ダウンロードは(無理でした)

同時ダウンロードできるか試しましたが、

$ youtube-dl --format 151/95 gu0qlPLOlk0

の場合は151(worst)でダウンロードし、

$ youtube-dl --format95/151 gu0qlPLOlk0

の場合は95(best)でダウンロードしました。
複数解像度のダウンロードの順序を指定しているだけでした。
なお、数字でもbest/worstでも同じことでした。

同じようなgemは無いのか

Ruby使いとしてはrubygemsに同様のgemが無いか気になりました。
GitHub - rb2k/viddl-rb: An extendable commandline video downloader for flash video sites like vimeo, youtube, ...というのが近いかと思いましたが、残念ながらYoutube Liveには対応していませんでした。

$ viddl-rb http://www.youtube.com/watch?v=gu0qlPLOlk0
Loading Plugins
Plugins loaded: [ViddlRb::ArtePlusSeven, ViddlRb::Blip, ViddlRb::Metacafe, ViddlRb::Soundcloud, ViddlRb::Veoh, ViddlRb::Vimeo, ViddlRb::Youtube]
Will try to extract audio: false.
Analyzing URL: http://www.youtube.com/watch?v=gu0qlPLOlk0
Using plugin: ViddlRb::Youtube
[YOUTUBE] ID FOUND: gu0qlPLOlk0
Error: Error while running the "ViddlRb::Youtube" plugin. Maybe it has to be updated?
Error: undefined method `split' for nil:NilClass.
Backtrace:
(eval):207:in `extract_download_urls'
(eval):195:in `parse_stream_map'
(eval):170:in `extract_urls_formats'
(eval):108:in `grab_url_embeddable'
(eval):93:in `process'
(eval):79:in `grab_single_url_filename'
(eval):62:in `get_urls_and_filenames'

とエラーになりました。
もう一つ、

北海道on天気ライブカメラ  HTB's Weather Live Cameras in Hokkaido - YouTube
http://www.youtube.com/watch?v=1T8HQLQz76c

というのをダウンロードしようとした際には

$ viddl-rb http://www.youtube.com/watch?v=1T8HQLQz76c
Loading Plugins
Plugins loaded: [ViddlRb::ArtePlusSeven, ViddlRb::Blip, ViddlRb::Metacafe, ViddlRb::Soundcloud, ViddlRb::Veoh, ViddlRb::Vimeo, ViddlRb::Youtube]
Will try to extract audio: false.
Analyzing URL: http://www.youtube.com/watch?v=1T8HQLQz76c
Using plugin: ViddlRb::Youtube
[YOUTUBE] ID FOUND: 1T8HQLQz76c
[YOUTUBE] VIDEO IS NOT EMBEDDABLE
[YOUTUBE] VIDEO IS REMOVED

とのエラーになりました。

ので、youtube-dlを使った方がよさそうです。もしくは自分でUIをつくるか(youtube-dlもffmpegにパラメータ渡してるだけでしょうから)。



2017/4/26追記:
YouTubeのフォーマット(サイズや品質などの違う動画・音声)の指定について、参考になるサイトがあったので引用。

FORMAT SELECTION

formatオプションで使用する。使用可能なformat codeは--list-formatsで確認できる。
format codeを指定する。

 -f 22

こんな指定の仕方も出来る。best, worst, bestvideo, worstvideo, bestaudio, worstaudioがある。

 -f best

細かく絞り込む事も出来る。

 -f "best[height=720]"
 -f "[filesize>10M]"
 -f "[height <=? 720][tbr>500]"

カンマで複数指定出来る。

 -f 136/137/mp4/bestvideo,140/m4a/bestaudio

優先順位を指定する。22がなければ17、それもなければ18をダウンロードする。

 -f 22/17/18

映像と音声のformat codeを別々に指定する事も可能。指定方法は<video format> + <audio format>。ただしffmpegかavconvのどちらかが必要。

 -f bestvideo+bestaudio

こんな指定の仕方も可能。この場合高さ480以下のmp4とwebmをダウンロードする。

 -f "(mp4,webm)[height<480]"

同じサイトで「音声のみ」とかのオプションも書いていてくれている。感謝。

Post-processing Options

 -x, --extract-audio

動画を音声のみに変換する。

 --audio-format FORMAT

音声フォーマットを指定する。best, aac, vorbis, mp3, m4a, opus, wavのいずれか。

 --audio-quality QUALITY

音声変換時のクオリティを指定。VBRなら0-9、CBRなら128Kなど

 --recode-video FORMAT

映像フォーマットを指定のフォーマットに変換する。

(以下略)

*1:もちろん番組終了まで録画すれば、ちゃんと終わります