如何为豆瓣FM写一个chrome的歌词插件

对于喜欢豆瓣FM的同学来说,没有歌词是件令人苦恼的事,下面我就来总结下怎样为豆瓣FM写一个chrome的歌词插件。

1.需要的技能

首先,你要会javascript,其次你要掌握一点chrome的hack,最后要有一个可以根据歌曲名查到歌词的API。

2.localStorage

localStorage与cookie类似,它是存储在客户端浏览器中的数据,它与cookie不同的一点是它没有时间限制。localStorage属于html5中的新特性。因为我们要做chrome的插件,所以按F12弹出开发者模式,点击resource,就可以看见localstorage选项了,通过localStorage,我们可以得到当前豆瓣播放的歌曲的id,歌曲名,演唱者等信息:

3.歌词迷的API

请求地址: http://geci.me/api/lyric/:song
返回格式: JSON
请求方法: GET
示例: 
curl 'http://geci.me/api/lyric/海阔天空'

返回:

{
    "count": 15,
    "code": 0,
    "result": [
        { "aid": 2848529, "lrc": "http://s.geci.me/lrc/344/34435/3443588.lrc", "sid": 3443588, "artist_id": 2, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2346662, "lrc": "http://s.geci.me/lrc/274/27442/2744281.lrc", "sid": 2744281, "artist_id": 2396, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1889264, "lrc": "http://s.geci.me/lrc/210/21070/2107014.lrc", "sid": 2107014, "artist_id": 8715, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2075717, "lrc": "http://s.geci.me/lrc/236/23651/2365157.lrc", "sid": 2365157, "artist_id": 8715, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1563419, "lrc": "http://s.geci.me/lrc/166/16685/1668536.lrc", "sid": 1668536, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1567586, "lrc": "http://s.geci.me/lrc/167/16739/1673997.lrc", "sid": 1673997, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1571906, "lrc": "http://s.geci.me/lrc/167/16796/1679605.lrc", "sid": 1679605, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1573814, "lrc": "http://s.geci.me/lrc/168/16819/1681961.lrc", "sid": 1681961, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1656038, "lrc": "http://s.geci.me/lrc/179/17907/1790768.lrc", "sid": 1790768, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 1718741, "lrc": "http://s.geci.me/lrc/187/18757/1875769.lrc", "sid": 1875769, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2003267, "lrc": "http://s.geci.me/lrc/226/22642/2264296.lrc", "sid": 2264296, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2020610, "lrc": "http://s.geci.me/lrc/228/22889/2288967.lrc", "sid": 2288967, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2051678, "lrc": "http://s.geci.me/lrc/233/23323/2332322.lrc", "sid": 2332322, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2412704, "lrc": "http://s.geci.me/lrc/283/28376/2837689.lrc", "sid": 2837689, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" },
        { "aid": 2607041, "lrc": "http://s.geci.me/lrc/311/31116/3111659.lrc", "sid": 3111659, "artist_id": 9208, "song": "\u6d77\u9614\u5929\u7a7a" }
    ]
}

4.重头戏----javascript脚本

有了上面的准备工作,我们现在就可以安心的编码了。

首先,创建一个DoubanFM伪类(javascript中没有“真正的”类)

funciton DoubanFM() {
	this.name = '豆瓣FM';
	this.tmp_song_id = '';
	this.flag = 1;
	this.lyrics = this.draw_lyrics();
}

然后,对这个伪类拓展原型,创建新的函数:

【注】关于javascript拓展函数原型,我原来写过一篇博客:http://blog.csdn.net/wusuopubupt/article/details/14520209

用javascript创建新的节点(一个显示歌词的div,同时设置div的css):

DoubanFM.prototype.draw_lyrics = funciton() {
	var lyrics_div = document.createElement('div');//用document.createElement()方法可以创造新的节点
	document.body.appendChild(lyrics_div);//用document.body.appendChild()方法把新的节点附加到到document中
	lyrics_div.style.width = '900px';//下面几行是设置css
	lyrics_div.style.backgroundColor = '#F00';
	lyrics_div.style.zIndex = '42';
	lyrics_div.style.position = 'relative';
	lyrics_div.style.margin = '200px auto 0';
	
	return lyrics_div;
}

根据localstorage里获取的信息,构造获取歌词的url:

DoubanFM.prototype.geci_entry_url = function(song, artist) {
	if (song == undefined || song == null || song == '') return '';
	var url = 'http://geci.me/api/lyric/' + song;
	if (!(artist == undefined || artist == null || artist == '')) {
		url += '/' + artist;
	}
	console.log(url);
	return url;
}

用AJAX方式异步请求歌词:

Douban.prototype.request_geci = function() {
	eval('var stored_song = ' + localStorage['bubbler_song_info']);//这里是重点,localstorage!
	console.log('the song in localStorage:' + stored_song.artist + ' ' + stored_song.song_name);
	if (this.tmp_song_id != stored_song.id) {
		console.log(this.tmp_song_id + ' is not ' + stored_song.id);
		var url = this.geci_entry_url(stored_song.song_name, stored_song.artist);
		this.tmp_song_id = stored_song.id;
		this.ajax_get(url);
	}
}

ajax请求:

DoubanFM.prototype.ajax_get = function(url) {
	var XHR = new XMLHttpRequest();
	var obj = this;
	//一次典型的原生js发起的AJAX请求
	XHR.onreadystatechange = function() {
		if (XHR.readyState == 4) {
			if (XHR.status == 200) {
				obj.deal_response(XHR.responseText);
			} else {
				obj.print_lyrics('获取歌词失败');
			}
		} else {
			obj.print_lyrics('歌词搜索中');
		}
	}
	
	XHR.open('GET', url, true);
	XHR.send();
}

DoubanFM.prototype.deal_response = function(data) {
	if (this.flag == 1) {
		eval('var resp = ' + data);
		if (resp.count > 0) {
			this.ajax_get(resp.result[0].lrc);
			this.flag++;
		} else {
			this.print_lyrics('没有找到歌词');
		}
	} else {
		this.print_lyrics(this.format(data));
		this.ajax_flag = 1;
	}
}

对返回的歌词做处理:

DoubanFM.prototype.format = function(text) {
	var s = text.replace(/\[(.*)\]/g, '').trim();//去除返回数据的[]两端的内容,只保留歌词部分
	return s.replace(/\n/g, '\n<br />');//每行末尾输出html的换行符
}

把format过后的歌词显示在上面用document.createElement()方法创建出来的div中:

DoubanFM.prototype.print_lyrics = function(text) {
	this.lyrics.innerHTML = '<div id="mylrc" style="width: 490px; max-height: 280px; padding:10px; background-color: #9dd6c5; z-index: 42; po	sition: absolute; right: 0; overflow-x: hidden; overflow-y: scroll; display: block;">'+ text +'</div>';
}

最后,用setInterval()方法,每隔一秒执行就获取歌词的方法,实现豆瓣FM歌词的更新和显示:

var  fm = new DoubanFM(true);
window.setInterval(function() { fm.request_geci(); }, 1000);

至此,javascript的工作就完成了。

5.还需要什么?

写一个chrome的插件,你还需要一个manifest.json文件,类似这样:

{
	"name" : "Douban FM 歌词",
	"version" : "1.0",
	"manifest_version" : 2,
	"description" : "Douban FM Lrc",
	
	"page_action" : {
      "default_icon" : "icon.png",
      "default_title" : "Douban FM 歌词"
	},

	"permissions" : ["tabs", "http://douban.fm/", "http://*.geci.me/*"],
	"background" : {"scripts" : ["background.js"]},
	"content_scripts" : [{
		"matches" : ["http://douban.fm/"],
		"js" : ["lyrics.js"],
		"runat" : "document_end"
	}],
	"icons" : {
		"48" : "icon-48.png",
		"128" : "icon-128.png"
	}
}

还需要几个不同size的icon,类似这样:

最后,到chrome的拓展程序(直接在地址栏输入:chrome://extensions/),选择“打包拓展程序”,然后把我们的整个程序的文件夹选中,即可生成一个.crx文件,拖进chrome,即可安装。

:如果你想好好学下如何制作chrome的拓展,可以看这篇文章:http://www.cnblogs.com/walkingp/archive/2011/03/31/2001628.html

6.最后的效果

在我们的拓展程序中,可以看到:

再进入豆瓣FM,听听歌,哦,我看到歌词啦!

7.参考:

1).http://www.v2ex.com/t/54570

2).http://www.douban.com/note/282160723/?type=like

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏osc同步分享

springboot Actuator

springboot Actuator只需要加入依赖即可使用: <dependency> <groupId>org.springframework.bo...

2996
来自专栏Java与Android技术栈

Android App安全防范措施的小结

关闭打印的日志,防止日志中的调试信息被看到。如果在网络框架中使用了日志,那就更加需要关闭了。

1082
来自专栏前端杂货铺

Blob初探

简介   Blob在js中意味着二进制大数据。实现该接口的对象有3个属性,分别是type(MIME),size(byte)和 一个切割方法:slice(在大文件...

3513
来自专栏FreeBuf

如何在CTF中少走弯路(基础篇)

自己并不是专业的赛棍也没有打过很多比赛,这篇文章是自己在CTF中对于杂项这块知识学习的小结,希望可以对初入CTF的同学有所帮助,在CTF中少走弯路从而更快的提升...

1.3K4
来自专栏子勰随笔

iMac使用过程中的简单故障解决

2091
来自专栏小灰灰

Java & PhantomJs 实现html输出图片

Java & PhantomJs 实现html输出图片 借助phantomJs来实现将html网页输出为图片 I. 背景 如何在小程序里面生成一张图,分享到朋...

7178
来自专栏GIS讲堂

web中的树形结构【小结】

最近在做一个项目,是一个b/s架构的,在项目中,用到了树形结构,即如图1所示的结构。

2792
来自专栏小尘哥的专栏

小程序(3):授权登录

判断是否授权,如果没有,则显示授权按钮。注意上面的open-type="getUserInfo",这个会自动调起授权框。看一下js

2434
来自专栏deepcc

linux中nodejs后台运行工具forever

3118
来自专栏大魏分享(微信公众号:david-share)

从PowerVM,KVM到Docker:存储池的配置与调优---第一篇终结(第3子篇)

VIOC 上的 VSCSI 性能调优 在本实验的 VIOC 中,一个磁盘对应 4 条 VSCSI 路径。查看磁盘默认的属性 ; # lsattr -El hdi...

5206

扫码关注云+社区

领取腾讯云代金券