「YouTube (Music)のプレイリストのギャップレス再生」の版間の差分

Notion-MW
Notion-MW
 
(同じ利用者による、間の1版が非表示)
11行目: 11行目:
インストールは実行ファイル単体でダウンロードしてもいいし、pipのパッケージとして入れてもよい。
インストールは実行ファイル単体でダウンロードしてもいいし、pipのパッケージとして入れてもよい。


例えば、<code>yt&#45;dlp &#45;F 動画URL</code>とすると、ダウンロード可能なフォーマット(画質・音質に差がある)が一覧表示される。なおURLに&amp;が含まれる場合は””で囲うこと。これを見るとわかるが、YouTubeの動画は内部では動画と音声に分けて管理されており、再生時にブラウザで両者を合成している。最も高品質な音声データは”251”というフォーマット番号のもので、Opus形式で圧縮されたWebMオーディオとなっている。これをギャップレス再生することができれば目的は達成できそうである。
例えば、<code>yt&#45;dlp &#45;F 動画URL</code>とすると、ダウンロード可能なフォーマット(画質・音質に差がある)が一覧表示される。なおURLに&amp;が含まれる場合は””で囲うこと。これを見るとわかるが、YouTubeの動画は内部では動画と音声に分けて管理されており、再生時にブラウザで両者を合成している。最も高品質な音声データは”251”というフォーマット番号のもので、Opus形式で圧縮されたWebMオーディオとなっている。これをギャップレス再生することができれば目的は達成できそうである。なお、動画によっては(アップロード日が古いもの?)”251”がないものもある。


WebMオーディオのギャップレス再生に対応したソフトは少なく、筆者が知っているものは[https://mpv.io/ mpv]のみである。mpvの使い方やオプションについては[[MPVとギャップレス再生|MPVとギャップレス再生]]も参照。mpv以外だとWindows Media PlayerやFoobar2000などはwavやflacのギャップレス再生には対応しているが、webaの再生においてはわずかに隙間が聴こえる。従ってこの記事ではmpvを使用する。
WebMオーディオのギャップレス再生に対応したソフトは少なく、筆者が知っているものは[https://mpv.io/ mpv]のみである。mpvの使い方やオプションについては[[MPVとギャップレス再生|MPVとギャップレス再生]]も参照。mpv以外だとWindows Media PlayerやFoobar2000などはwavやflacのギャップレス再生には対応しているが、webaの再生においてはわずかに隙間が聴こえる。従ってこの記事ではmpvを使用する。
28行目: 28行目:
では再生用のコマンドの設計を定める。現実にはプレイリストを丸ごと聴くとは限らないから、開始曲と終了曲を指定できるようにしたい。そこで今回は、
では再生用のコマンドの設計を定める。現実にはプレイリストを丸ごと聴くとは限らないから、開始曲と終了曲を指定できるようにしたい。そこで今回は、


<syntaxhighlight lang="python">
<syntaxhighlight lang="c">ytp "[開始曲のプレイリストID付きURL]" [再生曲数(指定なしあるいは0なら最後まで再生)]</syntaxhighlight>
 
c
ytp "[開始曲のプレイリストID付きURL]" [再生曲数(指定なしあるいは0なら最後まで再生)]</syntaxhighlight>
という構文で動作するytpというプログラムを作成する。丸ごと聴きたければ最初の曲のリンクを渡せばよい。Windowsにおいてはスタートボタンを押して「検索」欄に入力すれば任意のコマンドを実行できるので(※Windows 11のバージョン22H2ではバグで引数が読まれないので代わりにWin+Rを使うとよい)、YouTube Musicのプレイリスト画面から始めてかなり少ないステップで音楽を聴くことができるようになる。ここで「プレイリストID付きURL」と言っているのは、<code>https&#58;//&#91;wwwまたはmusic&#93;.youtube.com/watch?v&#61;動画のID&amp;list&#61;プレイリストのID&amp;index&#61;&#91;数&#93;</code>という形式のもので、このindexの部分から開始曲を取得する。<code>www.youtube.com</code>のほうではプレイリスト内の動画を右クリックして表示されるメニューからこの形式のURLをコピーできる。一方でYouTube Musicでは、アルバム画面で曲目を<u><strong>Shift+</strong></u>右クリックすれば同様にURLを得られるが、indexの部分が含まれていない。そこで今回は、[https://requestly.io/ <strong>Requestly</strong>]というブラウザ拡張機能(Chrome、Edge、Safari、FireFox等で使える)を使用し、YouTube MusicのWebページを書き換えてURLに<code>&amp;index&#61;&#91;数&#93;</code>を付加する。
という構文で動作するytpというプログラムを作成する。丸ごと聴きたければ最初の曲のリンクを渡せばよい。Windowsにおいてはスタートボタンを押して「検索」欄に入力すれば任意のコマンドを実行できるので(※Windows 11のバージョン22H2ではバグで引数が読まれないので代わりにWin+Rを使うとよい)、YouTube Musicのプレイリスト画面から始めてかなり少ないステップで音楽を聴くことができるようになる。ここで「プレイリストID付きURL」と言っているのは、<code>https&#58;//&#91;wwwまたはmusic&#93;.youtube.com/watch?v&#61;動画のID&amp;list&#61;プレイリストのID&amp;index&#61;&#91;数&#93;</code>という形式のもので、このindexの部分から開始曲を取得する。<code>www.youtube.com</code>のほうではプレイリスト内の動画を右クリックして表示されるメニューからこの形式のURLをコピーできる。一方でYouTube Musicでは、アルバム画面で曲目を<u><strong>Shift+</strong></u>右クリックすれば同様にURLを得られるが、indexの部分が含まれていない。そこで今回は、[https://requestly.io/ <strong>Requestly</strong>]というブラウザ拡張機能(Chrome、Edge、Safari、FireFox等で使える)を使用し、YouTube MusicのWebページを書き換えてURLに<code>&amp;index&#61;&#91;数&#93;</code>を付加する。


45行目: 42行目:
ちなみに、<code>www.youtube.com</code>のほうに強制的に遷移させる(履歴ごと上書きするために<code>location.replace</code>を使うのがよい)という方法もある。
ちなみに、<code>www.youtube.com</code>のほうに強制的に遷移させる(履歴ごと上書きするために<code>location.replace</code>を使うのがよい)という方法もある。


<syntaxhighlight lang="python">
<syntaxhighlight lang="javascript">new MutationObserver(() => {
 
javascript
new MutationObserver(() => {
     if (location.href.indexOf("youtube.com/playlist") >= 0) {
     if (location.href.indexOf("youtube.com/playlist") >= 0) {
         urlAddIndex();
         urlAddIndex();
102行目: 96行目:
<ul>
<ul>
<li><p>ytp.bat(最初に呼ばれるランチャー)</p>
<li><p>ytp.bat(最初に呼ばれるランチャー)</p>
<syntaxhighlight lang="python">
<syntaxhighlight lang="c">cd %~dp0
c
cd %~dp0
set "snd=%2"
set "snd=%2"
if "%2"=="" set "snd=0"
if "%2"=="" set "snd=0"
110行目: 102行目:
<p>再生曲数が指定されていない場合は0を補う。<code>&#45;&#45;af</code>オプションに関してはバックスラッシュとシングルクォートでエスケープしている(試行錯誤のすえ、とりあえずこれで問題なく動いている)。</p></li>
<p>再生曲数が指定されていない場合は0を補う。<code>&#45;&#45;af</code>オプションに関してはバックスラッシュとシングルクォートでエスケープしている(試行錯誤のすえ、とりあえずこれで問題なく動いている)。</p></li>
<li><p>ytp&#45;invisible.vbs(bashを非表示で起動するためのvbs)</p>
<li><p>ytp&#45;invisible.vbs(bashを非表示で起動するためのvbs)</p>
<syntaxhighlight lang="python">
<syntaxhighlight lang="vb.net">Dim oWshShell
vb.net
Dim oWshShell
Set oWshShell = CreateObject("WScript.Shell")
Set oWshShell = CreateObject("WScript.Shell")
Dim mpv_args
Dim mpv_args
121行目: 111行目:
<p>2つ目以降の引数をつなげて渡している。Runのオプションで0(非表示)、False(終了を待たない)を指定している。デバッグ時は0を1に変えておくとウィンドウが表示される。</p></li>
<p>2つ目以降の引数をつなげて渡している。Runのオプションで0(非表示)、False(終了を待たない)を指定している。デバッグ時は0を1に変えておくとウィンドウが表示される。</p></li>
<li><p>ytpx.sh(処理を行う本体)</p>
<li><p>ytpx.sh(処理を行う本体)</p>
<syntaxhighlight lang="python">
<syntaxhighlight lang="shell">#!/bin/sh
shell
#!/bin/sh
cd /path/to/mpv_dir
cd /path/to/mpv_dir
ARR=(`echo $1 | sed -r "s/^.*(www|music)\.youtube\.com\/watch\?v=[^&]+&list=([^&]+)&index=([^&]+)$/\1 \2 \3/"`)
ARR=(`echo $1 | sed -r "s/^.*(www|music)\.youtube\.com\/watch\?v=[^&]+&list=([^&]+)&index=([^&]+)$/\1 \2 \3/"`)
134行目: 122行目:
fi
fi
shift 2
shift 2
yt-dlp $NA_OPTION -f 251 --extractor-args "youtube:lang=ja" -O title -O url -I $INDEX:$END_INDEX ${ARR[1]} | sed '1~2 s/^/#EXTINF:-1,/' | sed '1i#EXTM3U' | ./mpv.exe --player-operation-mode=pseudo-gui --prefetch-playlist=yes --playlist=- $@</syntaxhighlight>
yt-dlp $NA_OPTION -f bestaudio --extractor-args "youtube:lang=ja" -O title -O url -I $INDEX:$END_INDEX ${ARR[1]} | sed '1~2 s/^/#EXTINF:-1,/' | sed '1i#EXTM3U' | ./mpv.exe --player-operation-mode=pseudo-gui --prefetch-playlist=yes --playlist=- $@</syntaxhighlight>
<p>まず3行目で、長さ3の配列ARRに①”www”または”music”②プレイリストID③index、をそれぞれ入れる(動画IDは捨てる)。4~6行目で<code>&#45;&#45;compat&#45;options no&#45;youtube&#45;unavailable&#45;videos</code>の有無を設定する。</p>
<p>まず3行目で、長さ3の配列ARRに①”www”または”music”②プレイリストID③index、をそれぞれ入れる(動画IDは捨てる)。4~6行目で<code>&#45;&#45;compat&#45;options no&#45;youtube&#45;unavailable&#45;videos</code>の有無を設定する。</p>
<p>7~10行目では開始indexと再生曲数を用いて植木算をして終了曲のindexを計算している。$2が0なら$END_INDEXは未設定のため事実上は空文字列(終了曲の指定なし)となる。</p>
<p>7~10行目では開始indexと再生曲数を用いて植木算をして終了曲のindexを計算している。$2が0なら$END_INDEXは未設定のため事実上は空文字列(終了曲の指定なし)となる。</p>
<p>最後がメインのコマンド実行である。yt&#45;dlpを用いてタイトルと内部URLの一覧を取得する(なお<code>&#45;&#45;extractor&#45;args &quot;youtube&#58;lang&#61;ja&quot;</code>は日本語タイトルを取得しようとして入れてあるが、現状では(おそらくyt&#45;dlpがwww.のほうしか見ないため)効果なし)。フォーマットは最高音質の251を指定する。さらに、ここまでに計算した開始・終了インデックスを<code>&#45;I</code>オプションで渡す。出力形式としてはタイトルと内部URLが交互に書かれた複数行テキストが返ってくる。</p>
<p>最後がメインのコマンド実行である。yt&#45;dlpを用いてタイトルと内部URLの一覧を取得する(なお<code>&#45;&#45;extractor&#45;args &quot;youtube&#58;lang&#61;ja&quot;</code>は日本語タイトルを取得しようとして入れてあるが、現状では(おそらくyt&#45;dlpがwww.のほうしか見ないため)効果なし)。フォーマットは最高音質を取得する<code>bestaudio</code>を指定する。さらに、ここまでに計算した開始・終了インデックスを<code>&#45;I</code>オプションで渡す。出力形式としてはタイトルと内部URLが交互に書かれた複数行テキストが返ってくる。</p>
<p>次に、mpvにm3u形式のプレイリスト(単にurlやファイル名を列挙する書式と違って、再生時のタイトルを指定できる)として渡すため、タイトルがある行(奇数行)の先頭に&#35;EXTINF&#58;&#45;1,を付加し、さらに全体の先頭行に&#35;EXTM3Uを付ける。そして最後にmpvの&#45;&#45;playlistに対して標準出力(ハイフンで表される)を渡すことで、めでたくタイトル付きで音声をギャップレス再生できる。動画データを渡していないので画面は真っ黒である。</p>
<p>次に、mpvにm3u形式のプレイリスト(単にurlやファイル名を列挙する書式と違って、再生時のタイトルを指定できる)として渡すため、タイトルがある行(奇数行)の先頭に&#35;EXTINF&#58;&#45;1,を付加し、さらに全体の先頭行に&#35;EXTM3Uを付ける。そして最後にmpvの&#45;&#45;playlistに対して標準出力(ハイフンで表される)を渡すことで、めでたくタイトル付きで音声をギャップレス再生できる。動画データを渡していないので画面は真っ黒である。</p>
<p>追加のmpvのオプションとしては、バッチファイルから渡されてきたものに加えて、CUIからの実行でもGUIを強制する<code>&#45;&#45;player&#45;operation&#45;mode&#61;pseudo&#45;gui</code>とWeb上リソースのギャップレス再生に有効な<code>&#45;&#45;prefetch&#45;playlist&#61;yes</code>を指定しているが、古いバージョンではさらにオプションが必要かもしれない([[MPVとギャップレス再生|MPVとギャップレス再生]] も参照)。もちろん、スクリプト内ではなくmpv.confで指定してもよい。</p>
<p>追加のmpvのオプションとしては、バッチファイルから渡されてきたものに加えて、CUIからの実行でもGUIを強制する<code>&#45;&#45;player&#45;operation&#45;mode&#61;pseudo&#45;gui</code>とWeb上リソースのギャップレス再生に有効な<code>&#45;&#45;prefetch&#45;playlist&#61;yes</code>を指定しているが、古いバージョンではさらにオプションが必要かもしれない([[MPVとギャップレス再生|MPVとギャップレス再生]] も参照)。もちろん、スクリプト内ではなくmpv.confで指定してもよい。</p>
146行目: 134行目:
上記の実装では引用符の入力など多少の回りくどいキーボード操作が必要である。URLはクリップボードに入っているので、ショートカットキーから起動することももちろん可能である。ただし再生曲数を入力するためのダイアログは必要である。以下のAutoHotkeyのスクリプトの例では、Ctrl+Alt+Shift+Lを押すと入力ダイアログを表示して再生曲数を取得し、ytp.batを起動する。
上記の実装では引用符の入力など多少の回りくどいキーボード操作が必要である。URLはクリップボードに入っているので、ショートカットキーから起動することももちろん可能である。ただし再生曲数を入力するためのダイアログは必要である。以下のAutoHotkeyのスクリプトの例では、Ctrl+Alt+Shift+Lを押すと入力ダイアログを表示して再生曲数を取得し、ytp.batを起動する。


<syntaxhighlight lang="python">
<syntaxhighlight lang="vb.net">^!+l::
 
vb.net
^!+l::
InputBox, play_numbers, Gapless Play YouTube, Enter the number of tracks to play ("" or "0" will play to the end)
InputBox, play_numbers, Gapless Play YouTube, Enter the number of tracks to play ("" or "0" will play to the end)
Run ytp.bat "%clipboard%" %play_numbers%</syntaxhighlight>
Run ytp.bat "%clipboard%" %play_numbers%</syntaxhighlight>