v2.31 更新
pull/13/head
mengkunsoft 2017-09-13 17:21:07 +08:00
parent 1ff73fb3b9
commit da9b0388d1
9 changed files with 116 additions and 75 deletions

View File

@ -1,4 +1,4 @@
MKOnlineMusicPlayer v2.3 MKOnlineMusicPlayer v2.31
======== ========
MKOnlineMusicPlayer 是一款开源的基于 `Meting` 的在线音乐播放器。具有音乐搜索、播放、下载、歌词同步显示、个人网易云音乐播放列表同步等功能。 MKOnlineMusicPlayer 是一款开源的基于 `Meting` 的在线音乐播放器。具有音乐搜索、播放、下载、歌词同步显示、个人网易云音乐播放列表同步等功能。
@ -41,6 +41,7 @@ php 5.4+, curl_exec, file_get_contents, json_decode, openssl_encrypt
### 待解决的问题 ### 待解决的问题
----- -----
- 高音质音乐下载功能 - 高音质音乐下载功能
- IOS 歌曲播放问题
- 歌曲播放模式切换(单曲循环、随机播放、列表循环)功能 - 歌曲播放模式切换(单曲循环、随机播放、列表循环)功能
### 打赏 ### 打赏
@ -52,6 +53,13 @@ php 5.4+, curl_exec, file_get_contents, json_decode, openssl_encrypt
### 更新日志 ### 更新日志
----- -----
#### v2.31 `2017/9/13`
- 优化下载功能,支持直接弹出下载
- 下载或分享无版权音乐时给出提示
- 再次降低移动端背景特效内存占用
- 修复某些手机浏览器列表页右侧菜单按钮下移 BUG
- 升级 Meting 至最新版本
#### v2.3 `2017/9/9` #### v2.3 `2017/9/9`
- 全面支持网易云、QQ、虾米、酷狗、百度音乐源切换 - 全面支持网易云、QQ、虾米、酷狗、百度音乐源切换
- 移动端歌曲列表支持直接分享、下载歌曲 - 移动端歌曲列表支持直接分享、下载歌曲

View File

@ -1,9 +1,9 @@
@charset "utf-8"; @charset "utf-8";
/************************************************** /**************************************************
* MKOnlinePlayer v2.2 * MKOnlinePlayer v2.31
* *
* mengkun(http://mkblog.cn) * mengkun(http://mkblog.cn)
* 2017-3-26 * 2017-9-13
*************************************************/ *************************************************/
/* 小于 900px 采用这个样式 */ /* 小于 900px 采用这个样式 */
@ -92,6 +92,10 @@
background-position: -30px -365px; background-position: -30px -365px;
right: 0; right: 0;
top: 50%; top: 50%;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
transform: translateY(-50%); transform: translateY(-50%);
z-index: 2; z-index: 2;
cursor: pointer; cursor: pointer;

View File

@ -4,6 +4,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
<meta name="renderer" content="webkit">
<meta http-equiv="Cache-Control" content="no-siteapp">
<!-- 强制移动设备以app模式打开页面(即在移动设备下全屏,仅支持部分浏览器) --> <!-- 强制移动设备以app模式打开页面(即在移动设备下全屏,仅支持部分浏览器) -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
@ -141,7 +143,10 @@
<script src="js/background-blur.min.js"></script> <script src="js/background-blur.min.js"></script>
<!-- 站长统计代码 --> <!-- 站长统计代码 -->
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan style='display: none' id='cnzz_stat_icon_1261525999'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s95.cnzz.com/z_stat.php%3Fid%3D1261525999' type='text/javascript'%3E%3C/script%3E"));</script> <span style="display: none">
<!-- 各类统计代码都放在这里…… -->
<script src="https://s95.cnzz.com/z_stat.php?id=1261525999&web_id=1261525999" language="JavaScript"></script>
</span>
</body> </body>
</html> </html>

View File

@ -1,8 +1,8 @@
/************************************************** /**************************************************
* MKOnlinePlayer v2.2 * MKOnlinePlayer v2.31
* Ajax 后台数据交互请求模块 * Ajax 后台数据交互请求模块
* 编写mengkun(http://mkblog.cn) * 编写mengkun(http://mkblog.cn)
* 时间2017-3-26 * 时间2017-9-13
*************************************************/ *************************************************/
// ajax加载搜索结果 // ajax加载搜索结果

View File

@ -1,8 +1,8 @@
/************************************************** /**************************************************
* MKOnlinePlayer v2.2 * MKOnlinePlayer v2.31
* 封装函数及UI交互模块 * 封装函数及UI交互模块
* 编写mengkun(http://mkblog.cn) * 编写mengkun(http://mkblog.cn)
* 时间2017-3-26 * 时间2017-9-12
*************************************************/ *************************************************/
// 判断是否是移动设备 // 判断是否是移动设备
var isMobile = { var isMobile = {
@ -370,19 +370,50 @@ function thisShare(obj) {
// 下载歌曲 // 下载歌曲
// 参数:包含歌曲信息的数组 // 参数:包含歌曲信息的数组
function download(music) { function download(music) {
$('<a id="tmp-down" href="'+ music.url +'" download="' +music.name + ' - ' + music.artist + '.mp3" target="_blank">1</a>').appendTo('body').click(); if(music.url == 'err' || music.url == "" || music.url == null) {
$('#tmp-down').click(); layer.msg('这首歌不支持下载');
$('#tmp-down').remove(); // 移除 return;
window.open(music.url); }
openDownloadDialog(music.url, music.name + ' - ' + music.artist);
}
/**
* 通用的打开下载对话框方法没有测试过具体兼容性
* @param url 下载地址也可以是一个blob对象必选
* @param saveName 保存文件名可选
* http://www.cnblogs.com/liuxianan/p/js-download.html
*/
function openDownloadDialog(url, saveName)
{
if(typeof url == 'object' && url instanceof Blob)
{
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // HTML5新增的属性指定保存文件名可以不要后缀注意file:///模式下不会生效
var event;
if(window.MouseEvent) event = new MouseEvent('click');
else
{
event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event);
} }
// 获取外链的ajax回调函数 // 获取外链的ajax回调函数
// 参数:包含音乐信息的数组 // 参数:包含音乐信息的数组
function ajaxShare(music) { function ajaxShare(music) {
if(music.url == 'err' || music.url == "" || music.url == null) {
layer.msg('这首歌不支持外链获取');
return;
}
var tmpHtml = '<p>' + music.artist + ' - ' + music.name + ' 的外链地址为:</p>' + var tmpHtml = '<p>' + music.artist + ' - ' + music.name + ' 的外链地址为:</p>' +
'<input class="share-url" onmouseover="this.focus();this.select()" value="' + music.url + '">'; '<input class="share-url" onmouseover="this.focus();this.select()" value="' + music.url + '">';
if(music.source != "netease" && music.source != "xiami") { if(music.source != "netease") {
tmpHtml += '<p class="share-tips">* 当前音乐源歌曲链接有效期较短,不建议作外链使用</p>' tmpHtml += '<p class="share-tips">* 当前音乐源歌曲链接有效期较短,不建议作外链使用</p>'
} }
@ -410,14 +441,18 @@ function changeCover(music) {
$(".sheet-item[data-no='1'] .sheet-cover").attr('src', img); // 改变正在播放列表的图像 $(".sheet-item[data-no='1'] .sheet-cover").attr('src', img); // 改变正在播放列表的图像
if(img == "err") img = ""; // 背景为空 if(img == "err") img = ""; // 背景为空
if((mkPlayer.coverbg === true && !rem.isMobile) || (mkPlayer.mcoverbg === true && rem.isMobile)) { // 开启了封面背景
if(mkPlayer.mcoverbg === true && rem.isMobile && img) // 移动端封面
{
$("#music-cover").load(function(){
$("#mobile-blur").css('background-image', 'url("' + img + '")');
});
}
else if(mkPlayer.coverbg === true && !rem.isMobile) // PC端封面
{
$("#music-cover").load(function(){ $("#music-cover").load(function(){
if(animate) { // 渐变动画也已完成 if(animate) { // 渐变动画也已完成
if(rem.isMobile) { // 移动端禁用动画,节约内存
$("#mobile-blur").css('background-image', 'url("' + img + '")');
} else {
$("#blur-img").backgroundBlur(img); // 替换图像并淡出 $("#blur-img").backgroundBlur(img); // 替换图像并淡出
}
$("#blur-img").animate({opacity:"1"}, 2000); // 背景更换特效 $("#blur-img").animate({opacity:"1"}, 2000); // 背景更换特效
} else { } else {
imgload = true; // 告诉下面的函数,图片已准备好 imgload = true; // 告诉下面的函数,图片已准备好
@ -428,12 +463,7 @@ function changeCover(music) {
// 渐变动画 // 渐变动画
$("#blur-img").animate({opacity: "0.2"}, 1000, function(){ $("#blur-img").animate({opacity: "0.2"}, 1000, function(){
if(imgload) { // 如果图片已经加载好了 if(imgload) { // 如果图片已经加载好了
if(rem.isMobile) {
$("#mobile-blur").css('background-image', 'url("' + img + '")');
} else {
$("#blur-img").backgroundBlur(img); // 替换图像并淡出 $("#blur-img").backgroundBlur(img); // 替换图像并淡出
}
$("#blur-img").animate({opacity:"1"}, 2000); // 背景更换特效 $("#blur-img").animate({opacity:"1"}, 2000); // 背景更换特效
} else { } else {
animate = true; // 等待图像加载完 animate = true; // 等待图像加载完
@ -475,8 +505,8 @@ function loadList(list) {
addItem(i + 1, tmpMusic.name, tmpMusic.artist, tmpMusic.album); addItem(i + 1, tmpMusic.name, tmpMusic.artist, tmpMusic.album);
// 只有网易云和虾米音乐源的歌曲进行链接记录(其它音乐链接均有有效期限制,重新显示列表时清空处理) // 只有网易云的歌曲进行链接记录(其它音乐链接均有有效期限制,重新显示列表时清空处理)
if(tmpMusic.source != "netease" && tmpMusic.source != "xiami") tmpMusic.url = ""; if(tmpMusic.source != "netease") tmpMusic.url = "";
} }
if(i == 0) { if(i == 0) {
addListbar("nodata"); // 列表中没有数据 addListbar("nodata"); // 列表中没有数据

View File

@ -1,8 +1,8 @@
/************************************************** /**************************************************
* MKOnlinePlayer v2.2 * MKOnlinePlayer v2.31
* 歌词解析及滚动模块 * 歌词解析及滚动模块
* 编写mengkun(http://mkblog.cn) * 编写mengkun(http://mkblog.cn)
* 时间2017-3-26 * 时间2017-9-13
*************************************************/ *************************************************/
var lyricArea = $("#lyric"); // 歌词显示容器 var lyricArea = $("#lyric"); // 歌词显示容器

View File

@ -77,7 +77,7 @@ var musicList = [
pic_id: "2946691234868155", // 封面ID pic_id: "2946691234868155", // 封面ID
lyric_id: "436514312", // 歌词ID lyric_id: "436514312", // 歌词ID
pic: "https://p3.music.126.net/34YW1QtKxJ_3YnX9ZzKhzw==/2946691234868155.jpg", // 专辑图片 pic: "https://p3.music.126.net/34YW1QtKxJ_3YnX9ZzKhzw==/2946691234868155.jpg", // 专辑图片
url: "https://p2.music.126.net/7o5D4dA6271VktgawcbZFA==/18665309393829604.mp3" // mp3链接 url: "https://p2.music.126.net/7o5D4dA6271VktgawcbZFA==/18665309393829604.mp3" // mp3链接(此项建议不填,因为各大音乐平台的外链有效期都较短……)
}, },
// 下面演示插入各个平台的音乐。。。 // 下面演示插入各个平台的音乐。。。
{ {
@ -114,7 +114,7 @@ var musicList = [
pic_id: "81175", pic_id: "81175",
lyric_id: "81175", lyric_id: "81175",
pic: "https://pic.xiami.net/images/album/img58/1258/66271400572139.jpg@300h_300w_100q_1c.jpg", pic: "https://pic.xiami.net/images/album/img58/1258/66271400572139.jpg@300h_300w_100q_1c.jpg",
url: "https://om6.alicdn.com/258/1258/6627/81175_60243588_h.mp3?auth_key=31b6f2878c1e29b769cbb6b63d2da843-1505098800-0-null" url: "" // 虾米的外链有效期较短,插入时 url [必须]设置空值,播放时再临时抓取
}, },
{ {
id: "2a24dea6c74884195fe5b9732fd95ca8", id: "2a24dea6c74884195fe5b9732fd95ca8",

View File

@ -1,8 +1,8 @@
/************************************************** /**************************************************
* MKOnlinePlayer v2.3 * MKOnlinePlayer v2.31
* 播放器主功能模块 * 播放器主功能模块
* 编写mengkun(http://mkblog.cn) * 编写mengkun(http://mkblog.cn)
* 时间2017-9-3 * 时间2017-9-12
*************************************************/ *************************************************/
// 播放器功能配置 // 播放器功能配置
var mkPlayer = { var mkPlayer = {
@ -16,7 +16,7 @@ var mkPlayer = {
dotshine: true, // 是否开启播放进度条的小点闪动效果[不支持IE](true/false) *开启后会有些卡 dotshine: true, // 是否开启播放进度条的小点闪动效果[不支持IE](true/false) *开启后会有些卡
mdotshine: false, // 是否开启[移动端]播放进度条的小点闪动效果[不支持IE](true/false) mdotshine: false, // 是否开启[移动端]播放进度条的小点闪动效果[不支持IE](true/false)
volume: 0.6, // 默认音量值(0~1之间) volume: 0.6, // 默认音量值(0~1之间)
version: "v2.3", // 播放器当前版本号(仅供调试) version: "v2.31", // 播放器当前版本号(仅供调试)
debug: false // 是否开启调试模式(true/false) debug: false // 是否开启调试模式(true/false)
}; };
@ -202,6 +202,7 @@ function initAudio() {
rem.audio[0].addEventListener('error', audioErr); // 播放器错误处理 rem.audio[0].addEventListener('error', audioErr); // 播放器错误处理
} }
// 播放音乐 // 播放音乐
// 参数:要播放的音乐数组 // 参数:要播放的音乐数组
function play(music) { function play(music) {

View File

@ -3,7 +3,7 @@
* Meting music framework * Meting music framework
* https://i-meto.com * https://i-meto.com
* https://github.com/metowolf/Meting * https://github.com/metowolf/Meting
* Version 1.3.8 * Version 1.3.9
* *
* Copyright 2017, METO Sheel <i@i-meto.com> * Copyright 2017, METO Sheel <i@i-meto.com>
* Released under the MIT license * Released under the MIT license
@ -153,15 +153,15 @@ class Meting
'method' => 'GET', 'method' => 'GET',
'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp', 'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp',
'body' => array( 'body' => array(
'format' => 'json',
'p' => $page, 'p' => $page,
'n' => $limit, 'n' => $limit,
'w' => $keyword, 'w' => $keyword,
'aggr' => 1, 'aggr' => 1,
'lossless' => 1, 'lossless' => 1,
'cr' => 1, 'cr' => 1,
'platform' => 'yqq', 'new_json' => 1,
), ),
'decode' => 'jsonp2json',
'format' => 'data#song#list', 'format' => 'data#song#list',
); );
break; break;
@ -321,12 +321,14 @@ class Meting
case 'tencent': case 'tencent':
$API=array( $API=array(
'method' => 'GET', 'method' => 'GET',
'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg', 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg',
'body' => array( 'body' => array(
'albummid' => $id, 'albummid' => $id,
'platform' => 'yqq', 'platform' => 'mac',
'format' => 'json',
'newsong' => 1,
), ),
'format' => 'data#list', 'format' => 'data#getSongInfo',
); );
break; break;
case 'xiami': case 'xiami':
@ -406,7 +408,8 @@ class Meting
'begin' => 0, 'begin' => 0,
'num' => $limit, 'num' => $limit,
'order' => 'listen', 'order' => 'listen',
'platform' => 'yqq', 'platform' => 'mac',
'newsong' => 1,
), ),
'format' => 'data#list', 'format' => 'data#list',
); );
@ -484,15 +487,14 @@ class Meting
case 'tencent': case 'tencent':
$API=array( $API=array(
'method' => 'GET', 'method' => 'GET',
'url' => 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg', 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg',
'body' => array( 'body' => array(
'disstid' => $id, 'id' => $id,
'utf8' => 1, 'format' => 'json',
'type' => 1, 'newsong' => 1,
'platform' => 'yqq', 'platform' => 'jqspaframe.json',
), ),
'decode' => 'jsonp2json', 'format' => 'data#cdlist#0#songlist',
'format' => 'cdlist#0#songlist',
); );
break; break;
case 'xiami': case 'xiami':
@ -653,7 +655,7 @@ class Meting
'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg', 'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg',
'body' => array( 'body' => array(
'songmid' => $id, 'songmid' => $id,
'g_tk' => 5381, 'g_tk' => '5381',
), ),
'decode' => 'tencent_lyric', 'decode' => 'tencent_lyric',
); );
@ -751,7 +753,7 @@ class Meting
), ),
'tencent'=>array( 'tencent'=>array(
'referer' => 'https://y.qq.com/portal/player.html', 'referer' => 'https://y.qq.com/portal/player.html',
'cookie' => 'pgv_pvi=3832878080; pgv_si=s4066364416; pgv_pvid=3938077488; yplayer_open=1; qqmusic_fromtag=66; ts_last=y.qq.com/portal/player.html; ts_uid=5141451452; player_exist=1; yq_index=1', 'cookie' => 'pgv_pvi=22038528; pgv_si=s3156287488; pgv_pvid=5535248600; yplayer_open=1; ts_last=y.qq.com/portal/player.html; ts_uid=4847550686; yq_index=0; qqmusic_fromtag=66; player_exist=1',
'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
), ),
'xiami'=>array( 'xiami'=>array(
@ -794,13 +796,6 @@ class Meting
); );
return $API; return $API;
} }
private function jsonp2json($jsonp)
{
if ($jsonp[0] !== '[' && $jsonp[0] !== '{') {
$jsonp = substr($jsonp, strpos($jsonp, '('));
}
return trim($jsonp, '();');
}
private function tencent_singlesong($result) private function tencent_singlesong($result)
{ {
$result=json_decode($result, 1); $result=json_decode($result, 1);
@ -834,11 +829,9 @@ class Meting
{ {
$data=json_decode($result, 1); $data=json_decode($result, 1);
if (isset($data['data'][0]['uf']['url'])) { if (isset($data['data'][0]['uf']['url'])) {
$url=array( $data['data'][0]['url']=$data['data'][0]['uf']['url'];
'url' => $data['data'][0]['uf']['url'], }
'br' =>$data['data'][0]['uf']['br']/1000, if (isset($data['data'][0]['url'])) {
);
} elseif (isset($data['data'][0]['url'])) {
$url=array( $url=array(
'url' => $data['data'][0]['url'], 'url' => $data['data'][0]['url'],
'br' => $data['data'][0]['br']/1000, 'br' => $data['data'][0]['br']/1000,
@ -861,8 +854,8 @@ class Meting
'body' => array( 'body' => array(
'json' => 3, 'json' => 3,
'guid' => $GUID, 'guid' => $GUID,
'format' => 'json',
), ),
'decode' => 'jsonp2json',
); );
$KEY=json_decode($this->curl($API), 1); $KEY=json_decode($this->curl($API), 1);
$KEY=$KEY['key']; $KEY=$KEY['key'];
@ -1002,7 +995,7 @@ class Meting
} }
private function tencent_lyric($result) private function tencent_lyric($result)
{ {
$result=$this->jsonp2json($result); $result=substr($result,18,-1);
if (!$this->_FORMAT) { if (!$this->_FORMAT) {
return $result; return $result;
} }
@ -1098,13 +1091,13 @@ class Meting
$data=$data['musicData']; $data=$data['musicData'];
} }
$result=array( $result=array(
'id' => $data['songmid'], 'id' => $data['mid'],
'name' => $data['songname'], 'name' => $data['name'],
'artist' => array(), 'artist' => array(),
'album' => isset($data['albumname'])?$data['albumname']:$data['album']['name'], 'album' => trim($data['album']['title']),
'pic_id' => $data['albummid'], 'pic_id' => $data['album']['mid'],
'url_id' => $data['songmid'], 'url_id' => $data['mid'],
'lyric_id' => $data['songmid'], 'lyric_id' => $data['mid'],
'source' => 'tencent', 'source' => 'tencent',
); );
foreach ($data['singer'] as $vo) { foreach ($data['singer'] as $vo) {