声明:
树莓派采用树莓派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