英文原文:
http://www.linux.com/article.pl?sid=07/03/28/154246我最近写了一个简单的脚本,用来把一个歌词数据库融合到我的一些音乐处理脚本中.我充分利用了开源软件的一大好处,那就是先找了一个实现该功能的程序,然后看看它源的码,来学习别人是怎么做的.
我是从学习Rhythmbox(一个音乐管理程序)的代码开始的.我发现(这个程序的)作者向一个基于Web的叫做Leo的歌词数据库发了许多简单的URL请求.请求的地址是:
http://api.leoslyrics.com/api_search.php?auth=duane&artist=cake&songtitle=comfort eagle
http://api.leoslyrics.com/api_lyrics.php?auth=duane&hid=VxwOBYpM3iY=
第一个请求返回了一个XML文件,这个文件里包含了搜索的结果,示例如下.(服务器似乎忽略了授权信息[我用的是"duane"]. 我也没有找到关于这个网站的基于Web的 API文档.我试着以能提交歌词的账号登录该网站,然后向该网站支持的地址发送电子邮件,但仍然没有响应.)
<?xml version="1.0" encoding="UTF-8"?>
<leoslyrics>
<response code="0">SUCCESS</response>
<searchResults>
<result id="120741" hid="VxwOBYpM3iY=" exactMatch="true">
<title>Comfort Eagle</title>
<feat/>
<artist>
<name>Cake</name>
</artist>
</result>
</searchResults>
</leoslyrics>
从这个response元素(<response code="0">SUCCESS</response>)来看,这次请求成功了.接下来我比较感兴起的是这个result元素(<result id="120741" hid="VxwOBYpM3iY=" exactMatch="true">),特别是这个hid属性,它是这条歌词的id. 我把这个hid传到第二个URL中,然后得到下面这个结果:
<?xml version="1.0" encoding="UTF-8"?>
<leoslyrics>
<response code="0">SUCCESS</response>
<lyric hid="VxwOBYpM3iY=" id="120741">
<title>Comfort Eagle</title>
<feat/>
<artist>
<name>Cake</name>
</artist>
<albums>
<album>
<name>Comfort Eagle</name>
<imageUrl>http://images.amazon.com/images/P/B00005MCW5.01.MZZZZZZZ.jpg</imageUrl>
</album>
</albums>
<writer/>
<text>We are building a religion
We are building it bigger
.................
Pendant keychains</text>
</lyric>
</leoslyrics>
从这结果,我知道我可以提取出text元素 (<text>.../<text>)来得到我的歌词
我在bash脚本里用wget和xmlstarlet来自动完成这个过程.wget是一个从Internet上以非交互的方式下载文件的小工具.我就是用wget来请求(上面的)具有正确参数的URL来捕捉的这些XML结果的.Xmlstarlet是一组用来查询和处理XML文档的命令行工具.我用xmlstarlet来从URL请求的结果中提取相关信息.
为了使这个脚本实用,我给这个脚本提供了一个MP3文件的路径,然后让它从这个文件的ID3标签中提取演唱者和歌名信息,用这些信息再来下载歌词.我用了id3tool,这是一个可以查看和编辑MP3文件的ID3标签的命令行工具.
在脚本的一开始运行完id3tool之后,我用sed来从id3tool的输出中提取演唱者信息,并把它存到一个叫ARTIST的shell变量中.我用类似的方法提取歌名信息.
ARTIST=`id3tool "$1" | sed -ne "s/.*Artist:(.*)/1/p"`
我接着用wget来请求带有(刚才提取的)演唱者和歌名参数的URL. 请求返回的XML结果被存在一个叫做search_results的shell变量中.
search_results=`wget -q "http://api.leoslyrics.com/api_search.php?auth=$AUTH&artist=$ARTIST&songtitle=$SONGTITLE" -O -`
接着,我用xmlstarlet来解析这个XML结果.下面这个例子是执行xmlstarlet的sel命令来解析这个文本的response元素:
result=`echo $search_results | xmlstarlet sel -t -v "/leoslyrics/response/text()"`
最后,我把上面提到的技巧合起来使用(来提取歌词),再用xmlstarlet的unesc命令处理一下(unsec仅仅是用来在文本中恢复所有的转义字符,这样读起来更方便)
echo $lyrics | xmlstarlet sel -t -v "/leoslyrics/lyric/text/text()" | xmlstarlet unesc > "$1.txt"
完整的脚本一次可以下载一首个歌的歌词.如果要下载你的所有歌的歌词,你可以使用带有exec参数的find命令,来在你的所有歌曲上执行这个脚本. 例如,你的歌曲库在/share/music/目录下,你可以执行:
find /share/music/ -iname *.mp3 -exec get_lyrics.sh {} ;
你可以很容易的在你喜欢的语言里,使用同样的URL请求和结果解析技术(只要这种语言可以提取网页并能解析XML).这些技术也可以修改后用到其他支持基于Web APIs的歌词数据库中.