add:新增歌词功能

This commit is contained in:
Yutousama 2022-07-10 23:40:01 +08:00
parent f57325c327
commit fefcfe6c35
4 changed files with 276 additions and 54 deletions

27
web/css/lyricer.min.css vendored Normal file
View File

@ -0,0 +1,27 @@
#lyricer {
font-size: 100%;
font-family: "Microsoft YaHei","Hiragino Sans GB W3",Tahoma,Arial;
text-shadow: 0 0 1px #EEEEEE;
color: #666666;
overflow: hidden;
}
#lyricer ul {
list-style-type: none;
padding: 5px;
margin-left: 50px;
}
#lyricer ul li {
overflow: auto;
}
#lyricer ul li:hover {
color: #428bca;
}
#lyricer .lyricer-current-line {
color: #fff;
text-shadow: 0 0 1px #fff, 0 0 2px #fff, 0 0 3px #fff, 0 0 4px #ff2d95, 0 0 6px #ff2d95, 0 0 8px #ff2d95, 0 0 10px #ff2d95, 0 0 12px #ff2d95;
padding:10px
}

View File

@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>来点Music~</title> <title>来点Music~</title>
<link rel="stylesheet" href="/layui/css/layui.css"> <link rel="stylesheet" href="/layui/css/layui.css">
<link rel="stylesheet" href="/css/lyricer.min.css">
</head> </head>
<body> <body>
<div class="layui-layout layui-layout-admin"> <div class="layui-layout layui-layout-admin">
@ -16,9 +17,9 @@
<div style="margin-left: 2%; margin-top: 2%;"> <div style="margin-left: 2%; margin-top: 2%;">
<div> <div>
<img src="/assets/defaultPlayImg.jpg" id="img" style="height: 200px; width: 200px"/> <img src="/assets/defaultPlayImg.jpg" id="img" style="height: 300px; width: 300px"/>
<div style="display:inline-block;"> <div style="top: 800px;display:inline-block;">
<div id="musicSize">歌单总数:</div> <div id="musicSize">歌单总数:</div>
<div id="playerNowList">播放列表:</div> <div id="playerNowList">播放列表:</div>
<div id="title">标题:</div> <div id="title">标题:</div>
@ -28,6 +29,7 @@
<a class="layui-btn layui-btn-normal" id="download">下载</a> <a class="layui-btn layui-btn-normal" id="download">下载</a>
<a class="layui-btn layui-btn-normal" id="next">下一首</a> <a class="layui-btn layui-btn-normal" id="next">下一首</a>
<a class="layui-btn layui-btn-normal" id="play_share">分享</a> <a class="layui-btn layui-btn-normal" id="play_share">分享</a>
<a class="layui-btn layui-btn-normal" id="showLrc">显示歌词</a>
</div> </div>
<div id="audioWrap"></div> <div id="audioWrap"></div>
@ -44,6 +46,7 @@
<script src="/layui/layui.js"></script> <script src="/layui/layui.js"></script>
<script src="/js/jquery-3.2.1.js"></script> <script src="/js/jquery-3.2.1.js"></script>
<script src="/js/myjs.js"></script> <script src="/js/myjs.js"></script>
<script src="/js/lyricer.min.js"></script>
<link rel="stylesheet" href="/css/AudioPlayer.css"> <link rel="stylesheet" href="/css/AudioPlayer.css">
<script src="/js/AudioPlayer.js"></script> <script src="/js/AudioPlayer.js"></script>
<script id="listTemplet"> <script id="listTemplet">
@ -64,23 +67,24 @@
let isRandom = true; let isRandom = true;
let playIndex = 0; let playIndex = 0;
let playNow = "" let playNow = ""
let share=getParam('share'); let share = getParam('share');
if(share!=null){ if (share != null) {
//$('#playlist').remove() //$('#playlist').remove()
$('#reload').remove() $('#reload').remove()
$('#next').remove() $('#next').remove()
$('#play_share').remove() $('#play_share').remove()
} }
$.get("/nas/music/getlocalhost.do",{share:share}, function (obj) {
$.get("/nas/music/getlocalhost.do", {share: share}, function (obj) {
try { try {
let json = JSON.parse(obj); let json = JSON.parse(obj);
if(json.code===403){ if (json.code === 403) {
layer.msg('您没有权限访问') layer.msg('您没有权限访问')
return; return;
} }
localhost = json.data ; localhost = json.data;
if (localhost === 'http://null:8000' || localhost === ":8000") { if (localhost === 'http://null:8000' || localhost === ":8000") {
localhost = "https://"+window.location.host; localhost = "https://" + window.location.host;
} }
} catch (e) { } catch (e) {
localhost = "" localhost = ""
@ -90,11 +94,11 @@
let table = layui.table; let table = layui.table;
let element = layui.element; let element = layui.element;
let listTable = undefined; let listTable = undefined;
$.post("/public/nas/music/playlist.do",{share:share},function (json) { $.post("/public/nas/music/playlist.do", {share: share}, function (json) {
if(json.code!==0){ if (json.code !== 0) {
return; return;
} }
listTable=table.render({ listTable = table.render({
elem: '#playlist' elem: '#playlist'
, url: json.data //数据接口 , url: json.data //数据接口
, method: 'post' , method: 'post'
@ -115,19 +119,19 @@
, done: function (res, curr, count) { , done: function (res, curr, count) {
musicLib = res.data musicLib = res.data
$('#musicSize').html("歌单总数:" + res.size) $('#musicSize').html("歌单总数:" + res.size)
},error:function (e,data){ }, error: function (e, data) {
} }
}) })
table.on('rowDouble(music)', function (obj) { table.on('rowDouble(music)', function (obj) {
//obj 同上 //obj 同上
if (obj.data.isdir === 1) { if (obj.data.isdir === 1) {
let path=obj.data.md5; let path = obj.data.md5;
if(path===undefined){ if (path === undefined) {
path=obj.data.file; path = obj.data.file;
} }
listTable.reload({ listTable.reload({
where: { where: {
path:path path: path
} }
, page: { , page: {
curr: 1 curr: 1
@ -149,49 +153,49 @@
window.open(localhost + "/nas/music/play.do?token=&random=false&filePath=" + data.md5) window.open(localhost + "/nas/music/play.do?token=&random=false&filePath=" + data.md5)
} }
} else if (obj.event === 'play') { } else if (obj.event === 'play') {
if(data.md5!==undefined){ if (data.md5 !== undefined) {
play(data) play(data)
return; return;
} }
$.ajax({ $.ajax({
type: "POST", type: "POST",
url:localhost + "/nas/music/list.do", url: localhost + "/nas/music/list.do",
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
data:JSON.stringify({type: true, path: data.file}), data: JSON.stringify({type: true, path: data.file}),
dataType: "json", dataType: "json",
success:function (json){ success: function (json) {
try { try {
if (json.code === 0) { if (json.code === 0) {
playIndex = 0; playIndex = 0;
musicLib=[] musicLib = []
for (let datum of json.data) { for (let datum of json.data) {
if(datum.isdir===0){ if (datum.isdir === 0) {
musicLib.push(datum) musicLib.push(datum)
} }
} }
isRandom = false; isRandom = false;
playNext() playNext()
} }
}catch (e){ } catch (e) {
} }
} }
}) })
}else if(obj.event==='share'){ } else if (obj.event === 'share') {
let isDir=false; let isDir = false;
let file=data.md5; let file = data.md5;
if(data.isdir===1){ if (data.isdir === 1) {
isDir=true; isDir = true;
file=data.file; file = data.file;
} }
$.post('/nas/music/share.do',{file:file,isDir:isDir},function (json){ $.post('/nas/music/share.do', {file: file, isDir: isDir}, function (json) {
if(json.code===0){ if (json.code === 0) {
var url="http://"+window.location.host+"/html/body/nas/music.html?share="+json.data.token var url = "http://" + window.location.host + "/html/body/nas/music.html?share=" + json.data.token
layer.prompt({ layer.prompt({
title:"分享链接", title: "分享链接",
value:url value: url
},function (value,index,elem){ }, function (value, index, elem) {
$('.layui-layer-input')[0].select() $('.layui-layer-input')[0].select()
document.execCommand("Copy") document.execCommand("Copy")
layer.close(index); layer.close(index);
@ -203,17 +207,19 @@
element.on('nav(menus)', function (elem) { element.on('nav(menus)', function (elem) {
}); });
}) })
function playShare(){
$.get('/nas/music/playShare.do?share='+share,function (json) { function playShare() {
$.get('/nas/music/playShare.do?share=' + share, function (json) {
isRandom = false; isRandom = false;
playIndex =0; playIndex = 0;
json.data.forEach(function (item) { json.data.forEach(function (item) {
musicLib.push(item) musicLib.push(item)
}) })
play(json.data[0]) play(json.data[0])
}) })
} }
if(share!==null){
if (share !== null) {
playShare() playShare()
} }
}); });
@ -221,6 +227,8 @@
}); });
let player = $.AudioPlayer; let player = $.AudioPlayer;
let showLrc = false;
let lrc = new Lyricer();
player.init({ player.init({
container: '#audioWrap' container: '#audioWrap'
, source: '' , source: ''
@ -237,6 +245,10 @@
}, canplayCallback: function () { }, canplayCallback: function () {
console.log("点击播放") console.log("点击播放")
}, timeupdateCallback: function (time) {
if (showLrc) {
lrc.move(time)
}
} }
}); });
$.ajax({cache: false}) $.ajax({cache: false})
@ -244,7 +256,7 @@
$('#footer').load("/html/footer.html"); $('#footer').load("/html/footer.html");
$('#img').click(function () { $('#img').click(function () {
if(share!==null){ if (share !== null) {
return; return;
} }
isRandom = true; isRandom = true;
@ -256,14 +268,14 @@
$('#next').click(function () { $('#next').click(function () {
playNext() playNext()
}); });
$('#play_share').click(function (){ $('#play_share').click(function () {
$.post('/nas/music/share.do',{file:playNow},function (json){ $.post('/nas/music/share.do', {file: playNow}, function (json) {
if(json.code===0){ if (json.code === 0) {
var url="http://"+window.location.host+"/html/body/nas/music.html?share="+json.data.token let url = "http://" + window.location.host + "/html/body/nas/music.html?share=" + json.data.token
layer.prompt({ layer.prompt({
title:"分享链接", title: "分享链接",
value:url value: url
},function(value,index,elem){ }, function (value, index, elem) {
$('.layui-layer-input')[0].select() $('.layui-layer-input')[0].select()
document.execCommand("Copy") document.execCommand("Copy")
layer.close(index); layer.close(index);
@ -271,12 +283,45 @@
} }
}) })
}) })
$('#showLrc').click(function () {
let html = '<div id="lyricer"></div>';
$.get(localhost + '/nas/music/lrc.do?filePath=' + playNow, function (file) {
layer.open({
title: '歌词列表',
area: ['400px', '600px'],
content: html,
shade: 0,
offset: 'rb',
success: function () {
showLrc = true
if(file===''){
file='[00:00.00]---暂无歌词---'
}
lrc.setLrc(file)
},
end: function () {
showLrc = false;
}
});
})
})
$('#reload').click(function () { $('#reload').click(function () {
$.post(localhost + "/nas/music/reload.do", function (obj) { $.post(localhost + "/nas/music/reload.do", function (obj) {
layer.msg("提交刷新请求成功,几分钟后生效") layer.msg("提交刷新请求成功,几分钟后生效")
}) })
}); });
function updateLrc() {
if (showLrc) {
$.get(localhost + '/nas/music/lrc.do?filePath=' + playNow, function (file) {
if(file===''){
file='[00:00.00]---暂无歌词---'
}
lrc.setLrc(file)
lrc.move(0)
})
}
}
function playNext() { function playNext() {
if (isRandom) { if (isRandom) {
@ -313,8 +358,8 @@
} }
function play(_json) { function play(_json) {
let md5='' let md5 = ''
md5=_json.md5 md5 = _json.md5
playNow = _json.md5 playNow = _json.md5
player.updateSource({ player.updateSource({
source: localhost + "/nas/music/play.do?random=false&filePath=" + md5 source: localhost + "/nas/music/play.do?random=false&filePath=" + md5
@ -344,9 +389,9 @@
title: json.data.title, title: json.data.title,
artist: json.data.artist, artist: json.data.artist,
album: json.data.album, album: json.data.album,
artwork:[ artwork: [
{ {
src: localhost+'/nas/music/web/image.do?fileName='+fileName, src: localhost + '/nas/music/web/image.do?fileName=' + fileName,
type: 'image/png', type: 'image/png',
sizes: '128x128' sizes: '128x128'
} }
@ -358,7 +403,8 @@
}); });
} }
}) })
$('#img').attr("src",localhost+'/nas/music/web/image.do?fileName='+fileName); $('#img').attr("src", localhost + '/nas/music/web/image.do?fileName=' + fileName);
updateLrc()
} }

View File

@ -414,6 +414,7 @@
_this.elements.totalTime.html(_this.formatTime(duration)); _this.elements.totalTime.html(_this.formatTime(duration));
} }
_this.elements.playProgress.width((_this.elements.audioDom.currentTime / _this.elements.audioDom.duration) * $('.progress_bg').width()); _this.elements.playProgress.width((_this.elements.audioDom.currentTime / _this.elements.audioDom.duration) * $('.progress_bg').width());
_this.options.timeupdateCallback(currTime)
} }
// Formatting a timestamp / 格式化时间戳相关 // Formatting a timestamp / 格式化时间戳相关
,formatTime: function(secs, format) { ,formatTime: function(secs, format) {

148
web/js/lyricer.min.js vendored Normal file
View File

@ -0,0 +1,148 @@
(function () {
// The constrcutor can be empty or passed in the lrc string
var Lyricer = function (options) {
this.divID = "lyricer"; // the default html container id
this.currentcss = "lyricer-current-line"; // this css for the line current playing
this.lineidPrefix = "lyricer-line"; // the id prefix for each line
this.showLines = 8; //lines showing before and after;
this.clickable = true;
this.clickEventName = "lyricerclick";
if( options ) {
for( var prop in options ) {
if ( typeof this[prop] != "undefined" && options.hasOwnProperty(prop)) {
this[prop] = options[prop];
}
}
}
};
Lyricer.prototype.setLrc = function(rawLrc) {
this.tags = {};
this.lrc = [];
this.rangeLrc = [];
var tagRegex = /\[([a-z]+):(.*)\].*/;
var lrcAllRegex = /(\[[0-9.:\[\]]*\])+(.*)/;
var timeRegex = /\[([0-9]+):([0-9.]+)\]/;
var timeRegexGim = /\[([0-9]+):([0-9.]+)\]/g;
var rawLrcArray = rawLrc.split(/[\r\n]/);
for (var i = 0; i < rawLrcArray.length; i++) {
// handle tags first
var tag = tagRegex.exec(rawLrcArray[i]);
if ( tag && tag[0] ) {
this.tags[tag[1]] = tag[2];
continue;
}
// handle lrc
var lrc = lrcAllRegex.exec(rawLrcArray[i]);
if ( lrc && lrc[0] ) {
var times = lrc[1].replace(/\]\[/g,"],[").split(",");
for (var j = 0; j < times.length; j++) {
var time = timeRegex.exec(times[j]);
if ( time && time[0] ) {
this.lrc.push( { "starttime": parseInt(time[1],10) * 60 + parseFloat(time[2]), "line": lrc[2].replace(timeRegexGim,'') } );
};
};
};
};
//sort lrc array
this.lrc.sort(function (a,b) {
return a.starttime - b.starttime;
});
// crate the range lrc array
// dummy lines
for (var i = 0; i < this.showLines; i++) {
this.rangeLrc.push( { "starttime": -1, "endtime": 0, "line": "&nbsp;" } );
};
// real data
var starttime = 0;
var line = "";
for (var i = 0; i < this.lrc.length; i++) {
endtime = parseFloat(this.lrc[i].starttime);
this.rangeLrc.push( { "starttime": starttime, "endtime": endtime, "line": line } );
starttime = endtime;
line = this.lrc[i].line;
};
this.rangeLrc.push( { "starttime": starttime, "endtime": 999.99, "line": line } );
// dummy lines
for (var i = 0; i < this.showLines; i++) {
this.rangeLrc.push( { "starttime": -1, "endtime": 0, "line": "&nbsp;" } );
};
this.totalLines = this.rangeLrc.length;
// set html and move to start
setHtml(this);
this.move(0);
};
var setHtml = function(self) {
self.currentLine = 0;
var container = document.getElementById(self.divID);
container.innerHTML = "";
var ul = document.createElement("ul");
container.appendChild(ul);
for (var i = 0; i < self.totalLines; i++) {
var li = document.createElement("li");
li.innerHTML = self.rangeLrc[i].line;
if (!li.innerHTML) {li.innerHTML="&nbsp;"};
li.setAttribute("id", self.lineidPrefix + i);
if (self.clickable) {
li.onclick = lineClicked(self, i);
li.style.cursor = 'pointer';
}
ul.appendChild(li);
};
// hide the later ones
for (var i = self.showLines; i < self.totalLines; i++) {
document.getElementById(self.lineidPrefix + i).style.display = "none";
};
};
var lineClicked = function(self, id) {
return function(){
var detail = {"time": self.rangeLrc[id].starttime};
var e = new CustomEvent(self.clickEventName, {
'detail': detail,
"bubbles": true
});
var elem = document.getElementById(self.lineidPrefix + id);
elem.dispatchEvent(e);
};
};
Lyricer.prototype.move = function(time) {
for (var i = 0; i < this.totalLines; i++) {
if (time >= this.rangeLrc[i].starttime && time < this.rangeLrc[i].endtime) {
this.currentLine = i;
moveToLine(this,this.currentLine);
return;
};
};
};
var moveToLine = function (self, line) {
var startShow = line - self.showLines;
var endShow = line + self.showLines;
for (var i = 0; i < self.totalLines; i++) {
var li = document.getElementById(self.lineidPrefix + i);
if ( i >= startShow && i <= endShow ) {
li.style.display = "block";
} else{
li.style.display = "none";
};
if (i==line) {
li.className = self.currentcss;
} else {
li.className = "";
};
};
};
window.Lyricer = Lyricer; //exposed to global
})();