소스 검색

播放列表:
audio标签增加sourceList播放列表的功能,src属性用逗号分隔多个播放地址,一个播放完后自动切换下一首。暂不支持source标签
增加上一曲下一曲功能
HACK修复歌词变快的问题
引入了第三方插件计算歌词同步
优化歌词同步显示的逻辑

ecd\tbw_1357250783514014 4 년 전
부모
커밋
9cf59a14df
7개의 변경된 파일717개의 추가작업 그리고 143개의 파일을 삭제
  1. 1 1
      book.toml
  2. 5 1
      src/chanting/evening_chanting_A.md
  3. 1 1
      src/chanting/evening_chanting_B.md
  4. 1 1
      src/chanting/evening_chanting_C.md
  5. 1 1
      src/chanting/evening_chanting_D.md
  6. 2 2
      theme/mycss/lrc.css
  7. 706 136
      theme/myjs/lrc.js

+ 1 - 1
book.toml

@@ -9,7 +9,7 @@ title = "教理部口袋书学习手册范例"
 [output.html]
 additional-js = ["theme/myjs/mermaid.min.js", "theme/myjs/mermaid-init.js","theme/myjs/jquery-1.12.3.min.js","theme/myjs/lrc.js","theme/myjs/nosleep.js","theme/myjs/social-share.min.js","theme/myplugin/layer/layer.js"]
 mathjax-support = true
-additional-css = ["theme/fonts/tai-tham-kh-new-v3.ttf","theme/mycss/font.css","theme/mycss/lrc.css","theme/mycss/share.min.css","theme/fonts/iconfont.ttf","theme/fonts/iconfont.woff","theme/myplugin/layer/theme/default/layer.css","theme/myplugin/layer/theme/default/icon.png"] 
+additional-css = ["theme/fonts/tai-tham-kh-new-v3.ttf","theme/mycss/font.css","theme/mycss/lrc.css","theme/mycss/share.min.css","theme/fonts/iconfont.ttf","theme/fonts/iconfont.woff","theme/myplugin/layer/theme/default/layer.css","theme/myplugin/layer/theme/default/icon.png","theme/大金塔寺晚课(宝经)祜巴罕听_0321.mp3"] 
 
 [output.html.fold]
 enable = true

+ 5 - 1
src/chanting/evening_chanting_A.md

@@ -2,13 +2,17 @@
 
 <div id="lyriccontainer" class="def-lyric" style="background-image:url('https://djt-res.fzcl.org.cn/jly/img/buddha_city.jpg');background-size:cover;--full-font-size: 4vmin;--default-font-size: 1.6rem;">
 	<audio id="audio" controls style="width: 100%;">
-	  <source src="https://djt-res.fzcl.org.cn/jly/audio/大金塔寺晚课(宝经)祜巴罕听_0321.mp3" type="audio/mpeg">
+	  <sourceList src="https://djt-res.fzcl.org.cn/jly/audio/大金塔寺晚课(宝经)祜巴罕听_0321.mp3" >
+	  <!--sourceList src="https://djt-res.fzcl.org.cn/jly/audio/大金塔寺晚课(宝经)祜巴罕听_0321.mp3,
+	  https://djt-res.fzcl.org.cn/jly/audio/dhammacakka_0218.mp3" -->
 	</audio>
 	<div id="line-tools">
 		<input type="checkbox" id='lyricSleep'>禁止熄屏</input>
 		<button id='lyricFullscreen'>全屏播放</button>
 		<button id='lyricBigger'>加大字体</button>
 		<button id='lyricSmaller'>缩小字体</button>
+		<button id='playNext' title="没有了">下一首</button>
+		<button id='playPrev' title="没有了">上一首</button>
 	</div>
 	<div id="line-last"><span></span><span></span><span></span></div>
 	<div id="line-current" class='active'><span></span><span></span><span></span></div>

+ 1 - 1
src/chanting/evening_chanting_B.md

@@ -1,7 +1,7 @@
 # **晚 课**<br>**大金塔课诵本**<br>**傣调试用版**
 <div id="lyriccontainer" class="def-lyric" style="background-image:url('https://djt-res.fzcl.org.cn/jly/img/buddha_city.jpg');background-size:cover;--full-font-size: 4vmin;--default-font-size: 1.6rem;">
 	<audio id="audio" controls style="width: 100%;">
-	  <source src="https://djt-res.fzcl.org.cn/jly/audio/大金塔晚课(傣)1031.mp3" type="audio/mpeg">
+	  <sourceList src="https://djt-res.fzcl.org.cn/jly/audio/大金塔晚课(傣)1031.mp3" type="audio/mpeg">
 	</audio>
 	<div id="line-tools">
 		<input type="checkbox" id='lyricSleep'>禁止熄屏</input>

+ 1 - 1
src/chanting/evening_chanting_C.md

@@ -2,7 +2,7 @@
 
 <div id="lyriccontainer" class="def-lyric" style="background-image:url('https://djt-res.fzcl.org.cn/jly/img/5_bhikkhu.jpg');background-size:cover;--full-font-size: 4vmin;--default-font-size: 1.6rem;">
 	<audio id="audio" controls style="width: 100%;">
-	  <source src="https://djt-res.fzcl.org.cn/jly/audio/dhammacakka_0218.mp3" type="audio/mpeg">
+	  <sourceList src="https://djt-res.fzcl.org.cn/jly/audio/dhammacakka_0218.mp3" type="audio/mpeg">
 	</audio>
 	<div id="line-tools">
 		<input type="checkbox" id='lyricSleep'>禁止熄屏</input>

+ 1 - 1
src/chanting/evening_chanting_D.md

@@ -3,7 +3,7 @@
 # dhammacakkappavattanasuttaṃ
 
 <audio controls>
-  <source src="https://djt-res.fzcl.org.cn/jly/audio/dhammacakka_0218.mp3" type="audio/mpeg">
+  <sourceList src="https://djt-res.fzcl.org.cn/jly/audio/dhammacakka_0218.mp3" type="audio/mpeg">
 </audio>
 
 Evaṃ me sutaṃ- ekaṃ samayaṃ bhagavā bārāṇasiyaṃ viharati isipatane migadāye. 

+ 2 - 2
theme/mycss/lrc.css

@@ -76,9 +76,9 @@
 	padding-left: 2em;
 }
 
-#lyricFullscreen,#lyricNoslep,#lyricBigger,#lyricSmaller {
+#line-tools button {
 	height: 2em;
-	width: 8em;
+	width: 6em;
 	color: #fff;
 	background-color: #57a957;
 	border-color: #57a957;

+ 706 - 136
theme/myjs/lrc.js

@@ -1,57 +1,603 @@
-/* ===================================================
- * jqlyric.js v0.1
- * shawnk@qq.com
-
- * 使用方法
- * var $container=$('#lyriccontainer'); //用于显示歌词的容器对象,样式自己定义
- * $container.jqlyric({
- *      lyric:'\
-            [ti:存在] \
-            [ar:汪峰] \
-            [al:存在] \
-            [by:Love] \
-            [00:00.00]汪峰 - 存在 \
-            [00:00.68]多少人走着却困在原地 \
-            [00:07.93]多少人活着却如同死去',   // 歌词字符串,标准lrc文件格式
- *      speed:1000,                  // 歌词滚动间隔 (毫秒)
- *      getPosition:function(){      // 获取当前播放位置的函数(返回秒数), 请定义外部函数,不指定本参数则默认从调用插件开始自动播放
- *          return position;
- *      }
- * });
-
- * ===================================================
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================================================== */
-
-(function($) {
-	var gtime = 0;
-	var lyric_listener;
-	$.fn.jqlyric = function(options) {
-		var opts = $.extend({},
-		$.fn.jqlyric.defaults, options);
-
-		return this.each(function() {
-			var o = $.meta ? $.extend({},
-			opts, $this.data()) : opts;
-			var $this = $(this);
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["Lyric"] = factory();
+	else
+		root["Lyric"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+/******/
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// identity function for calling harmony imports with the correct context
+/******/ 	__webpack_require__.i = function(value) { return value; };
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 20);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
 
+// Thank's IE8 for his funny defineProperty
+module.exports = !__webpack_require__(3)(function(){
+  return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7;
+});
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports) {
+
+module.exports = function(it){
+  return typeof it === 'object' ? it !== null : typeof it === 'function';
+};
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports) {
+
+var core = module.exports = {version: '2.4.0'};
+if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports) {
+
+module.exports = function(exec){
+  try {
+    return !!exec();
+  } catch(e){
+    return true;
+  }
+};
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports) {
+
+// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
+var global = module.exports = typeof window != 'undefined' && window.Math == Math
+  ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
+if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var anObject       = __webpack_require__(11)
+  , IE8_DOM_DEFINE = __webpack_require__(16)
+  , toPrimitive    = __webpack_require__(18)
+  , dP             = Object.defineProperty;
+
+exports.f = __webpack_require__(0) ? Object.defineProperty : function defineProperty(O, P, Attributes){
+  anObject(O);
+  P = toPrimitive(P, true);
+  anObject(Attributes);
+  if(IE8_DOM_DEFINE)try {
+    return dP(O, P, Attributes);
+  } catch(e){ /* empty */ }
+  if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!');
+  if('value' in Attributes)O[P] = Attributes.value;
+  return O;
+};
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+
+exports.default = function (instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+};
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+
+var _defineProperty = __webpack_require__(8);
+
+var _defineProperty2 = _interopRequireDefault(_defineProperty);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = function () {
+  function defineProperties(target, props) {
+    for (var i = 0; i < props.length; i++) {
+      var descriptor = props[i];
+      descriptor.enumerable = descriptor.enumerable || false;
+      descriptor.configurable = true;
+      if ("value" in descriptor) descriptor.writable = true;
+      (0, _defineProperty2.default)(target, descriptor.key, descriptor);
+    }
+  }
+
+  return function (Constructor, protoProps, staticProps) {
+    if (protoProps) defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) defineProperties(Constructor, staticProps);
+    return Constructor;
+  };
+}();
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports, __webpack_require__) {
+
+module.exports = { "default": __webpack_require__(9), __esModule: true };
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+__webpack_require__(19);
+var $Object = __webpack_require__(2).Object;
+module.exports = function defineProperty(it, key, desc){
+  return $Object.defineProperty(it, key, desc);
+};
+
+/***/ }),
+/* 10 */
+/***/ (function(module, exports) {
+
+module.exports = function(it){
+  if(typeof it != 'function')throw TypeError(it + ' is not a function!');
+  return it;
+};
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var isObject = __webpack_require__(1);
+module.exports = function(it){
+  if(!isObject(it))throw TypeError(it + ' is not an object!');
+  return it;
+};
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports, __webpack_require__) {
+
+// optional / simple context binding
+var aFunction = __webpack_require__(10);
+module.exports = function(fn, that, length){
+  aFunction(fn);
+  if(that === undefined)return fn;
+  switch(length){
+    case 1: return function(a){
+      return fn.call(that, a);
+    };
+    case 2: return function(a, b){
+      return fn.call(that, a, b);
+    };
+    case 3: return function(a, b, c){
+      return fn.call(that, a, b, c);
+    };
+  }
+  return function(/* ...args */){
+    return fn.apply(that, arguments);
+  };
+};
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var isObject = __webpack_require__(1)
+  , document = __webpack_require__(4).document
+  // in old IE typeof document.createElement is 'object'
+  , is = isObject(document) && isObject(document.createElement);
+module.exports = function(it){
+  return is ? document.createElement(it) : {};
+};
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var global    = __webpack_require__(4)
+  , core      = __webpack_require__(2)
+  , ctx       = __webpack_require__(12)
+  , hide      = __webpack_require__(15)
+  , PROTOTYPE = 'prototype';
+
+var $export = function(type, name, source){
+  var IS_FORCED = type & $export.F
+    , IS_GLOBAL = type & $export.G
+    , IS_STATIC = type & $export.S
+    , IS_PROTO  = type & $export.P
+    , IS_BIND   = type & $export.B
+    , IS_WRAP   = type & $export.W
+    , exports   = IS_GLOBAL ? core : core[name] || (core[name] = {})
+    , expProto  = exports[PROTOTYPE]
+    , target    = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]
+    , key, own, out;
+  if(IS_GLOBAL)source = name;
+  for(key in source){
+    // contains in native
+    own = !IS_FORCED && target && target[key] !== undefined;
+    if(own && key in exports)continue;
+    // export native or passed
+    out = own ? target[key] : source[key];
+    // prevent global pollution for namespaces
+    exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
+    // bind timers to global for call from export context
+    : IS_BIND && own ? ctx(out, global)
+    // wrap global constructors for prevent change them in library
+    : IS_WRAP && target[key] == out ? (function(C){
+      var F = function(a, b, c){
+        if(this instanceof C){
+          switch(arguments.length){
+            case 0: return new C;
+            case 1: return new C(a);
+            case 2: return new C(a, b);
+          } return new C(a, b, c);
+        } return C.apply(this, arguments);
+      };
+      F[PROTOTYPE] = C[PROTOTYPE];
+      return F;
+    // make static versions for prototype methods
+    })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
+    // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%
+    if(IS_PROTO){
+      (exports.virtual || (exports.virtual = {}))[key] = out;
+      // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%
+      if(type & $export.R && expProto && !expProto[key])hide(expProto, key, out);
+    }
+  }
+};
+// type bitmap
+$export.F = 1;   // forced
+$export.G = 2;   // global
+$export.S = 4;   // static
+$export.P = 8;   // proto
+$export.B = 16;  // bind
+$export.W = 32;  // wrap
+$export.U = 64;  // safe
+$export.R = 128; // real proto method for `library` 
+module.exports = $export;
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var dP         = __webpack_require__(5)
+  , createDesc = __webpack_require__(17);
+module.exports = __webpack_require__(0) ? function(object, key, value){
+  return dP.f(object, key, createDesc(1, value));
+} : function(object, key, value){
+  object[key] = value;
+  return object;
+};
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
+
+module.exports = !__webpack_require__(0) && !__webpack_require__(3)(function(){
+  return Object.defineProperty(__webpack_require__(13)('div'), 'a', {get: function(){ return 7; }}).a != 7;
+});
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports) {
+
+module.exports = function(bitmap, value){
+  return {
+    enumerable  : !(bitmap & 1),
+    configurable: !(bitmap & 2),
+    writable    : !(bitmap & 4),
+    value       : value
+  };
+};
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+// 7.1.1 ToPrimitive(input [, PreferredType])
+var isObject = __webpack_require__(1);
+// instead of the ES6 spec version, we didn't implement @@toPrimitive case
+// and the second argument - flag - preferred type is a string
+module.exports = function(it, S){
+  if(!isObject(it))return it;
+  var fn, val;
+  if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
+  if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val;
+  if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
+  throw TypeError("Can't convert object to primitive value");
+};
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var $export = __webpack_require__(14);
+// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes)
+$export($export.S + $export.F * !__webpack_require__(0), 'Object', {defineProperty: __webpack_require__(5).f});
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) {
+  if (true) {
+    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [module, exports, __webpack_require__(6), __webpack_require__(7)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
+				__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
+				(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
+				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+  } else if (typeof exports !== "undefined") {
+    factory(module, exports, require('babel-runtime/helpers/classCallCheck'), require('babel-runtime/helpers/createClass'));
+  } else {
+    var mod = {
+      exports: {}
+    };
+    factory(mod, mod.exports, global.classCallCheck, global.createClass);
+    global.index = mod.exports;
+  }
+})(this, function (module, exports, _classCallCheck2, _createClass2) {
+  'use strict';
+
+  Object.defineProperty(exports, "__esModule", {
+    value: true
+  });
+
+  var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+  var _createClass3 = _interopRequireDefault(_createClass2);
+
+  function _interopRequireDefault(obj) {
+    return obj && obj.__esModule ? obj : {
+      default: obj
+    };
+  }
+
+  var timeExp = /\[(\d{2,}):(\d{2})(?:\.(\d{2,3}))?]/g;
+
+  var STATE_PAUSE = 0;
+  var STATE_PLAYING = 1;
+
+  var tagRegMap = {
+    title: 'ti',
+    artist: 'ar',
+    album: 'al',
+    offset: 'offset',
+    by: 'by'
+  };
+
+  function noop() {}
+
+  var Lyric = function () {
+    function Lyric(lrc) {
+      var hanlder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop;
+      (0, _classCallCheck3.default)(this, Lyric);
+
+      this.lrc = lrc;
+      this.tags = {};
+      this.lines = [];
+      this.handler = hanlder;
+      this.state = STATE_PAUSE;
+      this.curLine = 0;
+
+      this._init();
+    }
+
+    (0, _createClass3.default)(Lyric, [{
+      key: '_init',
+      value: function _init() {
+        this._initTag();
+
+        this._initLines();
+      }
+    }, {
+      key: '_initTag',
+      value: function _initTag() {
+        for (var tag in tagRegMap) {
+          var matches = this.lrc.match(new RegExp('\\[' + tagRegMap[tag] + ':([^\\]]*)]', 'i'));
+          this.tags[tag] = matches && matches[1] || '';
+        }
+      }
+    }, {
+      key: '_initLines',
+      value: function _initLines() {
+        var lines = this.lrc.split('\n');
+        for (var i = 0; i < lines.length; i++) {
+          var line = lines[i];
+          var result = timeExp.exec(line);
+          if (result) {
+            var txt = line.replace(timeExp, '').trim();
+            if (txt) {
+              this.lines.push({
+                time: result[1] * 60 * 1000 + result[2] * 1000 + (result[3] || 0) * 10,
+                txt: txt
+              });
+            }
+          }
+        }
+
+        this.lines.sort(function (a, b) {
+          return a.time - b.time;
+        });
+      }
+    }, {
+      key: '_findCurNum',
+      value: function _findCurNum(time) {
+        for (var i = 0; i < this.lines.length; i++) {
+          if (time <= this.lines[i].time) {
+            return i;
+          }
+        }
+        return this.lines.length - 1;
+      }
+    }, {
+      key: '_callHandler',
+      value: function _callHandler(i) {
+        if (i < 0) {
+          return;
+        }
+        this.handler({
+          txt: this.lines[i].txt,
+          lineNum: i
+        });
+      }
+    }, {
+      key: '_playRest',
+      value: function _playRest() {
+        var _this = this;
+
+        var line = this.lines[this.curNum];
+        var delay = line.time - (+new Date() - this.startStamp);
+
+        this.timer = setTimeout(function () {
+          _this._callHandler(_this.curNum++);
+          if (_this.curNum < _this.lines.length && _this.state === STATE_PLAYING) {
+            _this._playRest();
+          }
+        }, delay);
+      }
+    }, {
+      key: 'play',
+      value: function play() {
+        var startTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
+        var skipLast = arguments[1];
+
+        if (!this.lines.length) {
+          return;
+        }
+        this.state = STATE_PLAYING;
+
+        this.curNum = this._findCurNum(startTime);
+        this.startStamp = +new Date() - startTime;
+
+        if (!skipLast) {
+          this._callHandler(this.curNum - 1);
+        }
+
+        if (this.curNum < this.lines.length) {
+          clearTimeout(this.timer);
+          this._playRest();
+        }
+      }
+    }, {
+      key: 'togglePlay',
+      value: function togglePlay() {
+        var now = +new Date();
+        if (this.state === STATE_PLAYING) {
+          this.stop();
+          this.pauseStamp = now;
+        } else {
+          this.state = STATE_PLAYING;
+          this.play((this.pauseStamp || now) - (this.startStamp || now), true);
+          this.pauseStamp = 0;
+        }
+      }
+    }, {
+      key: 'stop',
+      value: function stop() {
+        this.state = STATE_PAUSE;
+        clearTimeout(this.timer);
+      }
+    }, {
+      key: 'seek',
+      value: function seek(offset) {
+        this.play(offset);
+      }
+    }]);
+    return Lyric;
+  }();
+
+  exports.default = Lyric;
+  module.exports = exports['default'];
+});
+
+/***/ })
+/******/ ]);
+});
+
+$(function() {
+	var audio = document.getElementById("audio");
+	if (!audio) {
+		return;
+	}
+	var lyricObj;
+	var initLrc=function (lyric) {
 			var arrLyric = new Array(); //放存汉字的歌词
 			var arrTime = new Array(); //存放时间
 			var currentLine = 0; //当前活动的歌词行号
 			// 开始解析歌词
 			//将歌词解析成数组
-			var arrly = o.lyric.split('\n'); 
+			var arrly = lyric.split('\n'); 
 			for (var i = 0; i < arrly.length; i++) {
 				var str = arrly[i];
 				str = str.substring(str.indexOf("[") + 1, str.indexOf("]"));
@@ -85,77 +631,62 @@
 					}
 				}
 			}
-			// 所有歌词封装成歌词对象
-			var arrLyricObj = new Array();
-			for (var k = 0; k < arrTime.length; k++) {
-				var lrcContent = arrLyric[k];
-				var len = lrcContent.replace(/(^s*)|(s*$)/g, "").length; 
-				if (!lrcContent || len == 0) {
-					continue;
-				}
-				var timeStart = arrTime[k];
-				var timeEnd = k < arrTime.length - 1 ? arrTime[k + 1] - 0.01 : 99999999999999;
-				if (timeEnd < 0) {
-					continue;
-				}
 
-				var lrc = {
-					timeStart: timeStart,
-					timeEnd: timeEnd,
-					lrcContent: lrcContent
-				};
-				arrLyricObj.push(lrc);
-			}
 			// 显示歌词
 			var displayLine = function(lineID,num){
-				var lc = arrLyricObj[num].lrcContent.split("<br/>");
+				var lc = arrLyric[num].split("<br/>");
 				$(lineID+" span:eq(0)").text(lc[0]);
 				if (lc.length > 1) {
 					$(lineID+" span:eq(1)").text(lc[1]);
+				}else{
+					$(lineID+" span:eq(1)").text("");
 				}
 				if (lc.length > 2) {
 					$(lineID+" span:eq(2)").text(lc[2]);
+				}else{
+					$(lineID+" span:eq(2)").text("");
 				}
-				$(lineID).attr("currentLine", num);
 			};
 			
-			clearTimeout(lyric_listener);
-			var timeFun = function() { // 定时检查当前播放进度,作出滚动动作
-				var pos = o.getPosition();
-				for (var k = 0; k < arrLyricObj.length; k++) {
-					if (pos >= arrLyricObj[k].timeStart && pos <= arrLyricObj[k].timeEnd) {
-						if ($("#line-current").attr("currentLine") != k) {
-							if (k > 0) {
-								displayLine("#line-last",k-1);
-							}
-							if (k < arrTime.length - 1) {
-								displayLine("#line-next",k+1);
-							}
-
-							displayLine("#line-current",k);
-
-							break;
-						}
-					}
+			var handler = function ({lineNum, txt}){
+				if(currentLine==lineNum){
+					return;
 				}
-				lyric_listener = setTimeout(timeFun, o.speed);
+				
+				if (lineNum > 0) {
+					displayLine("#line-last",lineNum-1);
+				}
+				if (lineNum < arrTime.length - 1) {
+					displayLine("#line-next",lineNum+1);
+				}
+				
+				displayLine("#line-current",lineNum);
+				currentLine = lineNum;
+				//console.log(arrLyricObj[lineNum].lrcContent);
+			 }
+			 if(lyricObj){
+				 lyricObj.stop();
+			 }
+			lyricObj = new Lyric(lyric, handler);
+			var bugInterval=undefined;
+			audio.onplay=function(){
+				if(bugInterval){return;}
+				bugInterval=setInterval(function(){
+					audio.currentTime=audio.currentTime-0.001;
+					console.log("自动倒退:"+audio.currentTime);
+				},5*60*1000);				
+			}
+			audio.onpause=function(){				
+				clearInterval(bugInterval);
+				bugInterval=undefined;
+			}
+			audio.ontimeupdate=function(){
+				lyricObj.seek(audio.currentTime * 1000)
 			};
-			lyric_listener = setTimeout(timeFun, o.speed);
-		});
-	};
-
-	$.fn.jqlyric.defaults = {
-		lyric: '[00:00.00]未找到歌词',
-		// 歌词字符串 (lrc格式)
-		speed: 500,
-		// 歌词进度一首歌间隔(毫秒)
-		getPosition: function() { // 获取播放器当前播放位置
-			gtime += 0.5;
-			return gtime;
+			
 		}
-	}
 
-	function toSeconds(t) { //把形如:01:25的时间转化成秒;
+	var toSeconds=function (t) { //把形如:01:25的时间转化成秒;
 		var m = t.substring(0, t.indexOf(":"));
 		var s = t.substring(t.indexOf(":") + 1);
 		s = parseFloat(s.replace(/\b(0+)/gi, ""));
@@ -164,16 +695,58 @@
 		if (isNaN(totalt)) return 0;
 		return totalt;
 	}
-
-})(jQuery);
-
-$(function() {
-	var audio = document.getElementById("audio");
-	if (!audio) {
-		return;
-	}
-	var fun_getPosition = function() {
-		return audio.currentTime;
+	var $container = $('#lyriccontainer');
+	var loadLrc=function(){
+		var url = audio.src;
+		var urlArr = url.split('?');
+		var k = urlArr[0],
+		appU = k.split('/');
+		var srcFileExt = appU[appU.length - 1].split('.')[1];
+		url = url.replace("." + srcFileExt, ".lrc");
+		var url = "https://djt-res.fzcl.org.cn/getJSON.php?callback=?&url=" + url;
+		
+		$.getJSON(url,
+		function(data) {
+			var lrcContent = data.data; 
+			if (!lrcContent || lrcContent == "") {
+				return;
+			}
+			initLrc(lrcContent);
+		});
+	};
+	var list=new Array();
+	var playIndex=0;
+	var doPlay=function(){
+		if(playIndex>list.length-1||playIndex<0){
+			return;
+		}
+		audio.src = list[playIndex];
+		loadLrc();
+		if(playIndex<list.length-1){
+			$("#playNext").prop("title",list[playIndex+1]);
+			audio.onended=playEndedHandler;
+		}else{
+			$("#playNext").prop("title","没有了");
+		}
+		if(playIndex>0){
+			$("#playPrev").prop("title",list[playIndex-1]);
+		}else{
+			$("#playPrev").prop("title","没有了");
+		}
+		audio.play();
+	};
+	if ($("#audio sourceList").length>0) {
+		list=$("#audio sourceList").attr("src").split(",");
+		audio.src=list[0];
+		loadLrc();
+		if(list.length>1){
+			var playEndedHandler=function (){
+				playIndex++;
+				doPlay();
+			};
+			$("#playNext").prop("title",list[1]);
+			audio.onended=playEndedHandler;
+		}
 	}
 	audio.onerror = audio.onabort = audio.onstalled = function(m) {
 		layer.msg('播放器发生错误:'+m.type,{
@@ -184,14 +757,7 @@ $(function() {
 		  time:8000
 		});
 	};
-	var url = audio.currentSrc;
-	var urlArr = url.split('?');
-	var k = urlArr[0],
-	appU = k.split('/');
-	var srcFileExt = appU[appU.length - 1].split('.')[1];
-	url = url.replace("." + srcFileExt, ".lrc");
-	var url = "https://djt-res.fzcl.org.cn/getJSON.php?callback=?&url=" + url;
-	var $container = $('#lyriccontainer');
+	
 	var noSleep = new NoSleep();
 	var enableNoSleep = false;
 	var isFullScreen = false;
@@ -269,20 +835,7 @@ $(function() {
           $container[0].addEventListener(item, () => fullScreenChangeListener());
     });
 
-	$.getJSON(url,
-	function(data) {
-		var lrcContent = data.data; 
-		if (!lrcContent || lrcContent == "") {
-			return;
-		}
-		//用于显示歌词的容器对象,样式自己定义
-		$container.jqlyric({
-			lyric: lrcContent,
-			// 歌词字符串,标准lrc文件格式
-			getPosition: fun_getPosition,
-			speed:50
-		});
-	});
+	
 
 	var btn_lyricBigger = document.getElementById("lyricBigger");
 	//调节字体大小
@@ -328,7 +881,6 @@ $(function() {
 		},
 		false);
 	}
-	
 	var btn_lyricSmaller = document.getElementById("lyricSmaller");
 	if (btn_lyricSmaller) {
 		btn_lyricSmaller.addEventListener('click',
@@ -337,6 +889,24 @@ $(function() {
 		},
 		false);
 	}
+	var btn_playNext = document.getElementById("playNext");
+	if (btn_playNext) {
+		btn_playNext.addEventListener('click',
+		function() {
+			playIndex++;
+			doPlay();
+		},
+		false);
+	}
+	var btn_playPrev = document.getElementById("playPrev");
+	if (btn_playPrev) {
+		btn_playPrev.addEventListener('click',
+		function() {
+			playIndex--;
+			doPlay();
+		},
+		false);
+	}
 	var chk_lyricSleep = document.getElementById("lyricSleep");
 	if (chk_lyricSleep) {
 		chk_lyricSleep.addEventListener('change',