Streamlink utils Tool Raspberry Pi

前回作成したyoutube-dl utils Toolのstreamlink版を作成してみました。

Streamlink

インストール

$ pip3 install --upgrade --user streamlink

基本の書式(ダウンロード)

$ streamlink URL best -o 'hogehoge'

$ streamlink –plugins
streamlinkはサイトごとのpluginで実行します。国内(動画)サイトでは abematv, nhkworld, nicoliveなどがありますが当サイトではabematvを利用しています(ほか未確認)

基本のプログラムはyoutube_dl_utils.pyをベースに作成(streamlink_utils.py)しましたが操作性の統一を図るためyoutube_dl_utils.pyにも若干の変更を加えています。

Listbox

listboxの表示は自然な並びにするためsort -V追加

multimedia_list = "ls -FA | sort -V"


URL欄 urlをコピペ
Title欄 タイトル入力
streamlinkではタイトルを取得するオプションが見つからなかったのでタイトルを手作業で入力。空欄の場合は日付+時間を適用。取り敢えずなにか(話数)だけ入れてDL後ファイルマネージャーで変更しても可
Stream Linkボタンで実行開始

Streams各ボタンはStream sizeを変更(デフォルトは任意に変更)
# default stream(480p)
stream = “480p”
640×480 4:3
854×480 16:9

JSON DATA

-j オプションでJSON DATAを取得します。

grep -E(正規表現) 数値(3桁〜4桁)+pの行を検索

# url(stream)
def url_click():
    url = url_entry.get(); url = url.strip()
    t = t_entry.get(); t = t.strip()
    if not url:
        messagebox.showinfo('streamlink', 'No URL !')
        return
    st = ("streamlink '" + url + "' -j | grep -E '[0-9]{3,4}p' | awk '{print($1)}' | cut -c 2-5")
    st = (subprocess.Popen(st, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
    messagebox.showinfo('streamlink', 'Streams         \n\n' + st)


URL欄にurlを入力URLボタンで取得したJSON DATAから指定可能なstream sizeを抜き出します。urlを間違っていたり解釈不可の場合は空になります
abematvではurlが合っている限りこのサイズを表示します。比較的新しいコンテンツは指定可能ですが古い(4:3)形式のものは480pが出力されたりbestではエラーになることもあるようです(480pが無難)
180p worst
1080p best

youtube plugin

streamlinkは一応youtubeもpluginリストにあります。(youtube-dlがあるので使うことは無いのですが)

但しJSON DATAを取得出来ないurlが多い(DL不可)YouTubeの仕様変更に対してstreamlinkの対応が遅れているものと思います。
この例では144p(worst), 240p, 360p(best)が指定(DL)できます。
DLはbestが早いようだ

script file

scriptボタンでYouTube_dl Tool同様スクリプトファイルに書き出します。Title(edit)ボタンで編集

abematvのurlは連番形式とわかりやすくなっています。またタイトルもここで編集可(ファイル名 .streamlink.sh)
Listboxからファイル.streamlink.shを選択してStream Linkボタン(Yes)でDL開始

mediainfo

$ sudo apt install mediainfo


abematvの配信形式はMPEG-TSになっています。(トランスポートストリーミング)
Piでは拡張子が無くてもmpv,vlcからは正常に認識、再生可。拡張子を付けるならtsが適当と思います。

update


streamlinkのupdateはインストール時と同じコマンド
オプションstreamlink –version-checkを実行して同じバージョンならOKボタン


–version 2.3.0のorangepi3で実行確認
新しいバージョンがあればYes/Noボタン

youtube_dl_utils.py


scriptファイルの編集はType(edit)ボタンに変更、URLボタンは2つのウインドウが出るので見やすい方を選択
updateはw3mでサイトを確認するようにしました。

参考
streamlink_utils.py.20210917
youtube_dl_utils.py.20210917

2020年米RIAAからの著作権問題についてはyoutube-dlは白の判定が下りましたが各サイトについてはグレーです。
くれぐれも個人利用、自己責任で!

youtube-dl utils Tool (Audio Only, Script) Raspberry Pi

前回の作成からいろいろ使ってみました。気になるところを修正、追加しています。

video only + audio only

URL欄は以下の形式が利用できます。(YouTube)

https://www.youtube.com/watch?v=xxxxyyyyzzz
https://youtu.be/xxxxyyyyzzz
xxxxyyyyzzz

下記例の(best)は640×360 360pですがvideo only + audio onlyで必要なサイズ品質を指定できます。
135+140  854×480 480p (mp4)
244+251  854×480 480p (webm)

audio only

-f m4a ではmp4コンテナのm4a(mp4a AAC LC)音声のみがダウンロードできます。-f 251 は音声のみのwebm(opus)ですが拡張子は動画と同じwebmとなり区別がつきません。
youtube-dlオプション -x –audio-formatから各形式を指定出来ます。簡単に済ますためType欄の-f に続く形でインサートしています。そのためType欄へは140 or 251を入力後各ボタンのaudio-formatが入力可能になります。
flacはインストールが必要と思います。(# apt install flac)

# audio only
def aac_click():
    global ft; ft = "aac"; insert()
def flac_click():
    global ft; ft = "flac"; insert()
def mp3_click():
    global ft; ft = "mp3"; insert()
def opus_click():
    global ft; ft = "opus"; insert()
def vorbis_click():
    global ft; ft = "vorbis"; insert()
def wav_click():
    global ft; ft = "wav"; insert()

# audio Entory insert
def insert():
    t = t_entry.get()
    if not t:
        messagebox.showinfo('youtube-dl', 'Select a Format Type !')
        return
    # entry insert
    t_entry.insert(END," -x --audio-format " + ft)
    t = t_entry.get()
    proc = messagebox.askyesno('youtube-dl', "-f " + t + "\n\nYes/No ? (no clear) ")
    if proc == False:
        t_entry.delete("0","end")
    return

YouTubeがサポートしている形式m4a(aac),webm(opus)以外は再変換するものと思います。wav,flacについてはその形式で配布(サポート)しているサイトで本来の意味があるものと思われます。(mp4,webmは動画)

但し残念ながら当サイト環境のopus形式のファイルは大半が僅かにクリップ気味となってしまいます。特に音楽ファイルは動画に比べて出力レベルが高めとなっているためI2Sデバイスへの入力オーバーが原因と思われます。

Script file

ダウンロードはURLとTypeを入力してDLボタンで実行するだけですが少し大きめのファイルは数分かかります。纏めて実行できるようスクリプトファイルに書き出して実行します。
デフォルトディレクトリはmultimedia関連のディレクトリとしてListboxは隠しファイル(ピリオド)を表示することにします。(“ls -FA”)

# Listbox 1 (multimedia)
def media_list():
    global multimedia_dir, multimedia_list
    multimedia_list = "ls -FA"
    multimedia_list = (subprocess.Popen(multimedia_list, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')

赤scriptボタン(add)

# script click
def script_click():
    url = url_entry.get(); url = url.strip()
    t = t_entry.get(); t = t.strip()
    if not url:
        messagebox.showinfo('youtube-dl', 'No URL !')
        return
    if not t:
        t = "mp4"
    cmd = ("'" + url + "' -f " + t)
    with open('.youtube_dl_download.sh', 'a') as f:
        f.write("youtube-dl -o " + "'%(title)s.%(ext)s' " + cmd + "\n")
        messagebox.showinfo('youtube-dl', 'Add URL !')
        # reload
        reload_click()
    return

緑scriptボタン(edit)

# script edit
def script_edit():
    y = os.path.isfile('.youtube_dl_download.sh')
    if y == False:
        messagebox.showinfo('youtube-dl', 'No file .youtube_dl_download.sh ! ')
        return
    subprocess.run("xterm -g 130x24 -e vi .youtube_dl_download.sh &", shell=True)
    return

URL Typeを入力、赤scriptボタンクリック(OK)でListBoxの先頭に’.youtube_dl_download.sh’が生えてきます。
緑scriptボタンは更に編集が可能、特殊なオプションが必要な場合は末尾または適当な位置に追記します。

実行はListBoxから選択、YouTube_DLボタンで開始(終了したらスクリプトファイル削除)
YouTubeサイトは5本目位から急にダウンロード速度が低下するようです。(できるだけマメに結果的に早い)

space & bracket (_)

ダウンロードしたファイルは半角(space)があるとListBoxが乱れます。また特殊記号があるとsubprocessはplayerにうまく渡せません。気がついた記号”&()”をアンダースコアに置き換えます。クォーテーションマーク(‘”)はうまく処理出来なかったので必要であれば手作業で修正(ファイルマネージャーやプレーヤーソフトからは問題ないと思います)
(# apt install rename)

# space & bracket (_)
def space_click():
    subprocess.run("find . -name '* *' | rename 's/ /_/g'", shell=True)
    subprocess.run("find . -name '*&*' | rename 's/&/_/g'", shell=True)
    subprocess.run("find . -name '*(*)*' | rename 's/[ ()]/_/g'", shell=True)
    # reload
    reload_click()
    return

youtube-dl

debian系からmpvをインストールすると依存でyoutube-dlもインストールされると思います。パッケージのyoutube-dlはバージョンが古いので最新のyoutube-dlをインストールします。
http://ytdl-org.github.io/youtube-dl/download.html
上記サイトのyoutube-dlは/usr/local/bin/以下にインストールされます。

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

パッケージからインストールしたyoutube-dlがある場合は優先するので削除

$ sudo apt remove youtube-dl

updateボタンクリック 更新があればup-to-dateは最新の日付になります

その他

Homeボタン デフォルトディレクトリに移動
URL欄が空欄の場合は最後に取得したフォーマット情報(/tmp/youtube_F.log)を表示(OS再起動で削除)

# url
def url_click():
    url = url_entry.get()
    url = url.strip()
    if not url:
        ls = os.path.isfile("/tmp/youtube_F.log")
        if ls == True:
            subprocess.run("xterm -g 135x25 -e lv /tmp/youtube_F.log &", shell=True)
        else:
            messagebox.showinfo('youtube-dl', 'No URL !')
        return


基本はこのボタンで間に合うと思います。当サイトはdevilspie2で起動サイズを指定、必要があれば引き伸ばします(好みで)

参考 youtube_dl_utils.py.20210903

youtube-dl utils Tool Raspberry Pi

インターネットで公開している動画の中には公開期限の迫っているものやあとで再度見直してみたいものがあります。youtube-dlは豊富なオプションを備えた強力なダウンロードコマンドラインツールですが慣れないと手軽に使えない場面もあります。

運用方針

youtubeのデフォルトファイル形式はwebmだったりmkvだったりするようです。当サイトではffmpegと親和性が高いと思われるmp4を音声のみの場合はm4aを指定
テレビのない当サイトはPCモニタで閲覧できる必要十分なフォーマットタイプを指定することでファイルサイズを削減

ディレクトリボタンでfiledialog(askdirectory)が開きます。ディレクトリを選択、pythonからchdirして作業ディレクトリになります。
URL欄にブラウザからurlをコピーして貼り付け。URLボタンでタイトルと利用可能なフォーマットタイプを取得

subprocess.run("youtube-dl -e " + "'" + url + "'" + " > /tmp/youtube_F.log", shell=True)
subprocess.run("youtube-dl -F " + "'" + url + "'" + " >> /tmp/youtube_F.log", shell=True)
time.sleep(1)
subprocess.run("xterm -g 135x25 -e less /tmp/youtube_F.log &", shell=True)

上記のurlをターミナルから直接実行、最終的なデフォルトの保存形式はまた別の設定ファイルがあるようです。
$ youtube-dl url     拡張子mkv
$ youtube-dl -f mp4 url  拡張子mp4(best)
Type欄が空白の場合は-f mp4を割り当てています。Type欄に空白または18を入力することで最終行の(best)が適用
保存形式はタイトル+拡張子として作業ディレクトリに保存、タイトルは半角(space)が含まれていることがあるのでアンダースコア(_)に変換(パッケージrenameをインストール)
早い話がURL欄にurlを入力、DLボタン実行することでmp4形式の(best)をダウンロード保存します。

# youtube-dl
def dl_click():
    url = url_entry.get()
    url = url.strip()
    t = t_entry.get()
    t = t.strip()
    if not url:
        messagebox.showinfo('youtube-dl', 'No URL !')
        return
    if not t:
        t = "mp4"
    subprocess.run("xterm -g 100x24 -e youtube-dl -o '%(title)s.%(ext)s' " + "'" + url + "' -f " + t, shell=True)
    # space(_)
    subprocess.run("find -name '* *' | rename 's/ /_/g'", shell=True)
    # reload
    reloadclick()
    return

GYAO

動画によっては高画質で配信されているものがあります。

当サイトの目的はファイルサイズの小さい(少々低画質)ものを揃えることにあります。Typeボタンをクリックすると取得したフォーマットタイプ情報を元にvideo only,audio onlyなどを除いたリストを表示


hls-1785-3 を選択 mp4 854×480
hls-1785-3の値は各話で同じになるとは限りません
1920×1080 約930M
854×480 約300M
同じサイズで再エンコードすることにより更にファイルサイズを1/3程度まで小さくすることも出来ます(時間とマシンパワーが必要)
Type欄への入れ方によって組み合わせはいろいろ可能と思います(試していません)

urlは各話ごととplay list形式のurlがあります。play list形式のurlは(best)でよければ余計なオプションを指定せずターミナルから直接実行することで記載されたファイルを連続してダウンロードが可能になります。

参考 youtube_dl_utils.py

シンプルなアプリケーションランチャー by directory

前回作成したアプリケーションランチャーは登録形のランチャーですが特定のディレクトリを対象とするランチャーを作成してみました。

ディレクトリを対象

chdirに対象のディレクトリを指定 os.chdir(chdir)

import os
# --- default ---
sub_file = "sub_master.py"
chdir = "/home/hoge/bin/app_menu/" # full path

左は自己登録形、右はディレクトリ指定、ファイルをコピーするとリストに反映されます。
リストはlsコマンドを実行、ファイル名で並ぶので多少増えても選択しやすい
サブメニューを呼び出すサブマスターはディレクトリ指定が使いやすい
対象ファイル subファイルを対象

menu = ("ls sub* | grep -v sub*_")

 
前回のcertbot certificates

プログラム中はコピーしながらターミナルから実行します。rangerではyy(ヤンク)pp(ペースト)
メニューから実行確認、またひとつ前のプログラム確認

# Listbox (menu)
os.chdir(chdir)
#menu = ("ls ")
menu = ("ls | grep -v *py_ | grep -v *sh_")  # edit
menu = (subprocess.Popen(menu, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')


実行するファイルがひとつのディレクトリにまとまっていればいろいろ便利に使えると思います。

参考
sub_default_dir.py
sub_master_dir.py

 
 

Raspberry Pi 2 web server 更新(certbot renew)

Let’s EncryptのSSL証明書更新がエラーを吐いて更新できなくなってしまいました。debian 11 bullseyeのリリースも間もなくとあって安定版のRasPiOS(May 7th 2021)で再構築してみました。

Timeout during connect

これまではgitのcertbotスクリプトで更新していたのですがなにか仕様変更があるとやはりエラーを吐いて更新に失敗します。それでも修正をしながらなんとか更新できていたのですが今回はどうもうまくいきません。

Timeout during connect (likely firewall problem)

検索するとよくあるようですがパスもfirewallも特に問題ない。

Raspberry Pi2 web server nginx

Raspberry Pi OS Lite May 7th 2021
nginx   1.21.1-1~buster(コンパイル)
php7.3   7.3.29-1~deb10u1
mariadb  1:10.3.29-0+deb10u1
各設定ファイルはそのまま移行

certbot

現在のRasPiOSではパッケージとしてcertbotがあります。python3-certbot-nginxをインストールすることでwebrootで実行可

# apt install certbot python3-certbot-nginx

基本の設定が出来たところで–dry-run 実行。ssh clientはpi zero 母艦のPi4とはvnc接続

# certbot renew –dry-run

特に問題ないようです。続いて本番

# certbot renew

無事更新できました。gitのcertbotスクリプトに比べて断然早い、またLet’s Encryptの仕様変更に対してもcertbotのupgradeで対応することが期待できます。

python3-certbot-nginx

python3-certbot-nginxを導入することでcertbot.timer(自動更新)がデーモンとして起動します。

$ systemctl status certbot.timer


/etc/cron.d/certbotには以下の記載があります。毎日0時と12時にcertbot -q renewを実行しています
/var/log/syslogではcronの実行を確認できますがletsencrypt.logには記載されないようです。

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew

certbot certificates

今までは週に1回cronを回してrenewを実行、結果をメールで確認していたのですがcertbot.timerによる自動更新が正常かどうか注意して見ようと思います。
もし更新エラーがあれば早めに把握していれば対策も立てやすいと思います。
有効期限の確認方法はいろいろありますがcertbot certificatesコマンドがシンプル

xterm + ssh

サーバー側で実行するためssh公開鍵認証(空パスワード)を設定、毎回コマンドを打つのも面倒なのでxdotoolに代打ちをお願いします
メニューに登録実行
~bin/app_menu/letsencrypt/certificates.sh

#!/bin/sh
xterm -g 80x25+1124+25 -e ssh xyz81 &
sleep 1
xdotool mousemove 1500 100
xdotool type --delay 70 'sudo certbot certificates'
xdotool key Return

python3(tkinter)
上記で実行した結果を母艦のPi4に取り込めればもっと見やすく加工できます。
サーバー側でスクリプトを1日1回適当な時間に実行(cronを回す)

~/bin/certbot_certificates.sh (chmod 755)
#!/bin/sh
rm ~/*certbot
sudo certbot certificates > $(date +%Y%m%d_%H%M%S).certbot
$ crontab -e
35 06 * * * ~/bin/certbot_certificates.sh

user hogeのホームディレクトリに日付時間.certbotを作成
20210719_063001.certbot
母艦のPi4はこのファイルをプログラム起動時にscpして表示(起動は5秒位かかる)

ラベル欄に読み込んだファイル名表示 daysボタンで終了
通常は1日1回確認でOKですが敢えて最新の情報が必要な時はRETRYボタンを実行
xtermが起動してスクリプトを実行、サーバーのcertbot_certificates.shを実行 pythonプログラムを再起動


プログラムのボタン欄で赤ボタンにするdaysを変更(当サイトは31に設定)30日を切って更新エラーがあると緊迫感がより一層高まるものです。

参考 certificates.py

xdotool実行中はxtermからフォーカスが外れると打ち込みに失敗するのでそっと待ちます(起動まで約10秒)
sleepは環境によって調整

~/bin/app_menu/letsencrypt/certificates_save.sh
#!/bin/sh
xterm -g 80x12+1124+205 &
xdotool key Return
sleep 0.4
xdotool mousemove 1300 300
xdotool type --delay 70 'ssh xyz81'
xdotool key Return
sleep 1
xdotool type --delay 70 '~/bin/certbot_certificates.sh'
xdotool key Return
sleep 5
xdotool type --delay 70 'exit'
xdotool key Return
sleep 0.4
xdotool type --delay 70 '~/bin/app_menu/letsencrypt/certificates.py &'
xdotool key Return
sleep 5
xdotool mousemove 1300 300
xdotool click 1
xdotool key Return
xdotool type --delay 70 'exit'
xdotool key Return

次回の更新は9月14日 6:28(JST)以降からrenew実行可、certbot.timer12時に自動実行される予定です。気を付けて置きたいと思います。

追記 7月23日
更新開始(renew)の期日が気になっていたのでdateコマンドで確認してみました。

$ date -d '2021-10-12 21:28:23 UTC 30 day ago'
2021年  9月 13日 月曜日 06:28:23 JST


多分9月 13日が正解と思います。
終了時messageboxに表示するようにしました。

# quit
def quit_click():
    # renew days
    with open(save_dir+r_file, 'r') as f:
        certificates = f.read()
        d = certificates.find('Date')
        d = (certificates[d+6:d+25])
        cert_renew = ("date -d '" + d + " UTC 30 days ago'")
        cert_renew = (subprocess.Popen(cert_renew, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
        cert_renew = cert_renew.strip()
    # renew days
    if days_renew >= str(30):
        root.option_add('*Dialog.msg.font', 'Helvetica 11')
        messagebox.showinfo('certbot certificates', 'certbot renew \n\n' + cert_renew)
    root.quit()

Top