lrc paser

lrc 歌词解析播放

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

  1. /**
  2. * lrc parser and player
  3. * @version 0.1.0
  4. */
  5.  
  6. var Lrc = (function(){
  7. Date.now = Date.now || (new Date).getTime;
  8. var timeExp = /\[(\d{2,})\:(\d{2})(?:\.(\d{2,3}))?\]/g
  9. , tagsRegMap = {
  10. title: 'ti'
  11. , artist: 'ar'
  12. , album: 'al'
  13. , offset: 'offset'
  14. , by: 'by'
  15. }
  16. ;
  17. /**
  18. * lrc parser
  19. * @param {string} lrc lrc 歌词字符串
  20. * @param {function} [handler]
  21. * @constructor
  22. */
  23. var Parser = function(lrc, handler){
  24. lrc = Parser.trim(lrc);
  25. this.lrc = lrc;//lrc 歌词
  26. this.handler = handler || function(){}
  27. this.tags = {};//ID tags. 标题, 歌手, 专辑
  28. this.lines = [];//详细的歌词信息
  29. this.txts = [];
  30. this.isLrc = Parser.isLrc(lrc);
  31. this.curLine = 0;//
  32. this.state = 0;// 0: stop, 1: playing
  33. var res, line, time, lines = lrc.split(/\n/)
  34. , _last;
  35. for(var tag in tagsRegMap){
  36. res = lrc.match(new RegExp('\\[' + tagsRegMap[tag] + ':([^\\]]*)\\]', 'i'));
  37. this.tags[tag] = res && res[1] || '';
  38. }
  39. timeExp.lastIndex = 0;
  40. for(var i = 0, l = lines.length; i < l; i++){
  41. while(time = timeExp.exec(lines[i])){
  42. _last = timeExp.lastIndex;
  43. line = Parser.trim(lines[i].replace(timeExp, ''));
  44. timeExp.lastIndex = _last;
  45. this.lines.push({
  46. time: time[1] * 60 * 1000 + time[2] * 1000 + (time[3] || 0) * 10
  47. , originLineNum: i
  48. , txt: line
  49. });
  50. this.txts.push(line);
  51. }
  52. }
  53. this.lines.sort(function(a, b){
  54. return a.time - b.time;
  55. });
  56. };
  57. //按照时间点确定歌词行数
  58. function findCurLine(time){
  59. for(var i = 0, l = this.lines.length; i < l; i++){
  60. if(time <= this.lines[i].time){
  61. break;
  62. }
  63. }
  64. return i;
  65. }
  66. function focusLine(i){
  67. this.handler.call(this, this.lines[i].txt, {
  68. originLineNum: this.lines[i].originLineNum
  69. , lineNum: i
  70. })
  71. }
  72. //lrc stream control and output
  73. Parser.prototype = {
  74. //time: 播放起点, skipLast: 是否忽略即将播放歌词的前一条(可能是正在唱的)
  75. play: function(time, skipLast){
  76. var that = this;
  77. time = time || 0;
  78. that._startStamp = Date.now() - time;//相对开始时间戳
  79. that.state = 1;
  80. if(that.isLrc){
  81. that.curLine = findCurLine.call(that, time);
  82. if(!skipLast){
  83. that.curLine && focusLine.call(that, that.curLine - 1);
  84. }
  85. if(that.curLine < that.lines.length){
  86. clearTimeout(that._timer);
  87. that._timer = setTimeout(function loopy(){
  88. focusLine.call(that, that.curLine++);
  89. if(that.lines[that.curLine]){
  90. that._timer = setTimeout(function(){
  91. loopy();
  92. }, that.lines[that.curLine].time - (Date.now() - that._startStamp));
  93. //}, that.lines[that.curLine].time - that.lines[that.curLine--].time);//一些情况可能用得上
  94. }else{
  95. //end
  96. }
  97. }, that.lines[that.curLine].time - time)
  98. }
  99. }
  100. }
  101. , pauseToggle: function(){
  102. var now = Date.now();
  103. if(this.state){
  104. this.stop();
  105. this._pauseStamp = now;
  106. }else{
  107. this.play((this._pauseStamp || now) - (this._startStamp || now), true);
  108. delete this._pauseStamp;
  109. }
  110. }
  111. , seek: function(offset){
  112. this._startStamp -= offset;
  113. this.state && this.play(Date.now() - this._startStamp);//播放时让修改立即生效
  114. }
  115. , stop: function(){
  116. this.state = 0;
  117. clearTimeout(this._timer);
  118. }
  119. };
  120. Parser.trim = function(lrc){
  121. return lrc.replace(/(^\s*|\s*$)/m, '')
  122. };
  123. Parser.isLrc = function(lrc){
  124. return timeExp.test(lrc);
  125. };
  126. return Parser;
  127. })();
  128.  
  129. //node.js module
  130. if(typeof module !== 'undefined' && this.module !== module){
  131. module.exports.Lrc = Lrc;
  132. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址