点击这里给我发消息 点击这里给我发消息

微信公众帐号开发教程第18篇-应用实例之音乐搜索

添加时间:2014-4-10
    相关阅读: 开发 程序 链接 平台 百度
      微信公众平台支持向用户回复音乐消息,用户收到音乐消息后,点击即可播放音乐。通过音乐消息,公众账号可以实现音乐搜索(歌曲点播)功能,即用户输入想听的音乐名称,公众账号返回对应的音乐(歌曲)。读者可以关注xiaoqrobot体验该功能,操作指南及使用如下所示。
     考虑到歌曲名称有重复的情况,用户还可以同时指定歌曲名称、演唱者搜索歌曲。下面就为读者详细介绍歌曲点播功能的实现过程。
     音乐消息说明
     在微信公众平台开发者文档中提到,向用户回复音乐消息需要构造如下格式的XML数据。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
<xml>  
    <ToUserName><![CDATA[toUser]]></ToUserName>  
    <FromUserName><![CDATA[fromUser]]></FromUserName>  
    <CreateTime>12345678</CreateTime>  
    <MsgType><![CDATA[music]]></MsgType>  
    <Music>  
        <Title><![CDATA[TITLE]]></Title>  
        <Description><![CDATA[DESCRIPTION]]></Description>  
        <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>  
        <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>  
        <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>  
    </Music>  
</xml>  
     上面XML中,需要注意的是<Music>节点中的参数,说明如下:
     1)参数Title:标题,本例中可以设置为歌曲名称;
     2)参数Description:描述,本例中可以设置为歌曲的演唱者;
     3)参数MusicUrl:普通品质的音乐链接;
     4)参数HQMusicUrl:高品质的音乐链接,在WIFI环境下会优先使用该链接播放音乐;
     5)参数ThumbMediaId:缩略图的媒体ID,通过上传多媒体文件获得;它指向的是一张图片,最终会作为音乐消息左侧绿色方形区域的背景图片。
     上述5个参数中,最为重要的是MusicUrl和HQMusicUrl,这也是本文的重点,如何根据歌曲名称获得歌曲的链接。如果读者只能得到歌曲的一个链接,可以将MusicUrl和HQMusicUrl设置成一样的。至于ThumbMediaId参数,必须是通过微信认证的服务号才能得到,普通的服务号与订阅号可以忽略该参数,也就是说,在回复给微信服务器的XML中可以不包含ThumbMediaId参数。
     百度音乐搜索API介绍
    上面提到,给用户回复音乐消息最关键在于如何根据歌曲名称获得歌曲的链接,我们必须找一个现成的音乐搜索API,除非读者自己有音乐服务器,或者只向用户回复固定的几首音乐。百度有一个非公开的音乐搜索API,之所以说非公开,是因为笔者没有在百度官网的任何地方看到有关该API的介绍,但这并不影响读者对本例的学习,我们仍然可以调用它。百度音乐搜索API的请求地址如下:
      [html] view plaincopy在CODE上查看代码片派生到我的代码片
      http://box.zhangmen.baidu.com/x?op=12&count=1&title=TITLE$$AUTHOR$$$$  
      http://box.zhangmen.baidu.com为百度音乐盒的首页地址,上面的链接中不用管参数op和count,重点关注TITLE和AUTHOR,TITLE表示歌曲名称,AUTHOR表示演唱者,AUTHOR可以为空,参数TITLE和AUTHOR需要进行URL编码(UTF-8或GB2312均可)。例如,要搜索歌曲零点乐队的“相信自己”,可以像下面这样:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
// GB2312编码的音乐搜索链接  
http://box.zhangmen.baidu.com/x?op=12&count=1&title=%CF%E0%D0%C5%D7%D4%BC%BA$$%C1%E3%B5%E3%C0%D6%B6%D3$$$$  
// UTF-8编码的音乐搜索链接  
http://box.zhangmen.baidu.com/x?op=12&count=1&title=%E7%9B%B8%E4%BF%A1%E8%87%AA%E5%B7%B1$$%E9%9B%B6%E7%82%B9%E4%B9%90%E9%98%9F$$$$  
通过浏览器访问上面的地址,返回的是如下格式的XML数据:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
<result>  
    <count>1</count>  
    <url>  
        <encode>  
            <![CDATA[http://zhangmenshiting.baidu.com/data2/music/44277542/ZWZla2xra2pfn6NndK6ap5WXcJVob5puZ2trbWprmnBjZ2xolpeZa2drZmWZmZmdl2hjZWhvnWlpYmRtZmltcGplZFqin5t1YWBobW5qcGxia2NmZ2twbzE$]]>  
        </encode>  
        <decode>  
            <![CDATA[44277542.mp3?xcode=a39c6698955c82594aab36931dcbef60139f180191368931&mid=0.59949419022597]]>  
        </decode>  
        <type>8</type>  
        <lrcid>64644</lrcid>  
        <flag>1</flag>  
    </url>  
    <durl>  
        <encode>  

            <![CDATA[http://zhangmenshiting2.baidu.com/data2/music/44277530/ZWZla2xramhfn6NndK6ap5WXcJVob5puZ2trb

WprmnBjZ2xolpeZa2drZmWZmZmdl2hjaGhvnZ5qlGRpbpedamJla1qin5t1YWBobW5qcGxia2NmZ2twbzE$]]>  

        </encode>  
        <decode>  
            <![CDATA[44277530.mp3?xcode=a39c6698955c82594aab36931dcbef60439ff9b159af2138&mid=0.59949419022597]]>  
        </decode>  
        <type>8</type>  
        <lrcid>64644</lrcid>  
        <flag>1</flag>  
    </durl>  
    <p2p>  
        <hash>022bc0fbf66cd19bea96db49634419dc2600393f</hash>  
        <url>  
            <![CDATA[ ]]>  
        </url>  
        <type>mp3</type>  
        <size>5236902</size>  
        <bitrate>192</bitrate>  
    </p2p>  
</result>  
      返回结果中的主要参数说明如下:
     1)<count> 表示搜索到的音乐数;
     2)<url>中包含了普通品质的音乐链接,<durl>中包含了高品质音乐的链接;
     3)<encode>中包含了加密后的音乐链接,实际上只是对音乐名称进行了加密,<decode>中包含了解密后的音乐名称。因此,要获取      音乐的链接就需要重点分析<encode>和<decode>中的内容,下面会专门为读者进行介绍。
     4)<type>表示音乐文件的类型,如rm、wma、mp3等;
     5)<lrcid>是歌词的ID,<url>中的歌词ID为64644,那么如何得到歌词呢?本例并不关心歌词,只是附带提一下。歌词的地址如下:
     [html] view plaincopy在CODE上查看代码片派生到我的代码片
     http://box.zhangmen.baidu.com/bdlrc/646/64644.lrc  
     其中,http://box.zhangmen.baidu.com/bdlrc/是固定值;646为歌词所在目录名,计算方法为歌词ID(64644)除以100,取整数部分;64644.lrc是歌词文件名。
     下面来看如何从<encode>和<decode>中得到音乐链接。为了便于说明,笔者将上面搜索结果中的<url>和<durl>部分抽取出来,并进行了标注,如下图所示。


     上图中,1和2拼接起来是普通品质音乐的链接,3和4拼接起来是高品质音乐的链接。也就是说,普通品质和高品质的音乐链接如下:
 [html] view plaincopy在CODE上查看代码片派生到我的代码片
// 普通品质音乐链接  
http://zhangmenshiting.baidu.com/data2/music/44277542/44277542.mp3?xcode=a39c6698955c82594aab36931dcbef60139f180191368931  
// 高品质音乐链接  
http://zhangmenshiting2.baidu.com/data2/music/44277530/44277530.mp3?xcode=a39c6698955c82594aab36931dcbef60439ff9b159af2138  
       参数xcode可以理解为随机验证码,每次搜索得到的值都不一样,如果不带该参数会报未授权异常“401 Authorization Required”。需要注意的是,xcode是有时间限制的,超过限制再访问链接会报异常:{"Error":{"code":"2","Message":"object not exists","LogId":"3456414897"}}。在xcode有效的前提下,通过浏览器访问上面的音乐链接,会提示下载音乐。
      编程调用百度音乐搜索API
      知道如何从API返回结果中得到音乐链接后,就可以编写程序来实现了。笔者将发送HTTP请求、URL编码、解析XML等操作全部封装         在BaiduMusicService类中,该类的代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
import java.io.InputStream;  
import java.io.UnsupportedEncodingException;  
import java.net.HttpURLConnection;  
import java.net.URL;  
import java.util.List;  
  
import org.dom4j.Document;  
import org.dom4j.Element;  
import org.dom4j.io.SAXReader;  
  
import org.liufeng.course.message.resp.Music;  
  
/** 
 * 百度音乐搜索API操作类 
 *  
 * @author liufeng 
 * @date 2013-12-09 
 */  
public class BaiduMusicService {  
    /** 
     * 根据名称和作者搜索音乐 
     *  
     * @param musicTitle 音乐名称 
     * @param musicAuthor 音乐作者 
     * @return Music 
     */  
    public static Music searchMusic(String musicTitle, String musicAuthor) {  
        // 百度音乐搜索地址  
        String requestUrl = "http://box.zhangmen.baidu.com/x?op=12&count=1&title={TITLE}$${AUTHOR}$$$$";  
        // 对音乐名称、作者进URL编码  
        requestUrl = requestUrl.replace("{TITLE}", urlEncodeUTF8(musicTitle));  
        requestUrl = requestUrl.replace("{AUTHOR}", urlEncodeUTF8(musicAuthor));  
        // 处理名称、作者中间的空格  
        requestUrl = requestUrl.replaceAll("\\+", "%20");  
  
        // 查询并获取返回结果  
        InputStream inputStream = httpRequest(requestUrl);  
        // 从返回结果中解析出Music  
        Music music = parseMusic(inputStream);  
  
        // 如果music不为null,设置标题和描述  
        if (null != music) {  
            music.setTitle(musicTitle);  
            // 如果作者不为"",将描述设置为作者  
            if (!"".equals(musicAuthor))  
                music.setDescription(musicAuthor);  
            else  
                music.setDescription("来自百度音乐");  
        }  
        return music;  
    }  
  
    /** 
     * UTF-8编码 
     *  
     * @param source 
     * @return 
     */  
    private static String urlEncodeUTF8(String source) {  
        String result = source;  
        try {  
            result = java.net.URLEncoder.encode(source, "UTF-8");  
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
    /** 
     * 发送http请求取得返回的输入流 
     *  
     * @param requestUrl 请求地址 
     * @return InputStream 
     */  
    private static InputStream httpRequest(String requestUrl) {  
        InputStream inputStream = null;  
        try {  
            URL url = new URL(requestUrl);  
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setRequestMethod("GET");  
            httpUrlConn.connect();  
            // 获得返回的输入流  
            inputStream = httpUrlConn.getInputStream();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return inputStream;  
    }  
  
    /** 
     * 解析音乐参数 
     *  
     * @param inputStream 百度音乐搜索API返回的输入流 
     * @return Music 
     */  
    @SuppressWarnings("unchecked")  
    private static Music parseMusic(InputStream inputStream) {  
        Music music = null;  
        try {  
            // 使用dom4j解析xml字符串  
            SAXReader reader = new SAXReader();  
            Document document = reader.read(inputStream);  
            // 得到xml根元素  
            Element root = document.getRootElement();  
            // count表示搜索到的歌曲数  
            String count = root.element("count").getText();  
            // 当搜索到的歌曲数大于0时  
            if (!"0".equals(count)) {  
                // 普通品质  
                List<Element> urlList = root.elements("url");  
                // 高品质  
                List<Element> durlList = root.elements("durl");  
  
                // 普通品质的encode、decode  
                String urlEncode = urlList.get(0).element("encode").getText();  
                String urlDecode = urlList.get(0).element("decode").getText();  
                // 普通品质音乐的URL  
                String url = urlEncode.substring(0, urlEncode.lastIndexOf("/") + 1) + urlDecode;  
                if (-1 != urlDecode.lastIndexOf("&"))  
                    url = urlEncode.substring(0, urlEncode.lastIndexOf("/") + 1) + urlDecode.substring(0, urlDecode.lastIndexOf("&"));  
  
                // 默认情况下,高音质音乐的URL 等于 普通品质音乐的URL  
                String durl = url;  
  
                // 判断高品质节点是否存在  
                Element durlElement = durlList.get(0).element("encode");  
                if (null != durlElement) {  
                    // 高品质的encode、decode  
                    String durlEncode = durlList.get(0).element("encode").getText();  
                    String durlDecode = durlList.get(0).element("decode").getText();  
                    // 高品质音乐的URL  
                    durl = durlEncode.substring(0, durlEncode.lastIndexOf("/") + 1) + durlDecode;  
                    if (-1 != durlDecode.lastIndexOf("&"))  
                        durl = durlEncode.substring(0, durlEncode.lastIndexOf("/") + 1) + durlDecode.substring(0, durlDecode.lastIndexOf("&"));  
                }  
                music = new Music();  
                // 设置普通品质音乐链接  
                music.setMusicUrl(url);  
                // 设置高品质音乐链接  
                music.setHQMusicUrl(durl);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return music;  
    }  
  
    // 测试方法  
    public static void main(String[] args) {  
        Music music = searchMusic("相信自己", "零点乐队");  
        System.out.println("音乐名称:" + music.getTitle());  
        System.out.println("音乐描述:" + music.getDescription());  
        System.out.println("普通品质链接:" + music.getMusicUrl());  
        System.out.println("高品质链接:" + music.getHQMusicUrl());  
    }  
}  
      下面对代码进行简单的说明:
      1)代码中的Music类是对音乐消息的封装(不包括ThumbMediaId参数),读者可以在本系列教程的第4篇中找到该类的定义;
       2)运行上述代码需要引入dom4j的JAR包,笔者使用的是dom4j-1.6.1.jar;
       3)searchMusic()方法是提供给外部调用的,在CoreService类中会调用该方法获得音乐消息需要的Music相关的4个参数(Title、             Description、MusicUrl和HQMusicUrl);
      4)parseMusic()方法用于解析XML,读者可以结合代码中的注释和之前对XML的分析进行理解,这里就不再赘述了。
      5)116行、127行中的get(0)表示返回多条音乐结果时默认取第一条。
      公众账号后台的实现
      在公众账号后台的CoreService类中,需要对用户发送的文本消息进行判断,如果是以“歌曲”两个字开头,就认为用户是在使用“歌曲点播”功能,此时需要对“歌曲”两个字之后的内容进行判断,如果包含“@”符号,就表示需要按演唱者搜索,否则不指定演唱者。CoreService 类的完整代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
咨询热线:020-85648757 85648755 85648616 0755-27912581 客服:020-85648756 0755-27912581 业务传真:020-32579052
广州市网景网络科技有限公司 Copyright◎2003-2008 Veelink.com. All Rights Reserved.
广州商务地址:广东省广州市黄埔大道中203号(海景园区)海景花园C栋501室
= 深圳商务地址:深圳市宝源路华丰宝源大厦606
研发中心:广东广州市天河软件园海景园区 粤ICP备05103322号 工商注册