デフォルトでリトライ設定(試行回数)のオプションがあるにも関わらず、たまに尻切れで終わってしまう現象と対策について。
youtube-dlを使い始めてなんとなく見えてきたものを(まだ不完全ながら)備忘録としてまとめてみます。
ちなみにこれはSHOWROOMの配信サービスについての話になります。今のところ他では使ったことないので・・・
youtube-dlのレジューム機能について
情報によるとyoutube-dlは「中断されても再度起動してやれば途中からレジュームしてくれる」ということでした。
が、少し勘違いをしてました。
なんでもかんでも無条件にレジュームしてくれるはずもなく、
実際には
その配信が継続していても一応の形で正常終了していれば(動画ファイルが生成されていれば)、継続してダウンロードはなされない。
保存中には「.part」ファイルが作られますが、なんらかの形で異常終了した場合それがそのまま残ります。そんな時は続きから再開してくれる、ということらしい。
逆に言えば仮に ctrl + c などで中断させたとしても異常終了とはならず、再び保存を試みても「すでにダウンロード済み」として再開してくれません。
例:youtube-dl logs(Showroom)
[ShowRoomLive] xxxxxxx: Downloading webpage [ShowRoomLive] xxxxxxx: Downloading JSON metadata [ShowRoomLive] xxxxxxx: Downloading JSON metadata [ShowRoomLive] xxxxxxx: Downloading m3u8 information [ShowRoomLive] xxxxxxx: Downloading m3u8 information [download] /Users/xxxx/Desktop/sample.mp4 has already been downloaded
あるいは配信中の、意図的かどうかはわかりませんが、ストリーミングURLの変更による404エラーでも同様のことが起こりえます。
つまりブラウザで見ている限りは突然動画がフリーズしても(接続エラー)、リロードすることであらためて視聴が可能になります。
読み込むURLの変更が反映されるから当然です。
しかしyoutube-dlはエラーで読めなくなった後もオプションで指定された回数、あるいはデフォルトで規定されている回数だけ同じURLに接続を試み続けます。
当然データを取得できるはずもなく、配信が終了したと判断しそれまでのデータを動画ファイルにまとめる作業に入ってしまう。
結果動画ファイルは生成され、再度起動しても続きがダウンロードされることはありません。
youtube-dlのリトライ設定(オプション)
youtube-dlのマニュアル(README.md)にはざっと見た感じ、2種類のリトライに関するオプションが用意されていました。
- -R, –retries RETRIES
- Number of retries (default is 10), or “infinite”.
- –fragment-retries RETRIES
- Number of retries for a fragment (default is 10), or “infinite” (DASH, hlsnative and ISM)
ダウンロード自体の試行回数と、
フラグメント取得の試行回数。
–fragment-retries の方は特にさわる必要はないのでさて置くとして、
問題はダウンロード自体の試行回数。
前述した通り、URLが変更されたのに同じところを見に行ってもあまり意味はありません。
それどころかリトライを繰り返すことで却って続きをダウンロードするのに遅れが生じてしまいます。
それを踏まえて設定する必要がありそうです。
対策:youtube-dlを複数回起動して補完する自作コマンド
では結局どうするか。
- 同じストリーミングURLではなくページ自体の再取得からダウンロードを試行する必要がある
- (この場合)オプションで設定するリトライの回数にあまり意味はない
- 保存先に同名の動画ファイルがある場合「ダウンロード済み」と判断されてしまう
ということを踏まえたスクリプトが必要になります。
以前書いた記事では単純に指定回数リトライするよう自作コマンドを作成しました。
#!/bin/bash RETRIES=0 until command youtube-dl "$@" || [ $RETRIES -eq 10 ]; do sleep 1 let ++RETRIES done
コマンドを実行、それが正常終了するか、試行回数が10回に達するまで1秒の間をおいて試行し続けるというスクリプトです。
これは「開始時刻を迎えるも少し遅れて配信された」なんて時には有効です。
未だオフラインなのに接続に行って失敗し、1回で諦めて保存できませんでした〜なんていう事態は回避できるかもしれません。
とは言えyoutube-dl側でも設定されたリトライの数だけ繋ぎに行くはずなので、実際には youtube-dlリトライ数 x 自作コマンドの繰り返し分 試行するはずです。
しかしこれでは少し足りません。
先に述べたように録画中、突然のURL変更による404エラーは配信終了と判断され録画を終えてしまう。
コマンドステータスでも「正常終了を意味する0」が返されることにより全ての処理を終えてしまいます。
配信は続いているにも関わらず。
これを避けるには
「たとえ正常に終了したとしても数回ダウンロードを試みる」
ということが必要になります。
そこで試行回数が10回に達するまでコマンドを実行、そして仮にコマンドが正常終了してもなお2回実行するように変えてみました。
#!/bin/bash RETRIES=0 SCSS=0 FLG=false until [ $SCSS -eq 3 ] || [ $RETRIES -eq 10 ]; do command youtube-dl "$@" && FLG=true $FLG && let ++SCSS || let RETRIES++ sleep 1 done
これで続きを保存できるようになりました。
美しくはありませんが一応機能します。
あとはファイル名とリトライ回数のオプション指定について。
出力ファイル名のオプション
-o ~/Desktop/%(title)s-%(epoch)s.%(ext)s
epoch (numeric): Unix epoch when creating the file
ファイル作成時の時刻を付与することでオリジナルのファイル名とします。
ファイルは別になりますが連続して再生するなり繋げるなりすれば事足ります。
リトライ回数のオプション
繰り返し説明しているように、もはや使われなくなったストリーミングURLに接続試行する意味はあまりありません。
デフォルトは10回ですが3回程度にしておけばなんかあった時でも十分でしょう。
--retries 3
これらのオプションは直接指定してもいいですし、configファイルを用意してそれを指定してあげてもいい。
まとめ
ということでyoutube-dlのリトライについて考察、対応してみました。
上記のスクリプトは
youtube-dler
という名前で保存し、実行権限をつけた上で
/usr/local/bin
にシンボリックリンクを置いて使っています。
本当ならこんな面倒臭いことせずとも、youtube-dlのオプションとして「ページの再取得からリトライする」というものがあれば解決するのだと思いますが・・・それを実現する技術や知識が自分にはないのでなんとも言えません。
そもそもの話としてはShowroomで同時配信されるラジオ番組を録画したいというものから始まりました。
ゆえに他の配信サイトなどでどうなるかなどは冒頭に書いた通り考慮していません。
肝心の番組は昨今の新型コロナの影響で配信休止がアナウンスされているんですけどね・・・
いずれ再開することを期待しつつ、勉強を兼ねて試行錯誤しています。
はぁ待ち遠しい。
コメント