声明:
树莓派采用树莓派3B。
音乐源来自网易云音乐。
正文:
根据整个树莓派折腾的经历,该项目主要沿着如下的路线递进:听歌->在线听歌->在线自由听歌->远程操控树莓派播放。
首先是听歌部分。无论是在Windows图形界面还是Linux图形界面中,都有许多可供选择的音乐播放器。但是在命令行情形下,就少得多了。其中比较知名的有mplayer,mpg123等。经测试,mpg123对mp3的支持不好,mplayer最佳。它的运行格式如下:
mplayer/home/pi/Music/XXX.mp3
但是以上方法有个缺点,只能播放本地音乐。由于SD卡容积较小,存放大量音乐过于浪费空间,播放在线音乐能解决以上问题。幸运的是,mplayer支持直接播放在线音乐,只需知道歌曲的URL地址即可。网络上有许多能提取直链的网站,比如:http://music.liuzhijin.cn/。
mplayer播放在线音乐的格式如下:
mplayer http://m2.236.net.XXX.mp3
同样的,这一个方法也有一个问题:每当我们想要听一首歌,还必须搜索它的直链,这无疑非常麻烦。为了解决这个问题,网络上有不少获取音乐直链的方法。以网易云音乐为例,主要有三种方法:
1.模拟登录web界面,进行处理。该方法不仅能实现音乐播放,还能实现登录等功能。
2.模拟网易云音乐安卓客户端1.5.2的行为,每次申请从网易服务端读取数据。
3.从网易给某些应用提供的音乐插件入手,分析其行为,得到数据。但功能有限
由于我只需要获得音乐直链,不需要进行登录,查看榜单等操作。因此我选择第三种方式,并寻找到了网易云音乐给网易旗下产品LOFTER的音乐接口。可能因为同属一家公司的缘故,该接口异常简单。它的形式如下:http://s.music.163.com/search/get/?src=lofter &type=1&s=X&limit=3,其中,s=后面即是需要搜索的内容,甚至无任何编码,type为搜索类型查询类型,1为单曲,10为专辑,100为歌手,1000为歌单,1002为用户。limit后为返回条数。而且网页返回的为裸露的json数据,非常易于提取。
到此,我们需要的数据基本采集完毕。我制作了一个脚本,用户输入想要搜索的歌曲名字,并指定播放曲目,便能轻松听歌。
脚本的实现思路如下:第一步,利用 urllib2函数将网页上的内容得到。第二步,通过reads及json.loads方法将内容解码成字典形式。第三步,观察字典格式,提取出我们想要的数据,比如直链可由以下命令提取:name1 = html[‘result’][‘songs’][0][‘name’]。第四步,调用mplayer播放该流媒体。为了方便,我们使用commands.getoutput方法让播放之灵在Python内部执行。
看上去简单,但是在编写脚本中遇到了不少的问题,比如某些歌曲很冷门,返回数据不足三首,我们利用字典路径查询时会出错。要解决这个问题,首先要知道它返回了多少首歌,并根据不同情况返回相应提示。一般来说,有两种方法:一是检查song下属有多少个段落,则得到多少首歌。二是通过一些特殊字符的个数得到歌曲数,我的方法是数“=”字符的个数,因为每一首歌会返回两个地址,一是专辑图片,二是音频地址。每个地址都包含两个“=”字符,因此数“=”的个数,再除以四即可。(注:此处直接得到json字段长度即可,更加简便)
完成脚本基本功能之后,为了方便用户使用,我还添加了一些实用的功能。比如帮助按钮,比如改变字体颜色,更加醒目。
该脚本的源码见附录。
该脚本能够实现在命令行中自动搜索并播放,但很多时候我们需要在移动设备上控制音箱。比如:在微信上发送指令,即可实现多种功能。这里介绍一个比较成熟的项目:微信-树莓派-网易云音乐[1],它基于ItChat项目以及命令行云音乐项目。将树莓派作为播放器,通过ItChat将树莓派和微信账号结合起来。任何对该账号的指令都能被树莓派读取。树莓派读取相关指令,结合Python代码中的定义,执行相关指令。
附录:
# -*- coding: utf-8 -*-
import urllib2
import json
import sys, getopt
import commands
import collections
reload(sys)
sys.setdefaultencoding('utf-8')
def main(argv):
searchname = ''
number = '0'
try:
opts, args = getopt.getopt(argv,'h',["name=","num="])
except getopt.GetoptError:
print '对不起,参数输入不完整,请重新输入'
sys.exit()
for opt, arg in opts:
if opt == '-h':
print '\n本项目源采用网易云音乐,播放器采用mplayer\n--name 写入歌曲名字\n--num 选择歌曲序号\n<- , -> 可快进快退\n9,0可增加减小音量'
sys.exit()
elif opt in ("--name"):
searchname = arg
elif opt in ("--num"):
number = arg
shtml = r'http://s.music.163.com/search/get/?src=lofter&type=1&filterDj=true&s=%s&limit=3'%(searchname)
html = urllib2.urlopen(shtml)
html = html.read() #句柄转化成字符串处理
counts = collections.Counter(html)
counts = counts['='] #此处最好用len函数判断songs底下的段落数目
counts = counts/4
html = json.loads(html) #解码json格式
if counts>0:
name1 = html['result']['songs'][0]['name']
singer1 = html['result']['songs'][0]['artists'][0]['name']
album1 = html['result']['songs'][0]['album']['name']
url1 = html['result']['songs'][0]['audio']
print '\n\033[1;36;40m1.歌名:%s \n 歌手:%s \n 专辑:%s \033[0m'%(name1,singer1,album1)
if counts>1:
name2 = html['result']['songs'][1]['name']
singer2 = html['result']['songs'][1]['artists'][0]['name']
album2 = html['result']['songs'][1]['album']['name']
url2 = html['result']['songs'][1]['audio']
print '\n\033[1;36;40m2.歌名:%s \n 歌手:%s \n 专辑:%s \033[0m'%(name2,singer2,album2)
if counts>2:
name3 = html['result']['songs'][2]['name']
singer3 = html['result']['songs'][2]['artists'][0]['name']
album3 = html['result']['songs'][2]['album']['name']
url3 = html['result']['songs'][2]['audio']
print '\n\033[1;36;40m3.歌名:%s \n 歌手:%s \n 专辑:%s \033[0m'%(name3,singer3,album3)
if counts==0:
print '未指定搜索内容或搜索无结果'
if number =='1':
a = 'mplayer %s'%(url1)
print '\n\033[5;31;40m♪♪\033[0m\033[0;31;40m正在播放第一首曲目\033[0m\033[5;31;40m♪♪\033[0m'
commands.getoutput(a)
if number =='2':
a = 'mplayer %s'%(url2)
print '\n\033[5;31;40m♪♪\033[0m\033[0;31;40m正在播放第二首曲目\033[0m\033[5;31;40m♪♪\033[0m'
commands.getoutput(a)
if number =='3':
a = 'mplayer %s'%(url3)
print '\n\033[5;31;40m♪♪\033[0m\033[0;31;40m正在播放第三首曲目\033[0m\033[5;31;40m♪♪\033[0m'
commands.getoutput(a)
if __name__ == "__main__":
main(sys.argv[1:])
[1] GitHub上的地址为:https://github.com/yaphone/RasWxNeteaseMusic