Vue.jsと云うjavascriptのフレームワークの存在を知り、どんなものかとお試しで音楽プレーヤーを作ってみた。どうにかイメージ通りに作成出来たが、もう少し勉強が必要かな。
また、作成中に音楽再生プログラムmpvをリモート制御する方法を見つけたので導入してみた(参考サイトの"webui.lua"を利用する)。
更に、フランスのネットラジオ局FIPで放送中の曲のジャケット情報を入手する方法が分かったので取り入れてみた。
●MPVプレーヤーの再生中曲情報を得る
参考サイトから入手したスクリプト"webui.lua"を利用してMPVプレーヤーが再生している曲情報を得る。(音楽ファイルとFIP以外のネットラジオ)
"webui.lua"を使用するにあたり、raspiで実行するには下記インストールが必要だった
lua-basexx-0.3-2 baseXX encoding/decoding library for Lua
lua-socket-3.0~rc1+git+ac3201d-4 TCP/UDP socket library for the Lua language
" ~/.config/mpv/scripts"フォルダに"webui.lua"を入れるとmpv実行時に自動でscriptが起動する
* MPVから再生中の曲情報を得る
handleStatusResponse: function(self, json) {
self.position = this.format_time(json['position']);
self.remaintime = this.format_time(json['remaining']);
let metas = [];
let metadata = json['metadata'];
let tracklist = json['track-list'];
let playlist = json['playlist'];
if(metadata['track']) metas.push('Track -------- ' + metadata['track']);
if(metadata['title']) metas.push('Title -------- ' + metadata['title']);
else if(metadata['TITLE']) metas.push('Title -------- ' + metadata['TITLE']);
else if(metadata['icy-title']) metas.push('Title -------- ' + metadata['icy-title']); // radio
else metas.push('Title -------- ' + self.plist[0].item);
metas.push('Duration ----- ' + this.format_time(json['duration']));
if(metadata['album']) metas.push('Album -------- ' + metadata['album']);
else if(metadata['ALBUM']) metas.push('Album -------- ' + metadata['ALBUM']);
else if(metadata['icy-name']) metas.push('Radio -------- ' + metadata['icy-name']); // radio
if(metadata['artist']) metas.push('Artist ------- ' + metadata['artist']);
else if(metadata['ARTIST']) metas.push('Artist ------- ' + metadata['ARTIST']);
else if(metadata['icy-br']) metas.push('BitRate ------ ' + metadata['icy-br']); // radio
if(metadata['genre']) metas.push('Genre -------- ' + metadata['genre']);
else if(metadata['GENRE']) metas.push('Genre -------- ' + metadata['GENRE']);
else if(metadata['icy-genre']) metas.push('Genre -------- ' + metadata['icy-genre']); // radio
metas.push('Codec -------- ' + tracklist[0]['codec']);
metas.push('SampleRate --- ' + Math.round(tracklist[0]['demux-samplerate']*100/1000)/100 + 'kHz');
self.tags = metas
for (let i = 0; i < self.plist.length; i++){ // リスト内再生中の曲をセレクトにする
self.plist[i].sel = playlist[i].hasOwnProperty('playing') ? true : false
}
},
getStatus: function(self){
var http = new XMLHttpRequest()
if(self.radioFip) http.open('get', self.fipUrl + '?fip='+self.plist[0].item)
else http.open('get', self.mpvUrl + 'status')
http.onreadystatechange = function() {
if (http.readyState === 4 && http.status === 200) {
var json = JSON.parse(http.responseText);
if ( self.radioFip ) self.handleStatusFip(self, json);
else self.handleStatusResponse(self, json);
}else if (http.status === 0) {
// clear play related flags
if (self.remaintime == "00:00:01"){
self.remaintime = "00:00:00"
};
};
http.onerror = function() {
console.log('onerror' + http.status + ' -- ' + http.statusText)
};
http.send(null);
},
●音楽ファイルからアルバム画像を得る
pythonのモジュール"mutagen"と"PIL"をインストールして作成。
音楽ファイルに画像データが含まれていない場合は、フォルダ内に有る画像ファイル(jpg/png)を使う。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import sys
import mutagen
import glob
import re
from PIL import Image
def getAlbumArt(song, imgfile):
tags = mutagen.File(song)
if 'APIC:' in tags: # MP3
artwork = tags.get("APIC:").data
elif 'covr' in tags: # MP4
artwork = tags.get("covr")[0]
elif tags.pictures: # FLAC
print(tags.pictures[0].type)
artwork = tags.pictures[0].data
else:
pathname = os.path.dirname(song)
coverlist = [p for p in glob.glob(pathname+"/*") if re.search('/*\.(jpg|png)', str(p))] # 画像ファイル抽出
jpglist = [jpg for jpg in coverlist if '.jpg' in jpg]
pnglist = [png for png in coverlist if '.png' in png]
if len(jpglist) > 1:
img = Image.open(jpglist[0])
else:
img = Image.open(pnglist[0])
img = img.convert('RGB') # png → jpg変換
if img.size[0] > 300 or img.size[1] > 300:
img = img.resize((300, int(300*img.size[1]/img.size[0])))
img.save(imgfile, quality=30)
return 0
with open(imgfile,"wb") as img:
img.write(artwork)
return 0
if __name__ == '__main__':
req = "all" # request function all:tags&image(default), tags:tags, img:image
imgfile = "./image.jpg" # default image store file path
song = "" # song file path
for parm in sys.argv[1:]:
if re.search('/*\.(jpg|png)', parm): imgfile = parm
elif re.search('/*\.(mp3|m4a|flac|wav)', parm): song = parm
if re.search('(all|tags|img)', parm): req = parm
st = 0
if re.search('(all|img)', req): st = getAlbumArt(song, imgfile)
sys.exit(st)
●YouTubeの再生情報を得る
YouTubeから再生情報を得るには"youtube-dl"を使用
youtube-dl --ignore-config --get-title --get-duration --get-description --get-thumbnail '.$code.' 2>/dev/null
--get-duration : 再生時間
--get-description : ソース情報(登録者により内容はバラバラ)
--get-thumbnail : 静止画像ファイルのアドレス
●radio FIPの再生情報
フランスのネットラジオ局 FIP では、その他のラジオ局の様にMPVで再生中曲情報を得られない。
ググっていたら特定のアドレスから情報が得られることが分かり利用した。しかし、再生音楽と得られる情報にタイムラグが有り、ディレイを置いて調整した。
また、当初、情報を得るために"file_get_contents()"を使用していたが、chromeブラウザではエラーになり(firefoxはOK)取得出来なかったので、サイト情報により"cURL"に変更したらエラーにならず取得出来た。
下記をPHPで作成
$fips = array(
array('name'=>"FIP", 'url'=>"https://www.fip.fr/latest/api/graphql?operationName=Now&variables=%7B%22bannerPreset%22%3A%22600x600-noTransform%22%2C%22stationId%22%3A7%2C%22previousTrackLimit%22%3A3%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%228a931c7d177ff69709a79f4c213bd2403f0c11836c560bc22da55628d8100df8%22%7D%7D", 'delay' => 12),
:
中略
:
);
$req = str_replace('radio ','',$_GET['fip']);
$matchFip = array_search($req, array_column($fips, 'name'));
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_URL, $fips[$matchFip]['url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$json = curl_exec($ch);
curl_close($ch);
$json = (array)json_decode($json, true);
$json[] = ['delay' => $fips[$matchFip]['delay']];