无聊给博客加了个背景音乐

如题。。顺手写了个管理中心。。这是我第一个用到 json 的玩意儿。。不过别说 json 还是挺方便的。。附源码及安装说明。。

2014-01-31 重要更新,因在编写前一个版本时不熟悉 php 的 cookies 机制,导致 随机播放时避免重复播放 的功能未实现,后准备使用 jquery 将播放列表存到本地 cookies 然后随机调用,又发现 cookies 有大小限制。之后只能放弃了这个功能,现在只使用 cookies 记录当前播放的曲目以及服务器传回的播放列表中总计的曲目数量,以便进行顺序播放。

一、先创建数据表

1
2
3
4
5
6
7
8
9
create table `music_list` (
`id` int not null auto_increment,
`name` text not null default "",
`url` text not null default "",
`singer` text not null default "",
`lrc` int not null default 0,
`lrc_data` text not null default "",
primary key(`id`)
);

表示偷了个小懒全用的 text

二、上传文件至根目录,命名无所谓,必须 .php 结尾,本站的是 music_list.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<?php
session_start();
header("Content-type:text/html;charset=utf-8");
date_default_timezone_set('Asia/Shanghai');
$pass='经 md5 加密后的密码';
$link = @mysql_connect("数据库服务器",'数据库用户名','数据库密码',true);
if(!$link) {
die("Connect Server Failed: " . mysql_error());
}
if(!mysql_select_db('数据库名',$link)) {
die("Select Database Failed: " . mysql_error($link));
}
mysql_query('set names utf8');

function get_music($id=null) {
$return_value=array();
$select_query=mysql_query('select * from `music_list`');
while (($value=mysql_fetch_array($select_query))!==false) {
$return_tmp=array();
$return_tmp['name']=$value['name'];
$return_tmp['url']=$value['url'];
$return_tmp['singer']=$value['singer'];
$return_tmp['id']=$value['id'];
$return_tmp['lrc']=htmlspecialchars($value['lrc']);
$return_tmp['lrc_data']=str_replace(array("\r","\n"),array("","<br />"),$value['lrc_data']);
$return_value[]=$return_tmp;
}
if ($id==null) {
return $return_value;
} else {
$return_values=$return_value[$id];
$return_values['length']=count($return_value);
return $return_values;
}
}

function chkid($id) {
if (!empty($id) && is_numeric($id)) {
$select_query=mysql_query('select * from `music_list` where `id`=\''.$id.'\'');
if (mysql_num_rows($select_query)==0) {
msg('找不到数据');
}
return true;
}
msg('找不到数据');
}
function get_post_data() {
if (!get_magic_quotes_gpc()) {
$return_value=array();
foreach ($_POST as $key=>$value) {
$return_value[$key]=addslashes($value);
}
} else {
$return_value=$_POST;
}
return $return_value;
}
function msg($msg) {
echo '<p>'.$msg.'</p><p><a href="'.$_SERVER['PHP_SELF'].'">返回首页</a></p>';
echo_footer();
exit();
}
function echo_header() {
echo '<html><head><meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"/><title>博客背景音乐管理中心</title></head><body>';
return true;
}
function echo_footer() {
echo '</body></html>';
return true;
}
if ($_GET['action']=='get_music') {
if ($_GET['id']!=='' && is_numeric($_GET['id'])) {
$output=get_music($_GET['id']);
preg_match_all("/^(http:\/\/.*\/)(.*?)$/",$output['url'],$outputtmp);
$output['url']=$outputtmp[1][0].rawurlencode($outputtmp[2][0]);
foreach ($output as $k=>$v) {
$output[$k]=urlencode($v);
}
echo urldecode(json_encode($output));
}
exit();
} elseif ($_GET['action']=='get_music_list') {
echo json_encode(get_music());
exit();
} elseif ($_GET['action']=='login') {
if ($_SESSION['admin']=='admin') {
header('Location: '.$_SERVER['PHP_SELF']);
exit();
}
echo_header();
if ($_POST) {
if (md5($_POST['password'])==$pass) {
$_SESSION['admin']='admin';
header('Location: '.$_SERVER['PHP_SELF']);
exit();
} else {
echo '<p>密码错误</p>';
}
}
echo '<form action="" method="post"><p><label>请输入密码:<input type="password" name="password" /></label></p><p><input type="submit" name="submit" value="提交" /></p></form>';
echo_footer();
} else {
if ($_SESSION['admin']!=='admin') {
header('Location: '.$_SERVER['PHP_SELF'].'?action=login');
exit();
}
echo_header();
if ($_GET['action']=='del') {
chkid($_GET['id']);
if ($_POST) {
$del_query=mysql_query('delete from `music_list` where `id`=\''.$_GET['id'].'\'');
if ($del_query) {
msg('删除成功');
} else {
msg('删除失败');
}
} else {
$select_query=mysql_fetch_array(mysql_query('select * from `music_list` where `id`=\''.$_GET['id'].'\''));
echo '<form action="" method="post"><p>您确定要删除 '.$select_query['name'].' - '.$select_query['singer'].'么?</p><p><input type="submit" name="submit" value="确定" /><a href="'.$_SERVER['PHP_SELF'].'">取消</a></p></form>';
}
} elseif ($_GET['action']=='edit') {
chkid($_GET['id']);
if ($_POST) {
$post_data=get_post_data();
$update_query=mysql_query('update `music_list` set `name`=\''.$post_data['name'].'\', `url`=\''.$post_data['url'].'\', `singer`=\''.$post_data['singer'].'\', `lrc`=\''.$post_data['lrc'].'\', `lrc_data`=\''.$post_data['lrc_data'].'\' where `id`=\''.$_GET['id'].'\'');
if ($update_query) {
msg('数据插入成功');
} else {
msg('数据插入失败');
}
} else {
$select_query=mysql_fetch_array(mysql_query('select * from `music_list` where `id`=\''.$_GET['id'].'\''));
echo '<form action="" method="post"><p><label>歌名:<input type="text" name="name" value="'.$select_query['name'].'" /></p><p><label>歌手:<input type="text" name="singer" value="'.$select_query['singer'].'" /></p><p><label>下载地址:<input type="text" name="url" value="'.$select_query['url'].'" /></p><p>显示 lrc 歌词: <label><input type="radio" name="lrc" value="1" '.($select_query['lrc']?'checked="checked" ':'').'/>是</label>&nbsp;&nbsp;<label><input type="radio" name="lrc" value="0" '.(!$select_query['lrc']?'checked="checked" ':'').'/>否</label></p><p>lrc 歌词(可选):<br /><textarea name="lrc_data">'.htmlspecialchars($select_query['lrc_data']).'</textarea></p><p><input type="submit" name="submit" value="确定" /><a href="'.$_SERVER['PHP_SELF'].'">取消</a></p></form>';
}
} elseif ($_GET['action']=='search') {
$post_data=get_post_data();
echo '<form action="?action=search" method="post"><p><input name="search" type="text" value="'.$post_data['search'].'"/></p><p><input type="submit" value="搜索" /></p></form>';
if ($_POST) {
$search_query=mysql_query('select * from `music_list` where `name` like \'%'.$post_data['search'].'%\' or `singer` like \'%'.$post_data['search'].'%\' or `url` like \'%'.$post_data['search'].'%\'');
if (mysql_num_rows($search_query)>0) {
echo '<ol>';
while (($value=mysql_fetch_array($search_query))!==false) {
echo '<li>'.$value['name'].' - '.$value['singer'].'&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?action=edit&id='.$value['id'].'">编辑</a>&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?action=del&id='.$value['id'].'">删除</a></li>';
}
echo '</ol><a href="'.$_SERVER['PHP_SELF'].'">返回首页</a>';
} else {
echo '<p>无搜索结果</p>';
}
}
} elseif ($_GET['action']=='add') {
if ($_POST) {
$post_data=get_post_data();
$insert_query=mysql_query('insert into `music_list`(`name`,`url`,`singer`,`lrc`,`lrc_data`) values(\''.$post_data['name'].'\',\''.$post_data['url'].'\',\''.$post_data['singer'].'\',\''.$post_data['lrc'].'\',\''.$post_data['lrc_data'].'\')');
if ($insert_query) {
msg('数据插入成功');
} else {
msg('数据插入失败');
}
} else {
echo '<form action="" method="post"><p><label>歌名:<input type="text" name="name" /></p><p><label>歌手:<input type="text" name="singer" /></p><p><label>下载地址:<input type="text" name="url" value="http://" /></p><p>显示 lrc 歌词: <label><input type="radio" name="lrc" value="1" />是</label>&nbsp;&nbsp;<label><input type="radio" name="lrc" value="0" checked="checked" />否</label></p><p>lrc 歌词(可选):<br /><textarea name="lrc_data">'.htmlspecialchars($select_query['lrc_data']).'</textarea></p><p><input type="submit" name="submit" value="确定" /><a href="'.$_SERVER['PHP_SELF'].'">取消</a></p></form>';
}
} else {
echo '<form action="?action=search" method="post"><p><input name="search" type="text" /></p><p><input type="submit" value="搜索" /></p></form>';
$all_list=get_music();
echo '<ol>';
foreach ($all_list as $value) {
echo '<li>'.$value['name'].' - '.$value['singer'].'&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?action=edit&id='.$value['id'].'">编辑</a>&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?action=del&id='.$value['id'].'">删除</a></li>';
}
echo '</ol>';
echo '<a href="'.$_SERVER['PHP_SELF'].'?action=add">添加新曲目</a>';
}
echo_footer();
}
?>

注意不要忘记修改数据库信息和登录密码

三、前台创建小工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
<script type="text/javascript" src="/json2.js"></script>
<script type="text/javascript" src="/jquery.cookie.js"></script>
<style>
/*
* Lyric support by kookxiang(http://ikk.me)
*/
.kk_player { width: 100%; max-height: 40px; }
.kk_lrc { height: 125px; overflow: auto; padding: 0; margin: 0; }
.kk_lrc li { display: block; text-align: center; color: gray; line-height: 20px; margin: 2px 0 3px 0 !important; min-height: 20px; }
.kk_lrc .current { color: black; font-weight: bold; }
.kk_lrc, .kk_lrc * { -webkit-transition-duration: 1s; -moz-transition-duration: 1s; transition-duration: 1s; }
.kk_lrc ::selection { background: transparent; background: rgba(127, 127, 127, 0.1); }
.kk_lrc_box { position: relative; }
.kk_lrc_box:before { content: '.'; overflow: hidden; text-indent: -9999px; width: 100%; height: 30px; z-index: 1; display: block; position: absolute; background: url(http://lab.imjs.work/getlrc/cover.png) repeat-x 0 0; top: 0; pointer-events: none; }
.kk_lrc_box:after { content: '.'; overflow: hidden; text-indent: -9999px; width: 100%; height: 30px; z-index: 1; display: block; position: absolute; background: url(http://lab.imjs.work/getlrc/cover.png) repeat-x 0 100%; bottom: 0; pointer-events: none; }

::-webkit-scrollbar { width: 8px; height: 8px;}
::-webkit-scrollbar-track { -webkit-border-radius: 10px; border-radius: 10px; }
::-webkit-scrollbar-thumb { -webkit-border-radius: 10px; border-radius: 10px; background: rgba(96, 96, 96, 0.8); -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5); }
::-webkit-scrollbar-thumb:window-inactive { background: rgba(96, 96, 96, 0.4); }
</style>
<script>
var ael=false;
var tmp_interval=[0,0];
function get_lrc(name,singer) {
var script = document.createElement('script');
script.setAttribute('src', "http://lab.liujiantao.me/lrc/?name="+encodeURIComponent(name)+"&singer="+encodeURIComponent(singer)+"&callback=con_lrc");
//load javascript
document.getElementsByTagName('head')[0].appendChild(script);
return true;
}

function con_lrc(lrc_data) {
var err_msg={"-1":"服务器没有接收到完整数据","-2":"无法正常获取 xml 文件","-3":"找不到该曲目","-4":"未收录 lrc 歌词","-5":"无法正常获取 lrc 歌词"};
if (lrc_data.status=="error") {
console.error(err_msg[lrc_data.errcode]);
$("#kk_lrc_box").css("display","none");
return false;
}
$("#player_lrc").html("<li></li><li></li><li></li>");
var kk_lrc = load_kk_lrc();
for (j=0;j<lrc_data.result.length;j++) {
var lrcArray=lrc_data.result[j].split("<br />");
var timeKey=new Object();
var strArray=new Array();
var _offset=lrc_data.result[j].match(/\[offset.*?(\d*?)\]/);
_offset=(typeof _offset=="undefined" || _offset===null)?0:_offset[1]/1000;
for (var i = 0,l = lrcArray.length;i < l;i++) {
clause = decodeURIComponent(lrcArray[i]).replace(/\[\d*?:\d*?([\.:]\d*?)?\]/g,'');
timeRegExpArr = decodeURIComponent(lrcArray[i]).match(/\[(\d*?):(\d*?)([\.:](\d*?))?\]/g);
if (timeRegExpArr!=null) {
for (var k = 0,h = timeRegExpArr.length;k < h;k++) { //第一遍循环,JSON存储歌词,数组存储时间
_timeRegExpArr = timeRegExpArr[k].match(/^\[(\d*?):(\d*?)([\.:](\d*?))?\]$/);
min = parseFloat(_timeRegExpArr[1]);
sec = parseFloat(_timeRegExpArr[2]);
msec = parseFloat(typeof _timeRegExpArr[4]=="undefined"?0:_timeRegExpArr[4]);
time=min * 60 + sec + msec/100 - _offset;
time=(time<0)?0:time;
if (!timeKey[time]) {
strArray.push(time);
timeKey[time] = clause + '<br />';
} else {
timeKey[time] += clause + '<br />';
}
}
}
}
strArray.sort(function(a,b) {
return a - b;
});
for (var i = 0,l = strArray.length;i < l;i++) { //第二遍循环,JSON存储时间,数组存储歌词
var tempIndex = strArray[i],
tempClause = timeKey[tempIndex];
kk_lrc.add_lrc(tempIndex,tempClause);
}
}
kk_lrc.init();
ael=true;
return true;
}

function add_lrc(lrc_data) {
con_lrc({'status':'success','errcode':'0','result':[lrc_data.replace("\n","<br />")]});
return true;
}

/*
* Lyric support by kookxiang(http://ikk.me)
*/
function load_kk_lrc(){
var kk_lrc = new Object();
kk_lrc.extra_top = 1;
kk_lrc.current = -1;
kk_lrc.current_obj;
kk_lrc.offset = 0;
kk_lrc.current_start = -1;
kk_lrc.next_update_time = -1;
kk_lrc.showtime = -1;
kk_lrc.lrc_offset = -1;
kk_lrc.lrc_height = -1;
kk_lrc.lrc = [];
kk_lrc.lrcobj = null;
kk_lrc.target = 0;
kk_lrc._target = 0;
kk_lrc.player_obj = document.getElementById('player_player');
kk_lrc.lrc_obj = document.getElementById('player_lrc');

kk_lrc.scroll_lrc = function () {
if(typeof kk_lrc.lrc[kk_lrc.current+2] != "undefined"){
for(id in kk_lrc.lrcobj) kk_lrc.lrcobj[id].className = '';
kk_lrc.lrcobj[kk_lrc.current+3].className = 'current';
}
kk_lrc.current_start = kk_lrc.lrc[kk_lrc.current];
kk_lrc.current++;
kk_lrc.current_obj = kk_lrc.lrcobj[kk_lrc.current+2];
kk_lrc.next_update_time = kk_lrc.lrc[kk_lrc.current];
kk_lrc.showtime = kk_lrc.next_update_time - kk_lrc.current_start;
kk_lrc.lrc_offset = kk_lrc.current_obj.offsetTop;
kk_lrc.lrc_height = kk_lrc.current_obj.offsetHeight;
};
kk_lrc.check_lrc_update = function () {
var curTime = kk_lrc.player_obj.currentTime;
if(curTime >= kk_lrc.next_update_time - 0.2){
kk_lrc.scroll_lrc();
kk_lrc.check_lrc_update();
}
if(typeof kk_lrc.lrc[kk_lrc.current-1] != "undefined"){
kk_lrc.extra_top = (kk_lrc.next_update_time - curTime) / kk_lrc.showtime;
}
kk_lrc.target = Math.round(kk_lrc.lrc_offset - (125 - kk_lrc.lrc_height) / 2);
if(kk_lrc.target < 0) kk_lrc.target = 0;
};
kk_lrc.init = function () {
kk_lrc.add_lrc('999999', '');
kk_lrc.add_lrc('999999', '');
kk_lrc.add_lrc('999999', '');
kk_lrc.current = -1;
kk_lrc.lrcobj = kk_lrc.lrc_obj.getElementsByTagName('li');
kk_lrc.current_obj = kk_lrc.lrcobj[0];
kk_lrc.scroll_lrc();
kk_lrc.check_lrc_update();
if (ael==false) {
kk_lrc.player_obj.addEventListener("seeked" ,function(){
kk_lrc.current = -1;
kk_lrc.scroll_lrc();
kk_lrc.check_lrc_update();
});
kk_lrc.player_obj.addEventListener("durationchange" ,function(){
kk_lrc.current = -1;
kk_lrc.scroll_lrc();
kk_lrc.check_lrc_update();
});
} else {
clearInterval(tmp_interval[0]);
clearInterval(tmp_interval[1]);
}
tmp_interval[0]=setInterval(function(){
if(kk_lrc.player_obj.paused) return;
if(kk_lrc.current_start > kk_lrc.player_obj.currentTime){
kk_lrc.current = -1;
kk_lrc.scroll_lrc();
kk_lrc.check_lrc_update();
}else{
kk_lrc.check_lrc_update();
}
}, 100);
tmp_interval[1]=setInterval(function(){
if(kk_lrc._target == kk_lrc.target) return;
if(Math.abs(kk_lrc.lrc_obj.scrollTop - kk_lrc._target) > kk_lrc.lrc_height){
kk_lrc._target = kk_lrc.lrc_obj.scrollTop;
}
if(kk_lrc.player_obj.paused){
kk_lrc._target = kk_lrc.fixFloat(kk_lrc._target * 0.8 + kk_lrc.target * 0.2);
}else{
kk_lrc._target = kk_lrc.fixFloat(kk_lrc._target * 0.98 + kk_lrc.target * 0.02);
}
kk_lrc.lrc_obj.scrollTop = kk_lrc._target;
}, 5);
};
kk_lrc.add_lrc = function (time, lrc) {
kk_lrc.lrc.push(parseFloat(time) + kk_lrc.offset);
var lrc_line = document.createElement("li");
lrc_line.innerHTML = lrc;
kk_lrc.lrc_obj.appendChild(lrc_line);
};
kk_lrc.get_lrc = function (num) {
if(typeof kk_lrc.lrc[num] != "undefined"){
return kk_lrc.lrc[num][1];
}else{
return '';
}
}
kk_lrc.setoffset = function (num) {
kk_lrc.offset = num / 1000;
}
kk_lrc.fixFloat = function (num) {
return Math.ceil(num * 10) / 10;
}
return kk_lrc;
}
function get_music() {
$("#audio_player").html('<p>正在加载播放器,请稍候</p>');
if ("undefined"==typeof $.cookie("music_list") || $.cookie("music_list")==null) {
var music_id=0;
} else {
var cookie_music=JSON.parse($.cookie("music_list"));
if ((cookie_music['id']+1)==cookie_music['length']) {
var music_id=0;
} else {
var music_id=cookie_music['id']+1;
}
}
var music_id=("undefined"!==typeof arguments[0])?arguments[0]:music_id;
$.ajax({
type: 'get',
url: '/music_list.php',
dataType: 'json',
timeout: 3000,
data: {"action":"get_music","id":music_id},
success: function(music) {
$("#audio_player").html('<p>当前<span id="audio_player_status">正在缓冲准备播放</span>的是:<br /><span id="music_name">' + music['name'] + ' - ' + music['singer'] + '</span>&nbsp;<a href="####" id="reload_audio_player">换一首</a></p>');
if (typeof $("#audio_list").html()!=='undefined') $("#audio_list").html($("#audio_list").html().replace(/<\/?span.*?>/g,'').replace($("#music_name").html(),'<span style="font-weight: bold; color: red">'+$("#music_name").html()+'</span>'));
if ($(document).width()>=768 && (new Date().getHours()>=8 && new Date().getHours()<23)) {
$("#player_player").attr("autoplay","autoplay");
}
$("#player_player").attr("src",music['url']);
if (music['lrc']=="0") {
$("#kk_lrc_box").css("display","none");
} else {
$("#kk_lrc_box").css("display","block");
if (music['lrc_data']!=="") {
add_lrc(music['lrc_data']);
} else {
get_lrc(music['name'],music['singer']);
}
}
$("#audio_player2").html('<!-- id=' + music_id + ' mysql_id=' + music['id'] + ' -->' + (($(document).width()<768 || new Date().getHours()<8 || new Date().getHours()>=23)?"<p><small>已为您关闭了自动播放</small></p>":""));
$.cookie("music_list",'{"id":'+ music_id + ',"length":' + music['length'] + '}',{expires: 7, path: '/'});
},
error: function(XMLHttpRequest,status) {
if (status == 'timeout') {
$("#audio_player").html('<p>请求超时,<a href="####" id="reload_audio_player">重新加载</a></p>');
return true;
} else {
$("#audio_player").html('<p>无法请求播放数据</p>');
return true;
}
}
});
}
function change_audio_player_status() {
$("#audio_player_status").html("正在播放")
}
$(function() {
get_music();
$("#audio_player").on('click', "#reload_audio_player", function() {
get_music();
});
});
</script>
<span id="audio_player"></span>
<audio src="" controls="controls" onended="get_music()" onplaying="change_audio_player_status()" style="width: 100%" id="player_player">您的浏览器不支持 HTML5</audio>
<span id="audio_player2"></span>
<div class="kk_lrc_box" id="kk_lrc_box"><ul id="player_lrc" class="kk_lrc">

</ul></div>

四、将下面这个文件解压上传至根目录,里面分别是 jQuery 的 JSON 插件和 Cookies 插件
jq.zip

效果如本页所示。有段时间没写 php 了,如果有什么 bug 或者建议请评论,谢谢