以前、作って運用しつつもブラッシュアップ中のRaspberry Pi 3 Model B+とJulius、Open JTalkベースの自作スマートスピーカーがあります。
主な機能は、
尚、ラズパイ用ACアダプタを挿したスイッチ付きコンセントでのON/OFFとは別にラズパイ用boot/reboot/shutdown物理ボタン付き。
音声認識にJuliusを使った自作スマートスピーカーに伝言とメモの機能を実装するにあたり、マイクとスピーカーを専有してしまうOSSやALSAからPulseAudioに移行しました。
ちなみに便利なのでラズパイだけでなく、PC/Debianにも自作スマートスピーカー機能を搭載しています。
自ずとモニタ付きとなるPC版スマートスピーカーには、PC及びラズパイ双方のスマートスピーカー機能のデスクトップアプリとしてPyQt5/Qt Designerによる操作パネルも作成しました。
今回は、ラズパイ・Julius・Open JTalk自作スマートスピーカーやPCに入れた自作スマートスピーカー機能でログインや動画のダウンロードせずにYouTubeミュージック動画の楽曲をストリーミングしつつ、プレイリストのシャッフル再生、スキップ、停止といった操作をできるようにしてみました。
PC版はともかくラズパイスマートスピーカーにはディスプレイを搭載していないので動画は不要、特定の楽曲ではなく、BGMとして音楽をかけ流ししたい、新/旧・邦楽/洋楽問わずなら平日8時〜21時30分に限られるものの、ラジオNIKKEI第2(RN2)や有志であることもあり、突如消滅することはあるもICECASTでジャズやクラシック、ロック等々既に取り入れていますが、最新の音楽や邦楽というくくりでも聴きたいとなれば、YouTubeやAmazon Music、Spotify、LINEミュージックなどストリーミングサービスが候補に。
ただ、クラウドに個人情報や利用状況が上がることに抵抗があるからこそ、敢えてローカルで完結するJulius/Open JTalkを使ったスマートスピーカーを自作した自身としては、自分の音楽的趣味嗜好や視聴時間帯なども日々晒したくはないので会員登録・ログインはしたくない...となると視聴可能動画の数に差はあるにせよ、YouTube一択かなと。
スマートスピーカーでも特定の動画・音声だけとか、1曲、2曲だとすぐに終わってしまいますし、それをリピートというのは、目的とは異なる...、気分が変わる度にスクリプト上の動画URLを書き換えるのもアナログ過ぎる、再生リストも50件、100件とあまり多いと取得するだけで時間がかかり、実用的ではない、メドレー動画なら相当時間聴取できますが、mplayerでshuffleできない為、毎回同じ曲から開始となり微妙...。
が、一瞬、実用的ではないかとも思ったものの、違法になる余地のないYouTube公式のプレイリストをダウンロードするか、仮にこれがYouTube規約違反ならWebスクレイピングして相当するリストを作る、プレイリストをシャッフル、ループして動画を順次再生させればいいのか...と思うに至りました。
が、が、後にGoogle系は、JavaScriptでページを作成するようになり、YouTubeもWebスクレイピングできなくなりました...。
現在のYouTubeにおいて視聴可能な動画の数は異なるにしても会員登録やログインをしなくともブラウザでのストリーミングは、利用可能なサービスであることは言うまでもなく、YouTubeの特徴であり、人気の秘密であると言えるべきものであることは間違いないでしょう。
また、今の世の中、普通にPCなどからYouTubeコンテンツを含む動画コンテンツをCLI操作できるツールも多々流通しており、YouTubeのCLI操作も少なくともストリーミング配信なら問題ないと考えてよさ気(判断は自己責任)。
コマンドラインからyoutubeを再生するにもあるように、youtube-dlなどを使わせて頂くとYouTubeの動画+音声はもちろん、音声だけを取得することもでき、mplayerなどを併用するとストリーミング再生できます。
となれば、スクリプトに書ける、スマートスピーカーに利用できるわけです。
尚、YouTube Music(旧Google Play Music)/YouTube Music Premium会員なら可能となった模様もその後も(YouTube)利用規約には、「いかなるコンテンツもダウンロード禁止」とありますが、これなら問題ないでしょう。
ただ、ログインしない場合、プレイリストにおけるシャッフル再生含め、1から再生する以外の機能のほとんどは使えないらしく、再生・停止はどうにでもなるとしてスマートスピーカーで呼び出し都度同じ曲順というのはちょっと...、というわけで後述のようにすることで実質シャッフル機能と更に副産物的な発見があってスキップ機能を実装してみました。
予め複数曲PlayList ID(符号化されたような文字列ながら実はファイル名っぽい)だけをダウンロードしておき、スクリプト内でプレイリストをシャッフル、ループさせつつ、URI/URLを作ってyoutube-dlとmplayerで順次再生してみるという目論見。
尚、自身は、Debian(Linux)のリポジトリからではなく、pipでinstallしたyoutube-dlを一応アップグレードしつつ、使用、これによる実行ファイルパス[~/.local/bin]を通していない(環境変数[PATH]に追加していない)為、フルパス指定してあります。
[注意1] ここでは、URLにlistパラメータだけ渡していますが、当初listのみでできたものが、翌日やってみると併せてvパラメータもないとダウンロードできなくなっているリストも存在したりと、ちょっと謎な挙動(対策打たれてる!?)があったので要注意、ただ、更に謎なのは、端末から実行するとvパラメータが要るのにスクリプトからだとvパラメータがなくてもいけること...です。[追記:その後、何れもvパラメータがなくてもいけるようになりました。頻繁に意味不明な仕様変更してる?]
[注意2] 更に注意すべきは、仮にスクリプトでもそうなった場合、vパラメータに指定したid(短縮?符号化?ファイル名)がリストの更新でなくなるようなことがあった場合、URLが有効になるのか否かで、無効なら後述のようなcronやスマートスピーカー機能起動スクリプトを使う場合、書き換えを要することになることです。
[注意3] ある日突然、プレイリスト自体がなくなる可能性も...。
仮にPlaylistもコンテンツであり、ダウンロードはダメということなら、先日ICECASTでやってみた通り、WebスクレイピングでプレイリストIDもしくは、プレイリストURLを取得するという方法もあるかと。(うっ、Google全般?...JavaScriptなどを駆使ししてWebスクレイピング対策してるっぽい...。)
プレイリストについては、違法アップロードの余地がないYouTube公式の『音楽チャンネル』、『邦楽プレイリスト』から、とりあえず、『J-Pop Hotlist』(59曲)と『人気のミュージック ビデオ トップ 100 - 日本』をチョイス、曲数からして後者が有力ですが、何れにするか、はたまたこれ以外のものにするかは後で考えることにしました。
昨日まで何ごともなく、ノートPCでもラズパイでも先のコマンドラインオプションで実行できていたyoutube-dlによるダウンロードですが、今日になって、ラズパイのみ、なぜか、[--force-ipv4]オプションを付加しないとダウンロードできない事態になりました。
プレイリストだけでなく、後述のスクリプト~/tmp/sound/script/youtubejpop.shにおける個別動画ストリーミング時のyoutube-dlコマンドについても同様です。
このオプションがないと[HTTP Error 429: Too Many Requests]とか、[Unable to extract video data]といったエラーメッセージが表示され、結果何もダウンロードできませんでした。
なぜ、今日突然、しかも、ラズパイのみ...謎...。
今日突然、今度は、逆に[--force-ipv4]オプションを付加すると[ERROR: YouTube said: Unable to extract video data]とエラー表示され、ダウンロードできない事態になりました。
しかも、やはり、ラズパイのみ...謎...。
今日になってPCでも[--force-ipv4]オプション付きだとエラーに...何このタイムラグ。
ラズパイでは、更に逆に[--force-ipv4]オプションを付けないとエラーに...何この週替りな感じ...こんな使い方されるのを嫌がってるってこと?
ちなみに[--force-ipv6]オプションではダメでした。
尚、今日は、再生中で(スクリプトも変わってないため当然)、途中で勝手に停止、原因を探ったらこれだった次第。
また、時間差でPCでも起きるのか?
PC以前にラズパイでまた[Unable to extract video data]、[HTTP Error 429]。
調べてみると、このHTTPエラーコード[429]は、IPが(アクセス過多などでYouTubeから)ブラックリスト化された可能性があるとのことでルータ(光ONU)を再起動したら(IPが変わったようで)、何事もなかったかのようにプレイリストのダウンロード及びストリーミングができました。
が、それが原因だとすると解せないのが、PCとラズパイでエラーが起きるタイミングが違う(常にラズパイで先に起きる)こと...なぜ...?
電源入れるタイミングだったのかな...?
今は、PCもラズパイも同じプレイリストをダウンロードしているから...つまり、どっちも起動したときは、同じIPアドレスから同じプレイリストに2度アクセスすることになると、アクセスしすぎだろと拒否られると。
だとすれば、PCとラズパイで違うプレイリストをダウンロードすればよいのか、とやってみると何事もなくできたので、まさにそうっぽい。
ぬぬぬ...、異なるプレイリストでもダメみたいでPC(のスマートスピーカー)起動後、しばらく経ってから起動したラズパイ(スマートスピーカー)では、やはり、ダウンロードできておらず、光ONUを再起動したら(たぶん、IPが変わったら)、あっさりダウンロードできました。
あれ、同じ条件で何事もないな...、アクセスポイント(無線LANルータ)の電源入れたばっかりだったからかも...接続前にダウンロードしようとして失敗みたいな...よってプレイリストさえ変えれば、いけそう。
更に何も考えず起動ごとにダウンロードしてしまっていたのですが、起動スクリプトを変更し、PCとラズパイで1日ずらしつつ、ともに最短7日間はプレイリストをダウンロードしないように変更してみました。
んー、1つのIPで?1つのジョブで?合わせて?プレイリスト2つまで、いや?1つまでか?のダウンロード制限がかかるようになったっぽい。
まぁ、なるべく別日になるようにしているものの、今、検証上は、同時にやってみているラズパイ版とPC版があるから、もしかしたら4つ(2つ)までかも?
ブラウザ確認時、URLとして存在することを確認済みの異なるプレイリストを、それぞれ4つダウンロードしていたラズパイスマートスピーカもPC版スマートスピーカー機能でも何度試してもランダムに2つしかダウンロードできなくなってる。
うわっ、違った...。
ブラウザ上で見た時にプレイリスト上に[再生リストをループ再生]、[再生リストをシャッフル]マークのあるプレイリストしかプレイリストのダウンロードができなくなってることが判明...。
それって今時点、Youtube音楽チャンネルでは、[チャート]のみ...。
やはり、ラズパイ版スマートスピーカーを先に、続いてPC版スマートスピーカー機能共に[チャート]から選択した同じプレイリストだと後からダウンロードしたPCの方は、全くダウンロードできず、0件...、何度か試すもONUを再起動してみても同じ。
以前やったように両者でダウンロードするプレイリストを分ければいけるのか、それとも...。
あ、自身のチョンボでした...。
ダウンロード含むスクリプトでURLアドレス指定し忘れていました...。
よってPCでもラズパイでも[チャート]に限らず、ダウンロードはでき、スマートスピーカーとして機能します。
それとダウンロードできたラズパイの方は、途中で止まる現象が頻発するようになった...時には、プチンと曲の途中で、時には、ちょうど曲の区切りで...原因不明。
極端にボリュームの低い楽曲が混ざっていて聴こえないというケースもありました。
その場合は、スキップしてしのいでます。
JPOPとPOPSのみ利用しているYouTube、相変わらず、スマートスピーカーから再生して、かけながしていると突然止まる現象があるのですが、何気なくネット検索してたら、最近、ブラウザ上でYouTubeのプレイリストをかけっぱなしにしておくと広告視聴していない人対策のようで途中、曲を止めて「続けて視聴しますか?」といった旨のポップアップを出すようになったらしく、どうやら、これの影響っぽい...。
ちなみにブラウザ視聴の場合ならChrome/Chromiumには、これをスキップするような対策アプリがあるようですが、Firefox他もあればいいのに...。
というか、Google傘下のYouTubeでGoogle謹製ブラウザや派生ブラウザにだけYouTube再生中断対策アプリがあるというのもそれはそれで皮肉っぽい気もしますが、そう見せかけておいて実は、他のブラウザとの差別化の一環だったりして。
それはさておき、途中でYouTube楽曲の再生が止まった時、それまでできていたスマートスピーカーから音声操作、もしくは、自作スマートスピーカー用のデスクトップアプリPyQt5/Qt5 Designerの操作パネル(自作)から改めてYouTubeを再生しようとしても再生されない現象に遭遇。
が、操作パネルで指定しているスクリプトをスマートスピーカー用ラズパイにログインして端末から直接実行、しばらく再生させて停止させた後だと音声操作やPyQt5/Qt5 Designerの操作パネルからでもYouTubeを再生できるようになることが判明。
なぜ?
順調だったPCとラズパイのスマートスピーカー機能によるYouTube音楽再生。
突然、ラズパイスマートスピーカーで再生されなくなりました。
ネットにはもちろんつながっていてyoutube-dlは最新、単なるダウンロードさえもされない、単に有効なURLを渡して端末から実行しても瞬間的に終了しているようでプロンプトが即表示される...。
結局、pip3でyoutube-dlをuninstallしてから、installしたら直りました...。
今日からPlayList IDからリスト内の全てのIDを取得できなくなったっぽい、いよいよ詰んだか...と思ったら、スクリプト内で最初に取得していた1つだけプレイリストがなくなってただけで存在するものに替えたらいけました...。
しかも途中、GitHubのCEOが削除された「youtube-dl」のリポジトリ復活に向けて動くなんて見つけちゃったもんだから、そうは言ってもダメになったのかと...。
たぶん、昨日あたりからだと思いますが、プレイリストにおいてURLにこれまで省略可能だったvオプションを付けておかないとlistパラメータだけでは、プレイリストに限らず、ビデオなどもダウンロードできなくなりました。
今のところ、当該プレイリストにさえあれば、vオプションに付与する曲はなんでも良いようです。
従来通り、[Music Premiumが必要]とあるものは、ダウンロードエラーになりますが、リストの場合、そうでないものがあれば、順次、ダウンロードされます。
JPOPに関しては、しばらく、人気の曲トップ100と人気のミュージックビデオトップ100を合わせてシャッフルしており、mplayer/mpvでは、シャッフルとは言え、同じ曲だと連続してかかるのですが、ここ最近、プレイリストが同一かっていうほど被っていたので1つに絞ることに、がっちゃんこした意味はなくなる...、まぁ、人気の曲のミュージックビデオが人気なのは、当然と言えば当然で被るのが普通か...。
PCのDebianにおける自作スマートスピーカー機能では問題ないのに自作ラズパイスマートスピーカーの方でYouTube再生において次のようなエラーが出て再生できない事象に見舞われました。
ちなみにyoutube-dlは、何れもpip/pip3でインストール、アップグレードしており、一連のスクリプト内で常に最新を維持するようにしてあります。
【前フリ】
ネット検索してみると数年前から時々ある事象のようで、たいていは、youtube-dlのバージョンによる可能性に言及しており、中には、それで解決した方もいたようですが、自身の場合、同じバージョンなのにPCとラズパイで再生できるか否か異なることから、バージョンの問題ではなさそう...。
一応、youtube-dlのバージョンを確認してみるとPC/Debianもラズパイ/Raspbianも2021/06/06バージョンっぽい。
youtube-dlのバージョン履歴を確認しても、やはり、2021/06/06。
従前、毎月のように更新されていたようでしたが、半年ほど空いている...、開発者の方に何かあったのかな?それともやめちゃったのかな?
でも、PC/Debianの方では、問題ないしな...。
そこで、まさか...とaptでシステムのアップグレードをしてみると1件の保留を除くと2件しかなかったのですが、2つとも、何やらダウンロードに関係ありそうなlibtorrent-rasterbar10とpython3-libtorrent...。
案の定、このアップグレードで何の問題もなく、youtube-dlなどを使った従来の一連のスクリプトでYouTube音源を再生できるようになりました。
というわけでyoutube-dlのバージョンが最新か否かではなく、システムの関連パッケージと思しきものが最新でないことが原因でしたとさ、めでたし、めでたし...
と思いきや、一度は、再生できたのに、改めてやると再生不能で同じエラーに...しかも、PCの方でも再生できなくなりました...何、いつもながらの、このタイムラグ...。
【解決策】
改めて当初のエラーでネット検索...、cvlcでも同じエラーが出るしな...、そう言えば、6〜7年前の記事youtube-dl failed to extract signatureに唐突に出てきた[yt-dlp]ってなんぞや?と調べてみたら、なんとyt-dlpとは、youtube-dlのパワフルな派生(フォーク)とな!?
が、github見るに新しそうだけど...同名の前身があったのかな!?
その古い記事の情報ではsnapも、え、まさか...とpip/pip3 installしてみると、ある!yt-dlp!
って、このときは、先のgithubのリンク先の存在に気づいておらず、まだyoutube-dlに替わり得るものだとまでは思ってもいない、ネーミングからしてインストールさえすれば、youtube-dlと絡めてうまいことやってくれるものだと思っていましたが、やはり、エラー。
もしかして、URLを渡せば...と思ってyt-dlp https://www.youtube.com/...してみるとエラーもなくダウンロードしてるっぽい...。
ん?これってyoutube-dlの替わりに使うものじゃん!ってことは、mplayerやmpvと組み合わせて...単にyoutube-dlと差し替えれば...、おお!見事に再生されました!
今までありがとう!youtube-dl...、これからよろしくね!yt-dlp...ということで今度こそ、めでたし、めでたし。
と思いつつ、早朝、ふと、youtube-dlのバージョン履歴を再確認してみると、なんと2021/12/17バージョンが出てる...おかえり、youtube-dl!
2021.12.17バージョンにアップグレードしてみたら、youtube-dl経由でもYouTube音源を再生できるようになりました。
今後は、youtube-dlに加え、yt-dlpという選択肢も増え、一層、頼もしくなり、更にめでたし、めでたし。
尚、ブラウザで確認してみると動画によっては、[Music Premiumが必要です]と表示されているものもあり、会員登録してログインしない場合には、プレイリスト内の動画であっても実質視聴可不可がある場合があり、視聴可能数に影響があるので要注意です。
idの取得においても取得できるものとできないものがあるらしく、CLIの場合、何も対策せず、エラーとなると一切、または、その先のリストを取得できない為、エラーや警告を無視するオプション[--ignore-errors]や[--no-warnings]を付けて取得しています。
実際、前述のような会員登録を要する表示がないものを選んだつもりのプレイリスト用IDリスト取得後、十分時間を置いて[wc -l]してみると、やはり、数曲分程度は、ダウンロードできないものもあるようです。
それはさておき、やることは単純なのでスクリプトにはshellを選択、サンプルスクリプトにおける想定プレイリストは、『J-POP Hotlist』。
曲順をシャッフルすべく、shellスクリプト内で予めダウンロード済みのプレイリストを[sort -R(--radom-sort)]でランダムに並べ替えつつ、ループ、URI/URL加工してyoutube-dlに、パイプ経由でmplayerに渡すことに、一巡してしまう場合に備え、これらを無限ループすることにしました。
複数のプレイリストを無限ループ内でそれぞれループで回すか、catで連結したバッファをsort -Rして曲数を嵩増しするのもありですね。
ただ、動画(ファイル)によってデフォルトのボリューム(音量)が異なるようで曲によって稀に極端に音が小さくなったり(微妙に大きくなったりも?)することがあります。
ポイントは、プレイリストそのものではなく、プレイリストに含まれる動画URLを直接指定し、ループで回す点でしょうか。
これは、ブラウザであれば、vパラメータでID(ファイル名)、listパラメータでプレイリスト、(indexパラメータで曲順)指定すると該当する楽曲から再生できるのですが、リファラチェック?によるのか、CLIからだと指定がエラーになり、常に1曲めから再生されてしまうので、これを回避する為です。
尚、少なくとも自身の現行の環境(光ONUから10base/100base-Tのスイッチングハブや無線LANルーター経由)だと有線・無線に関わらず、timeコマンドで計測してみるとプレイリストのダウンロードにとあるリスト55曲で1m33s、100曲で2m30sなど相応の時間がかかり、そのタイムラグは無視できない為、スクリプト内でダウンロードはしていませんが、公式プレイリストの更新もある可能性を考慮するとcronで一定の期間ごとにダウンロードするのが賢明でしょうね。
まだ、cron対応していませんし、したとしても、ダウンロード済みプレイリストとの差異は排除しきれないと思われるため、URLの画像やページが存在するかシェル上で確認を参考にファイル存在チェックにcurlとHTTPリターンコードを使うことにしました。
あ、特に自身の場合、PC版はもちろんのこと、ラズパイスマートスピーカーも常時電源ONではない(使用都度電源を入れている)為、cronよりもスマートスピーカー自動起動設定スクリプト上にバックグランドでダウンロードするよう追記しておけば、使用都度、常に最新のプレイリストに更新できますね。
何れにしてもダウンロード完了前にプレイリストを再生してしまうとプレイリストファイルにアクセスすることになり、ダウンロードが途中でもプロセスが強制終了してしまうようなので、どこかでプレイリストのダウンロード時間を十分に消費というか吸収というか確保する必要がありますが。
スマートスピーカーの辞書や応答スクリプトを編集し、ウェイクワード有効時間内のコールワードは、『JPOP』とか、『邦楽』にしてみました。
この実装に伴い、『音楽消して』や『ラジオ消して』に応答するstop_radio.shに[ps aux | grep youtubejpop.*.sh | awk '{ print "kill -9", $2 }' | sh]と[pkill -f youtube-dl]を追記しました。
([2020/01/09]ここでは、事前にICECASTでmplayerを使っていたため、既にpkill -f mplayerはなされている前提ですが、何らかの事情で加えてmpvも使う場合、pkill -f mpvも要追加)
[pkill -f youtube-dl]だけだと、その時流れている曲は停止するものの、ループ中のスクリプトがプロセスとして存在している為、次の曲が再生されてしまうからです。
というか、せっかく気づいたので、これをスキップ機能として使うべく、Julius辞書と応答スクリプトを編集、プレイリスト再生中にコールワード『スキップ』や『次の曲』で[pkill -f youtube-dl]だけ書いたshellスクリプトを呼ぶことにしました。
([2020/01/09]もし、mplayerではなくmpvを使う場合、プロセスはmpvとなると思われるため、その場合、[pkill -f mpv])
[youtubejpop.*.sh]としたのは、他の選択肢のスクリプト名を[youtubejpophotlist.sh]にしたから、仮に今後増やす場合もこの命名規則?でいこうと考えている為ですが、catで連結するならスクリプト1つでよいので、その場合は、特定のファイル名を指定してもよいですね。
ともかく、これでYouTubeにログインしたり、動画や音源をダウンロードする必要もなく、CLIによるストリーミング配信で、再生都度シャッフルをかけつつ、YouTubeのプレイリストに沿った音楽を聴取、再生時にスキップもできるようになりました。
今もスマートスピーカー機能起動スクリプトにYouTubeのプレイリストダウンロードを含め、以前のダウンロードから1週間以上経過しているか見て行っていますが、そのタイミングで[pip3 install -U youtube-dl]も追加することにしました。
というのも以前から、存在するプレイリストの曲数が0だったり、極端に少なかったりと断続的に起きることがあり、youtube-dlのアップグレードであっさり改善されることも多かったからです。
ありがたいことにyoutube-dlのアップグレードは、頻繁に行われているようですが、それももしかしたら、自身も遭遇しているように(Googleの傘下になってから?)YouTubeの摩訶不思議な仕様変更(≒迷走?≒妨害?)が頻繁にあるからでは、なんて推察してみたり。
コールワードをこんな感じでJuliusの辞書に登録、(Julius 4.4)では、eucjpに変換しておきます。
これらを踏まえ、自作スマートスピーカー用スクリプトvoicerecieve.plに適宜追記。
辞書に影響がある(辞書を編集した)場合は、少なくともJulius 4.4においては、iconvでeucjpに変換が必要です。
構成ファイル変更の反映については、systemd/systemctlならsystemd自動起動設定参照。