文档章节

在线音乐API的研究 (Part 2.1)

Kobe_Gong_5
 Kobe_Gong_5
发布于 2014/02/18 21:24
字数 1582
阅读 136
收藏 1

最近,在优化一个自己写的音乐播放器。主要目的是回顾、归纳,并希望能够写出一个属于自己的common lib。今天,主要是关于在线音乐API的一些分析结果。此次,主要分析的是歌词、专辑部分。在线搜索音乐、热门音乐及mp3的下载等,会在PART 2.2进行补充。

      原始API来源于网络资料,部分是后面使用个人补充的。主要包括百度API、腾讯API及歌词迷API,其中只有歌词迷的API是官方正式发布的。三个API都有着各自的优点、缺点,如下:

      (1) 百度API,请求方式稳定,速度快,资源最多,获取歌词比较准确;但是数据结构相对繁杂些,每行的歌词长度差异比较大。

      (2) 腾讯API,请求方式相对稳定,速度快,资源较多,准确度高,每行的歌词长度相当;但JSON(Xml相对正常)数据结构并不完全标准,解析麻烦, 专辑图片封面(约50KB|500 x 500 像素)较大。

      (3)歌词迷API,有官方正式API,使用简单,专辑封面相对小些(约10KB|185 x 160 像素);遗憾的是资源相对少,尤其在最新的资源方面,有点慢。

      提醒:以上全是个人开发的总结,并没有完整体系性的验证。

      如专辑封面大小问题,视乎个人开发需要而定,如果需要大图片,腾讯的保真度高,如果需要小图片,无疑歌词迷更好些。

      本人在歌词方面使用的腾讯API,专辑封面使用的是歌词迷API。 

       整个实现思路比较明确,大体上的类图设计如下:

Osmondy Lyric

      直接使用LyricLoader的loadLyric()方法进行歌词下载,loadLyric()方法封装了具体的处理逻辑,具体实现下载,由子类实现IDownload<Lyric>接口。摘取部分代码:

/** * 歌词助手 *  * @author Osmondy *  */public abstract class LyricLoader implements IDownload<Lyric>{        public LyricLoader(String name)    {            }        /**     * 获取网络请求歌词地址     *      * @param music     * @return     */    public abstract String getServerLyricUrl(Music music);        /**     * 返回本地存储歌词的路径     *      * @param music     * @return     */    protected String getLocalLyricPath(String songname, String singername)    {            }        /**     * 返回歌词, Step1: 本地歌词目录加载; Step2: 网络下载.     *      * @param music     * @return     */    public Lyric loadLyric(Music music)    {        if (TextUtils.isEmpty(music.getArtist()) || TextUtils.isEmpty(music.getTitle()))        {            Log.W(TAG, "Empty aritst or title, can't find lyric.");                        return null;        }                Lyric lyric = null;        String localPath = getLocalLyricPath(music.getTitle(), music.getArtist());                File file = new File(localPath);        if (file.exists())        {            // 本地存在歌词文件, 直接加载此歌词.            Log.D(TAG, "Loading lyric from local path.");            try            {                lyric = loadLocalLyric(localPath);                if (lyric != null)                {                    lyric.setSongname(music.getTitle());                    lyric.setSingername(music.getArtist());                                        Log.I(TAG, "Load local lyric finished. Lyric: " + lyric);                }            }            catch (IOException e)            {                if (e instanceof FileNotFoundException)                {                    Log.W(TAG, "Lyric not found.");                }                else                {                    e.printStackTrace();                }            }                        return lyric;        }                String requestUrl = getServerLyricUrl(music);                if (!TextUtils.isEmpty(requestUrl))        {            Log.D(TAG, "---------- Download lyric start ----------");            try            {                lyric = download(requestUrl, localPath);            }            catch (HttpRequestException e)            {                e.printStackTrace();            }                        Log.D(TAG, "---------- Download lyric end ----------");                        return lyric;        }                Log.W(TAG, "Not found a correct server lyric path.");                return null;            }        /**     * 保存歌曲文件, 默认保存至{@link AppConfig#DIRECTORY_LYRIC}, 子类可自行重写保存至其它路径. 保存时,     * 先保存成*.lrc.tmp, 下载及保存成功后, 再重命名为*.lrc. 防止异常或停止下载歌词, 下次无法再次下载.     *      * @param is     * @param music     * @return     */    protected boolean saveLyric(InputStream is, String savePath)    {            }        /**     * 返回指定地址的歌词文件     *      * @param path     * @return     * @throws IOException     */    public Lyric loadLocalLyric(String path) throws IOException    {            }    }

     抽象类LyricLoader提供了对歌词保存、加载的默认处理方式,子类可以自行重写saveLyric()、loadLocalLyric()定义自己的处理方式。子类的实现以百度API为例,它使用的是父类LyricLoader提供的默认实现。

/** * 歌词来源于Baidu *  * @author Osmondy *  */public class BaiduLyricHelper extends LyricLoader{        private static final String TAG = "BaiduLyricHelper";        /**     * 歌曲信息请求地址     */    protected static final String SONGINFO_BASE_URL = "http://box.zhangmen.baidu.com/x";        /**     * 歌词文件请求地址     */    protected static final String LYRIC_BASE_URL = "http://box.zhangmen.baidu.com/bdlrc";        public BaiduLyricHelper()    {        super("BaiDu");    }        @Override    public Lyric download(String requestUrl, String savePath) throws HttpRequestException    {            }        @Override    public String getServerLyricUrl(Music music)    {            }    }

     比较完整的代码已经上传至github:https://github.com/osmondy/LyricApi

 

      原始API如下:

      (1) 百度API

      歌曲信息请求地址:http://box.zhangmen.baidu.com/x?op=12&count=1&title=歌词名称$$歌手名称$$$$

      歌词信息请求地址:http://box.zhangmen.baidu.com/bdlrc/歌词ID除以100/歌词ID.lrc

/**     * 返回请求歌词的地址, 通过 SongInfo生成最终可请求到歌词文件的地址. </br>     *      * @param songInfo     * @return     */    protected String getServerLyricUrlBySongInfo(SongInfo songInfo)    {        int lrcid = songInfo.getLrcid();        int postfix = lrcid / 100;                StringBuffer sb = new StringBuffer();        sb.append(LYRIC_BASE_URL);        sb.append("/");        sb.append(postfix);        sb.append("/");        sb.append(lrcid);        sb.append(".lrc");                return sb.toString();    }    @Override    public String getServerLyricUrl(Music music)    {        if (TextUtils.isEmpty(music.getTitle()) || TextUtils.isEmpty(music.getArtist()))        {            return null;        }        //protected static final String SONGINFO_BASE_URL = "http://box.zhangmen.baidu.com/x?op=12&count=1&title=";        Log.D(TAG, "Songname: " + music.getTitle() + ", Singername: " + music.getArtist());        StringBuffer sb = new StringBuffer();        try        {            sb.append(SONGINFO_BASE_URL);            sb.append("?");            sb.append("op=12");            sb.append("&");            sb.append("count=1");            sb.append("&");            sb.append("title=");            sb.append(URLEncoder.encode(music.getTitle(), "utf-8"));            sb.append("$$");            sb.append(URLEncoder.encode(music.getArtist(), "utf-8"));            sb.append("$$$$");        }        catch (UnsupportedEncodingException e)        {            e.printStackTrace();        }                return sb.toString();    }

构建请求的URL

 

      (2) 腾讯API

      编码并非是UTF-8,而是GBK(gb2312)。

      歌曲信息请求地址:http://qqmusic.qq.com/fcgi-bin/qm_getLyricId.fcg?name=连哭都是我的错&singer=东来东往&from=qqplayer

      歌词请求地址:http://music.qq.com/miniportal/static/lyric/歌曲ID求余100/歌曲ID.xml

      专辑封面请求地址:http://imgcache.qq.com/music/photo/album/专辑ID求余100/albumpic_专辑ID_0.jpg

/**     * 返回请求歌词的地址, 通过 SongInfo生成最终可请求到歌词文件的地址. </br>     * 请求地址格式: http://music.qq.com/miniportal/static/lyric/67/183767.xml     *      * @param songInfo     * @return     */    protected String getServerLyricUrlBySongInfo(SongInfo songInfo)    {        String id = songInfo.getId();                if (!StringUtils.isNumeric(id))        {            return null;        }        int postfix = Integer.parseInt(id) % 100;                StringBuffer sb = new StringBuffer();        sb.append(LYRIC_BASE_URL);        sb.append("/");        sb.append(postfix);        sb.append("/");        sb.append(id);        sb.append(".xml");                return sb.toString();    }        /**     * 返回请求歌曲信息的地址.     * 请求地址格式: http://qqmusic.qq.com/fcgi-bin/qm_getLyricId.fcg?name=连哭都是我的错&singer=东来东往&from=qqplayer     */    @Override    public String getServerLyricUrl(Music music)    {        if (TextUtils.isEmpty(music.getTitle()) || TextUtils.isEmpty(music.getArtist()))        {            return null;        }                Log.D(TAG, "Songname: " + music.getTitle() + ", Singername: " + music.getArtist());        StringBuffer sb = new StringBuffer();        try        {            sb.append(SONGINFO_BASE_URL);            sb.append("?");            sb.append("name=" + URLEncoder.encode(music.getTitle(), "gbk"));            sb.append("&");            sb.append("singer=" + URLEncoder.encode(music.getArtist(), "gbk"));            sb.append("&");            sb.append("from=qqplayer");        }        catch (UnsupportedEncodingException e)        {            e.printStackTrace();        }                return sb.toString();    }

构建请求的URL

 

      (3)歌词迷API

      直接提供官方地址:http://api.geci.me/en/latest/

      歌词请求地址:http://geci.me/api/lyric/:歌曲名/:歌手名

      专辑封面请求地址:http://geci.me/api/cover/:专辑ID

@Override    public String getServerLyricUrl(Music music)    {        if (TextUtils.isEmpty(music.getTitle()) || TextUtils.isEmpty(music.getArtist()))        {            return null;        }                Log.D(TAG, "Songname: " + music.getTitle() + ", Singername: " + music.getArtist());        StringBuffer sb = new StringBuffer();        try        {            sb.append(LYRIC_BASE_PATH);            sb.append("/");            sb.append(URLEncoder.encode(music.getTitle(), "utf-8"));            sb.append("/");            sb.append(URLEncoder.encode(music.getArtist(), "utf-8"));        }        catch (UnsupportedEncodingException e)        {            e.printStackTrace();        }                return sb.toString();    }        /**     * 返回歌曲专辑信息请求地址     *      * @param albumId     * @return     */    public String getServerAlbumUrl(String albumId)    {        return ALBUM_BASE_PATH + "/" + albumId;    }

构建请求的URL

      

      最后,附上腾讯如何获取新歌榜及总榜的请求。

      新歌榜:http://music.qq.com/musicbox/shop/v3/data/hit/hit_newsong.js
      总榜:http://music.qq.com/musicbox/shop/v3/data/hit/hit_all.js

本文转载自:http://www.th7.cn/Program/Android/201308/147619.shtml

共有 人打赏支持
上一篇: 歌词迷API文档
下一篇: baiduMP3接口1
Kobe_Gong_5
粉丝 2
博文 55
码字总数 43587
作品 0
成都
私信 提问
Scripture 2.1 发布,在线圣经学习工具

Scripture 2.1 发布,Scripture 是一个在线和移动的研究中的应用,允许用户阅读,互动,并采用了许多独特的功能和工具研究圣经。 新版本改进记录: This release features paraphrased sear...

oschina
2012/11/04
160
1
中央音乐学院招音乐AI方向博士生,玩一把代码与音符齐飞?

整理 | 一一 出品 | AI科技大本营(ID:rgznai100) 无疑,如今频上热搜 AI 写词作曲给人们带来了意想不到的新鲜感。 去年的中国好声音上,清华大学博士生宿涵直接将 AI 写的歌改编后唱了出来...

AI科技大本营
03/04
0
0
AI 进军音乐界!它已经创造出了前所未有的声音

在过去,人工智能听起来似乎是一个非常遥远的词,仿佛只存在于未来幻想的电影和书里面。“人工智能”的这种表达方式就可能会引发争议,人们会担心那些无脸的机器人将很快取代自己和同事的位置...

王练
2017/06/05
1K
8
明明是悲伤的音乐,你却在享受什么?

文 / @C57 一年总有个那么365天,一天总有个24小时,我们会为自己矛盾的行为感到疑惑。 早上,7:00,我们会按掉前一晚定好的闹钟继续睡觉。 上午,9:00,心里不停催促自己努力工作学习的我们...

溪五七七C57
2018/01/14
0
0
MIT最新:机器学习首次模仿大脑处理声音,能辩歌词和歌曲分类

     大数据文摘作品   编译:大茜、笪洁琼、云舟   你是否对于Spotify之类的软件产生过这样的疑问:“Spotify,你放音乐的时候在想什么?”实际上这类软件可能会像你一样思考。   ...

大数据文摘
2018/05/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

《大话数据结构》读后总结(四)

一、算法 1、算法效率的度量方法 1.1 事后统计方法 通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。该方法具有很大缺陷,不...

徐曙辉
44分钟前
2
0
Android 整体设计及背后意义

阿里妹导读:现实工作中经常可以听到这样的说法:框架的升级带来协议性能的提升、编程模式的变革带来业务的飞跃...... 姑且不论这些表述是否有问题,实际上如果系统地看待事物整体,可能会有...

阿里云云栖社区
46分钟前
2
0
一文纵览EMAS 到底内含多少阿里核心技术能力

EMAS的整体定位是阿里巴巴移动技术对外输出的主窗口,沉淀了阿里巴巴近10年在移动互联网技术架构上的积累以及在一系列垂直场景中所实践的核心技术能力。一方面,EMAS希望为广大开发者提供安全...

阿里云官方博客
今天
2
0
Prometheus简介

Prometheus是什么? Prometheus(普罗米修斯)是一套最初在SoundCloud上构建的开源监视和告警系统 。 特征 普罗米修斯的主要特点是: 具有由度量名称和键/值对标识的时间序列数据的多维数据模...

阿dai学长
今天
2
0
Android 动画Animation

动画分为视图动画(view animation)和属性动画(property animation),视图动画又分为帧动画和补间动画 视图动画控件(iv)点击事件(OnClickListener接口)触发位置在原位置 1.帧动画(Fra...

Coding缘
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部