🏠

Greasy Fork is available in English.

lrc paser

lrc 歌词解析播放

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.org/scripts/7807/34341/lrc%20paser.js

提问、发表评价,或者 举报这个脚本
/**
* lrc parser and player
* @version 0.1.0
*/
var Lrc = (function(){
Date.now = Date.now || (new Date).getTime;
var timeExp = /\[(\d{2,})\:(\d{2})(?:\.(\d{2,3}))?\]/g
, tagsRegMap = {
title: 'ti'
, artist: 'ar'
, album: 'al'
, offset: 'offset'
, by: 'by'
}
;
/**
* lrc parser
* @param {string} lrc lrc 歌词字符串
* @param {function} [handler]
* @constructor
*/
var Parser = function(lrc, handler){
lrc = Parser.trim(lrc);
this.lrc = lrc;//lrc 歌词
this.handler = handler || function(){}
this.tags = {};//ID tags. 标题, 歌手, 专辑
this.lines = [];//详细的歌词信息
this.txts = [];
this.isLrc = Parser.isLrc(lrc);
this.curLine = 0;//
this.state = 0;// 0: stop, 1: playing
var res, line, time, lines = lrc.split(/\n/)
, _last;
for(var tag in tagsRegMap){
res = lrc.match(new RegExp('\\[' + tagsRegMap[tag] + ':([^\\]]*)\\]', 'i'));
this.tags[tag] = res && res[1] || '';
}
timeExp.lastIndex = 0;
for(var i = 0, l = lines.length; i < l; i++){
while(time = timeExp.exec(lines[i])){
_last = timeExp.lastIndex;
line = Parser.trim(lines[i].replace(timeExp, ''));
timeExp.lastIndex = _last;
this.lines.push({
time: time[1] * 60 * 1000 + time[2] * 1000 + (time[3] || 0) * 10
, originLineNum: i
, txt: line
});
this.txts.push(line);
}
}
this.lines.sort(function(a, b){
return a.time - b.time;
});
};
//按照时间点确定歌词行数
function findCurLine(time){
for(var i = 0, l = this.lines.length; i < l; i++){
if(time <= this.lines[i].time){
break;
}
}
return i;
}
function focusLine(i){
this.handler.call(this, this.lines[i].txt, {
originLineNum: this.lines[i].originLineNum
, lineNum: i
})
}
//lrc stream control and output
Parser.prototype = {
//time: 播放起点, skipLast: 是否忽略即将播放歌词的前一条(可能是正在唱的)
play: function(time, skipLast){
var that = this;
time = time || 0;
that._startStamp = Date.now() - time;//相对开始时间戳
that.state = 1;
if(that.isLrc){
that.curLine = findCurLine.call(that, time);
if(!skipLast){
that.curLine && focusLine.call(that, that.curLine - 1);
}
if(that.curLine < that.lines.length){
clearTimeout(that._timer);
that._timer = setTimeout(function loopy(){
focusLine.call(that, that.curLine++);
if(that.lines[that.curLine]){
that._timer = setTimeout(function(){
loopy();
}, that.lines[that.curLine].time - (Date.now() - that._startStamp));
//}, that.lines[that.curLine].time - that.lines[that.curLine--].time);//一些情况可能用得上
}else{
//end
}
}, that.lines[that.curLine].time - time)
}
}
}
, pauseToggle: function(){
var now = Date.now();
if(this.state){
this.stop();
this._pauseStamp = now;
}else{
this.play((this._pauseStamp || now) - (this._startStamp || now), true);
delete this._pauseStamp;
}
}
, seek: function(offset){
this._startStamp -= offset;
this.state && this.play(Date.now() - this._startStamp);//播放时让修改立即生效
}
, stop: function(){
this.state = 0;
clearTimeout(this._timer);
}
};
Parser.trim = function(lrc){
return lrc.replace(/(^\s*|\s*$)/m, '')
};
Parser.isLrc = function(lrc){
return timeExp.test(lrc);
};
return Parser;
})();
//node.js module
if(typeof module !== 'undefined' && this.module !== module){
module.exports.Lrc = Lrc;
}