hexo-theme-shokax 0.0.2-alpha2 → 0.0.2-alpha3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. package/CODE_OF_CONDUCT.md +128 -0
  2. package/CONTRIBUTING.md +56 -0
  3. package/LICENSE +28 -28
  4. package/LICENSE-shoka +21 -21
  5. package/README.md +46 -55
  6. package/README_en.MD +25 -0
  7. package/_config.yml +392 -355
  8. package/_images.yml +100 -100
  9. package/languages/README.md +19 -19
  10. package/languages/default.yml +1 -1
  11. package/languages/en.yml +151 -151
  12. package/languages/ja.yml +146 -146
  13. package/languages/zh-CN.yml +154 -154
  14. package/languages/zh-HK.yml +146 -146
  15. package/languages/zh-TW.yml +146 -146
  16. package/layout/_alternate/atom.ejs +30 -30
  17. package/layout/_alternate/json.ejs +16 -16
  18. package/layout/_alternate/rss.ejs +34 -34
  19. package/layout/_mixin/breadcrumb.pug +33 -33
  20. package/layout/_mixin/card.pug +37 -37
  21. package/layout/_mixin/comment.pug +66 -12
  22. package/layout/_mixin/postmeta.pug +30 -30
  23. package/layout/_mixin/segment.pug +32 -32
  24. package/layout/_mixin/sidebar.pug +36 -36
  25. package/layout/_mixin/widgets.pug +31 -29
  26. package/layout/_partials/footer.pug +40 -40
  27. package/layout/_partials/head/head.pug +51 -58
  28. package/layout/_partials/head/head_com.pug +17 -17
  29. package/layout/_partials/head/pwa.pug +18 -18
  30. package/layout/_partials/header.pug +18 -18
  31. package/layout/_partials/layout.pug +143 -153
  32. package/layout/_partials/loading.pug +13 -13
  33. package/layout/_partials/pagination.pug +4 -4
  34. package/layout/_partials/post/copyright.pug +20 -20
  35. package/layout/_partials/post/footer.pug +14 -14
  36. package/layout/_partials/post/nav.pug +13 -13
  37. package/layout/_partials/post/post.pug +28 -28
  38. package/layout/_partials/post/reward.pug +18 -18
  39. package/layout/_partials/sidebar/menu.pug +37 -37
  40. package/layout/_partials/sidebar/overview.pug +41 -42
  41. package/layout/_partials/third-party/baidu-analytics.pug +11 -11
  42. package/layout/_partials/third-party/clarity.pug +8 -8
  43. package/layout/archive.pug +118 -118
  44. package/layout/category.pug +63 -63
  45. package/layout/index.pug +33 -33
  46. package/layout/page.pug +56 -56
  47. package/layout/post.pug +35 -35
  48. package/layout/tag.pug +43 -43
  49. package/package.json +35 -35
  50. package/scripts/filters/locals.js +59 -59
  51. package/scripts/filters/post.js +23 -23
  52. package/scripts/generaters/archive.js +141 -141
  53. package/scripts/generaters/config.js +43 -43
  54. package/scripts/generaters/images.js +26 -26
  55. package/scripts/generaters/index.js +110 -110
  56. package/scripts/generaters/pages.js +19 -19
  57. package/scripts/generaters/script.js +89 -89
  58. package/scripts/helpers/asset.js +183 -237
  59. package/scripts/helpers/engine.js +190 -190
  60. package/scripts/helpers/list_categories.js +140 -140
  61. package/scripts/helpers/symbols_count_time.js +76 -76
  62. package/scripts/plugin/index.js +6 -6
  63. package/scripts/plugin/lib/injects-point.js +19 -19
  64. package/scripts/plugin/lib/injects.js +89 -88
  65. package/scripts/tags/links.js +86 -86
  66. package/scripts/tags/media.js +19 -19
  67. package/source/assets/algolia_logo.svg +9 -9
  68. package/source/assets/logo.svg +16 -16
  69. package/source/css/_colors.styl +207 -207
  70. package/source/css/_common/components/components.styl +6 -6
  71. package/source/css/_common/components/highlight/highlight.styl +353 -353
  72. package/source/css/_common/components/highlight/operation.styl +21 -21
  73. package/source/css/_common/components/pages/collapse.styl +119 -119
  74. package/source/css/_common/components/pages/home.styl +385 -385
  75. package/source/css/_common/components/pages/pages.styl +56 -56
  76. package/source/css/_common/components/pages/tag-cloud.styl +12 -12
  77. package/source/css/_common/components/post/breadcrumb.styl +39 -39
  78. package/source/css/_common/components/post/copyright.styl +41 -41
  79. package/source/css/_common/components/post/expand.styl +264 -264
  80. package/source/css/_common/components/post/footer.styl +11 -11
  81. package/source/css/_common/components/post/header.styl +79 -79
  82. package/source/css/_common/components/post/nav.styl +63 -63
  83. package/source/css/_common/components/post/post.styl +29 -29
  84. package/source/css/_common/components/post/reward.styl +50 -50
  85. package/source/css/_common/components/post/rtl.styl +12 -12
  86. package/source/css/_common/components/post/tags.styl +39 -39
  87. package/source/css/_common/components/tags/collapse.styl +72 -72
  88. package/source/css/_common/components/tags/container.styl +49 -49
  89. package/source/css/_common/components/tags/label.styl +12 -12
  90. package/source/css/_common/components/tags/links.styl +77 -77
  91. package/source/css/_common/components/tags/list.styl +131 -131
  92. package/source/css/_common/components/tags/note.styl +70 -70
  93. package/source/css/_common/components/tags/player.styl +361 -361
  94. package/source/css/_common/components/tags/quiz.styl +200 -200
  95. package/source/css/_common/components/tags/tabs.styl +83 -83
  96. package/source/css/_common/components/tags/tags.styl +9 -9
  97. package/source/css/_common/components/third-party/loading.styl +222 -222
  98. package/source/css/_common/components/third-party/mermaid/class.styl +90 -90
  99. package/source/css/_common/components/third-party/mermaid/flowchart.styl +72 -72
  100. package/source/css/_common/components/third-party/mermaid/gantt.styl +251 -251
  101. package/source/css/_common/components/third-party/mermaid/git.styl +7 -7
  102. package/source/css/_common/components/third-party/mermaid/mermaid.styl +37 -37
  103. package/source/css/_common/components/third-party/mermaid/pie.styl +9 -9
  104. package/source/css/_common/components/third-party/mermaid/sequence.styl +95 -95
  105. package/source/css/_common/components/third-party/mermaid/state.styl +130 -130
  106. package/source/css/_common/components/third-party/pace.styl +18 -18
  107. package/source/css/_common/components/third-party/search.styl +167 -167
  108. package/source/css/_common/components/third-party/theme.styl +151 -151
  109. package/source/css/_common/components/third-party/third-party.styl +22 -22
  110. package/source/css/_common/components/third-party/valine.styl +548 -548
  111. package/source/css/_common/components/third-party/widgets.styl +57 -57
  112. package/source/css/_common/outline/footer/footer.styl +69 -69
  113. package/source/css/_common/outline/header/brand.styl +77 -77
  114. package/source/css/_common/outline/header/header.styl +20 -20
  115. package/source/css/_common/outline/header/image.styl +79 -79
  116. package/source/css/_common/outline/header/menu.styl +117 -117
  117. package/source/css/_common/outline/header/nav.styl +81 -81
  118. package/source/css/_common/outline/header/right.styl +15 -15
  119. package/source/css/_common/outline/header/tool.styl +207 -207
  120. package/source/css/_common/outline/header/waves.styl +50 -50
  121. package/source/css/_common/outline/mobile.styl +46 -46
  122. package/source/css/_common/outline/outline.styl +78 -78
  123. package/source/css/_common/outline/sidebar/author.styl +59 -59
  124. package/source/css/_common/outline/sidebar/dimmer.styl +23 -23
  125. package/source/css/_common/outline/sidebar/menu.styl +63 -63
  126. package/source/css/_common/outline/sidebar/quick.styl +43 -43
  127. package/source/css/_common/outline/sidebar/related.styl +56 -56
  128. package/source/css/_common/outline/sidebar/sidebar.styl +75 -75
  129. package/source/css/_common/outline/sidebar/social.styl +69 -69
  130. package/source/css/_common/outline/sidebar/state.styl +37 -37
  131. package/source/css/_common/outline/sidebar/tab.styl +71 -71
  132. package/source/css/_common/outline/sidebar/toc.styl +47 -47
  133. package/source/css/_common/scaffolding/animate.styl +318 -318
  134. package/source/css/_common/scaffolding/base.styl +172 -172
  135. package/source/css/_common/scaffolding/buttons.styl +48 -48
  136. package/source/css/_common/scaffolding/divider.styl +36 -36
  137. package/source/css/_common/scaffolding/iconfont.styl +443 -443
  138. package/source/css/_common/scaffolding/normalize.styl +289 -289
  139. package/source/css/_common/scaffolding/pagination.styl +81 -81
  140. package/source/css/_common/scaffolding/ribbon.styl +38 -38
  141. package/source/css/_common/scaffolding/scaffolding.styl +14 -14
  142. package/source/css/_common/scaffolding/scrollbar.styl +37 -37
  143. package/source/css/_common/scaffolding/tables.styl +50 -50
  144. package/source/css/_common/scaffolding/tip.styl +19 -19
  145. package/source/css/_common/scaffolding/toggles.styl +59 -59
  146. package/source/css/_iconfont.styl +451 -451
  147. package/source/css/_mixins.styl +146 -146
  148. package/source/css/_variables.styl +89 -89
  149. package/source/css/app.styl +36 -36
  150. package/source/css/comment.styl +5 -5
  151. package/source/css/mermaid.styl +5 -5
  152. package/source/js/_app/components.js +330 -330
  153. package/source/js/_app/global.js +317 -317
  154. package/source/js/_app/library.js +302 -302
  155. package/source/js/_app/page.js +623 -623
  156. package/source/js/_app/player.js +748 -748
  157. package/source/js/_app/vue.js +43 -43
@@ -1,748 +1,748 @@
1
- let NOWPLAYING = null;
2
- const isMobile = /mobile/i.test(window.navigator.userAgent);
3
- const mediaPlayer = function (t, config) {
4
- const buttons = {
5
- el: {},
6
- create: function () {
7
- if (!t.player.options.btns) {
8
- return;
9
- }
10
- t.player.options.btns.forEach(function (item) {
11
- if (buttons.el[item]) {
12
- return;
13
- }
14
- buttons.el[item] = t.createChild('div', {
15
- className: item + ' btn',
16
- onclick: function (event) {
17
- t.player.fetch().then(function () {
18
- t.player.options.events[item](event);
19
- });
20
- }
21
- });
22
- });
23
- }
24
- };
25
- const controller = {
26
- el: null,
27
- btns: {
28
- mode: undefined,
29
- volume: undefined
30
- },
31
- step: 'next',
32
- create: () => {
33
- if (!t.player.options.controls) {
34
- return;
35
- }
36
- const that = controller;
37
- t.player.options.controls.forEach(function (item) {
38
- if (that.btns[item]) {
39
- return;
40
- }
41
- const opt = {
42
- onclick: function (event) {
43
- that.events[item] ? that.events[item](event) : t.player.options.events[item](event);
44
- }
45
- };
46
- switch (item) {
47
- case 'volume':
48
- opt.className = ' ' + (source.muted ? 'off' : 'on');
49
- opt.innerHTML = '<div class="bar"></div>';
50
- opt['on' + utils.nameMap.dragStart] = that.events.volume;
51
- opt.onclick = null;
52
- break;
53
- case 'mode':
54
- opt.className = ' ' + t.player.options.mode;
55
- break;
56
- default:
57
- opt.className = '';
58
- break;
59
- }
60
- opt.className = item + opt.className + ' btn';
61
- that.btns[item] = that.el.createChild('div', opt);
62
- });
63
- that.btns.volume.bar = that.btns.volume.child('.bar');
64
- },
65
- events: {
66
- mode: function (e) {
67
- switch (t.player.options.mode) {
68
- case 'loop':
69
- t.player.options.mode = 'random';
70
- break;
71
- case 'random':
72
- t.player.options.mode = 'order';
73
- break;
74
- default:
75
- t.player.options.mode = 'loop';
76
- }
77
- controller.btns.mode.className = 'mode ' + t.player.options.mode + ' btn';
78
- $storage.set('_PlayerMode', t.player.options.mode);
79
- },
80
- volume: function (e) {
81
- e.preventDefault();
82
- const current = e.currentTarget;
83
- let drag = false;
84
- const thumbMove = function (e) {
85
- e.preventDefault();
86
- t.player.volume(controller.percent(e, current));
87
- drag = true;
88
- };
89
- const thumbUp = function (e) {
90
- e.preventDefault();
91
- current.removeEventListener(utils.nameMap.dragEnd, thumbUp);
92
- current.removeEventListener(utils.nameMap.dragMove, thumbMove);
93
- if (drag) {
94
- t.player.muted();
95
- t.player.volume(controller.percent(e, current));
96
- }
97
- else {
98
- if (source.muted) {
99
- t.player.muted();
100
- t.player.volume(source.volume);
101
- }
102
- else {
103
- t.player.muted('muted');
104
- controller.update(0);
105
- }
106
- }
107
- };
108
- current.addEventListener(utils.nameMap.dragMove, thumbMove);
109
- current.addEventListener(utils.nameMap.dragEnd, thumbUp);
110
- },
111
- backward: function (e) {
112
- controller.step = 'prev';
113
- t.player.mode();
114
- },
115
- forward: function (e) {
116
- controller.step = 'next';
117
- t.player.mode();
118
- }
119
- },
120
- update: function (percent) {
121
- controller.btns.volume.className = 'volume ' + (!source.muted && percent > 0 ? 'on' : 'off') + ' btn';
122
- controller.btns.volume.bar.changeOrGetWidth(Math.floor(percent * 100) + '%');
123
- },
124
- percent: function (e, el) {
125
- let percentage = ((e.clientX || e.changedTouches[0].clientX) - el.left()) / el.changeOrGetWidth();
126
- percentage = Math.max(percentage, 0);
127
- return Math.min(percentage, 1);
128
- }
129
- };
130
- const progress = {
131
- el: null,
132
- bar: null,
133
- create: function () {
134
- const current = playlist.current().el;
135
- if (current) {
136
- if (progress.el) {
137
- progress.el.parentNode.removeClass('current')
138
- .removeEventListener(utils.nameMap.dragStart, progress.drag);
139
- progress.el.remove();
140
- }
141
- progress.el = current.createChild('div', {
142
- className: 'progress'
143
- });
144
- progress.el.attr('data-dtime', utils.secondToTime(0));
145
- progress.bar = progress.el.createChild('div', {
146
- className: 'bar'
147
- });
148
- current.addClass('current');
149
- current.addEventListener(utils.nameMap.dragStart, progress.drag);
150
- playlist.scroll();
151
- }
152
- },
153
- update: function (percent) {
154
- progress.bar.changeOrGetWidth(Math.floor(percent * 100) + '%');
155
- progress.el.attr('data-ptime', utils.secondToTime(percent * source.duration));
156
- },
157
- seeking: function (type) {
158
- if (type) {
159
- progress.el.addClass('seeking');
160
- }
161
- else {
162
- progress.el.removeClass('seeking');
163
- }
164
- },
165
- percent: function (e, el) {
166
- let percentage = ((e.clientX || e.changedTouches[0].clientX) - el.left()) / el.changeOrGetWidth();
167
- percentage = Math.max(percentage, 0);
168
- return Math.min(percentage, 1);
169
- },
170
- drag: function (e) {
171
- e.preventDefault();
172
- const current = playlist.current().el;
173
- const thumbMove = function (e) {
174
- e.preventDefault();
175
- const percentage = progress.percent(e, current);
176
- progress.update(percentage);
177
- lyrics.update(percentage * source.duration);
178
- };
179
- const thumbUp = function (e) {
180
- e.preventDefault();
181
- current.removeEventListener(utils.nameMap.dragEnd, thumbUp);
182
- current.removeEventListener(utils.nameMap.dragMove, thumbMove);
183
- const percentage = progress.percent(e, current);
184
- progress.update(percentage);
185
- t.player.seek(percentage * source.duration);
186
- source.disableTimeupdate = false;
187
- progress.seeking(false);
188
- };
189
- source.disableTimeupdate = true;
190
- progress.seeking(true);
191
- current.addEventListener(utils.nameMap.dragMove, thumbMove);
192
- current.addEventListener(utils.nameMap.dragEnd, thumbUp);
193
- }
194
- };
195
- const preview = {
196
- el: null,
197
- create: function () {
198
- const current = playlist.current();
199
- preview.el.innerHTML = '<div class="cover"><div class="disc"><img src="' + (current.cover) + '" class="blur" alt="music cover"/></div></div>' +
200
- '<div class="info"><h4 class="title">' + current.name + '</h4><span>' + current.artist + '</span>' +
201
- '<div class="lrc"></div></div>';
202
- preview.el.child('.cover').addEventListener('click', t.player.options.events['play-pause']);
203
- lyrics.create(preview.el.child('.lrc'));
204
- }
205
- };
206
- let source;
207
- const playlist = {
208
- el: null,
209
- data: [],
210
- index: -1,
211
- errnum: 0,
212
- add: (group, list) => {
213
- list.forEach(function (item, i) {
214
- item.group = group;
215
- item.name = item.name || item.title || 'Meida name';
216
- item.artist = item.artist || item.author || 'Anonymous';
217
- item.cover = item.cover || item.pic;
218
- item.type = item.type || 'normal';
219
- playlist.data.push(item);
220
- });
221
- },
222
- clear: function () {
223
- playlist.data = [];
224
- playlist.el.innerHTML = '';
225
- if (playlist.index !== -1) {
226
- playlist.index = -1;
227
- t.player.fetch();
228
- }
229
- },
230
- create: function () {
231
- const el = playlist.el;
232
- playlist.data.map(function (item, index) {
233
- if (item.el) {
234
- return;
235
- }
236
- const id = 'list-' + t.player._id + '-' + item.group;
237
- let tab = $dom('#' + id);
238
- if (!tab) {
239
- tab = el.createChild('div', {
240
- id,
241
- className: t.player.group ? 'tab' : '',
242
- innerHTML: '<ol></ol>'
243
- });
244
- if (t.player.group) {
245
- tab.attr('data-title', t.player.options.rawList[item.group].title)
246
- .attr('data-id', t.player._id);
247
- }
248
- }
249
- item.el = tab.child('ol').createChild('li', {
250
- title: item.name + ' - ' + item.artist,
251
- innerHTML: '<span class="info"><span>' + item.name + '</span><span>' + item.artist + '</span></span>',
252
- onclick: function (event) {
253
- const current = event.currentTarget;
254
- if (playlist.index === index && progress.el) {
255
- if (source.paused) {
256
- t.player.play();
257
- }
258
- else {
259
- t.player.seek(source.duration * progress.percent(event, current));
260
- }
261
- return;
262
- }
263
- t.player.switch(index);
264
- t.player.play();
265
- }
266
- });
267
- return item;
268
- });
269
- tabFormat();
270
- },
271
- current: function () {
272
- return this.data[this.index];
273
- },
274
- scroll: function () {
275
- const item = this.current();
276
- let li = this.el.child('li.active');
277
- li && li.removeClass('active');
278
- let tab = this.el.child('.tab.active');
279
- tab && tab.removeClass('active');
280
- li = this.el.find('.nav li')[item.group];
281
- li && li.addClass('active');
282
- tab = this.el.find('.tab')[item.group];
283
- tab && tab.addClass('active');
284
- pageScroll(item.el, item.el.offsetTop);
285
- return this;
286
- },
287
- title: function () {
288
- if (source.paused) {
289
- return;
290
- }
291
- const current = this.current();
292
- document.title = 'Now Playing...' + current.name + ' - ' + current.artist + ' | ' + originTitle;
293
- },
294
- error: function () {
295
- const current = this.current();
296
- current.el.removeClass('current').addClass('error');
297
- current.error = true;
298
- this.errnum++;
299
- }
300
- };
301
- const info = {
302
- el: null,
303
- create: function () {
304
- if (this.el) {
305
- return;
306
- }
307
- this.el = t.createChild('div', {
308
- className: 'player-info',
309
- innerHTML: (t.player.options.type === 'audio' ? '<div class="preview"></div>' : '') + '<div class="controller"></div><div class="playlist"></div>'
310
- }, 'after');
311
- preview.el = this.el.child('.preview');
312
- playlist.el = this.el.child('.playlist');
313
- controller.el = this.el.child('.controller');
314
- },
315
- hide: function () {
316
- const el = this.el;
317
- el.addClass('hide');
318
- window.setTimeout(function () {
319
- el.removeClass('show hide');
320
- }, 300);
321
- }
322
- };
323
- let option = {
324
- type: 'audio',
325
- mode: 'random',
326
- btns: ['play-pause', 'music'],
327
- controls: ['mode', 'backward', 'play-pause', 'forward', 'volume'],
328
- events: {
329
- 'play-pause': function (event) {
330
- if (source.paused) {
331
- t.player.play();
332
- }
333
- else {
334
- t.player.pause();
335
- }
336
- },
337
- music: function (event) {
338
- if (info.el.hasClass('show')) {
339
- info.hide();
340
- }
341
- else {
342
- info.el.addClass('show');
343
- playlist.scroll().title();
344
- }
345
- }
346
- }
347
- };
348
- let utils = {
349
- random: function (len) {
350
- return Math.floor((Math.random() * len));
351
- },
352
- parse: function (link) {
353
- let result = [];
354
- [
355
- ['music.163.com.*song.*id=(\\d+)', 'netease', 'song'],
356
- ['music.163.com.*album.*id=(\\d+)', 'netease', 'album'],
357
- ['music.163.com.*artist.*id=(\\d+)', 'netease', 'artist'],
358
- ['music.163.com.*playlist.*id=(\\d+)', 'netease', 'playlist'],
359
- ['music.163.com.*discover/toplist.*id=(\\d+)', 'netease', 'playlist'],
360
- ['y.qq.com.*song/(\\w+).html', 'tencent', 'song'],
361
- ['y.qq.com.*album/(\\w+).html', 'tencent', 'album'],
362
- ['y.qq.com.*singer/(\\w+).html', 'tencent', 'artist'],
363
- ['y.qq.com.*playsquare/(\\w+).html', 'tencent', 'playlist'],
364
- ['y.qq.com.*playlist/(\\w+).html', 'tencent', 'playlist'],
365
- ['xiami.com.*song/(\\w+)', 'xiami', 'song'],
366
- ['xiami.com.*album/(\\w+)', 'xiami', 'album'],
367
- ['xiami.com.*artist/(\\w+)', 'xiami', 'artist'],
368
- ['xiami.com.*collect/(\\w+)', 'xiami', 'playlist']
369
- ].forEach(function (rule) {
370
- const patt = new RegExp(rule[0]);
371
- const res = patt.exec(link);
372
- if (res !== null) {
373
- result = [rule[1], rule[2], res[1]];
374
- }
375
- });
376
- return result;
377
- },
378
- fetch: function (source) {
379
- const list = [];
380
- return new Promise(function (resolve, reject) {
381
- source.forEach(function (raw) {
382
- const meta = utils.parse(raw);
383
- if (meta[0]) {
384
- const skey = JSON.stringify(meta);
385
- const playlist = $storage.get(skey);
386
- if (playlist) {
387
- list.push(...JSON.parse(playlist));
388
- resolve(list);
389
- }
390
- else {
391
- fetch('https://api.i-meto.com/meting/api?server=' + meta[0] + '&type=' + meta[1] + '&id=' + meta[2] + '&r=' + Math.random())
392
- .then(function (response) {
393
- return response.json();
394
- }).then(function (json) {
395
- $storage.set(skey, JSON.stringify(json));
396
- list.push(...json);
397
- resolve(list);
398
- }).catch((ex) => {
399
- });
400
- }
401
- }
402
- else {
403
- list.push(raw);
404
- resolve(list);
405
- }
406
- });
407
- });
408
- },
409
- secondToTime: function (second) {
410
- const add0 = function (num) {
411
- return isNaN(num) ? '00' : (num < 10 ? '0' + num : '' + num);
412
- };
413
- const hour = Math.floor(second / 3600);
414
- const min = Math.floor((second - hour * 3600) / 60);
415
- const sec = Math.floor(second - hour * 3600 - min * 60);
416
- return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':');
417
- },
418
- nameMap: {
419
- dragStart: isMobile ? 'touchstart' : 'mousedown',
420
- dragMove: isMobile ? 'touchmove' : 'mousemove',
421
- dragEnd: isMobile ? 'touchend' : 'mouseup'
422
- }
423
- };
424
- source = null;
425
- t.player = {
426
- _id: utils.random(999999),
427
- group: true,
428
- load: function (newList) {
429
- let d = '';
430
- if (newList && newList.length > 0) {
431
- if (this.options.rawList !== newList) {
432
- this.options.rawList = newList;
433
- playlist.clear();
434
- }
435
- }
436
- else {
437
- d = 'none';
438
- this.pause();
439
- }
440
- for (const el in buttons.el) {
441
- buttons.el[el].display(d);
442
- }
443
- return this;
444
- },
445
- fetch: function () {
446
- const that = this;
447
- return new Promise(function (resolve, reject) {
448
- if (playlist.data.length > 0) {
449
- resolve(true);
450
- }
451
- else {
452
- if (that.options.rawList) {
453
- const promises = [];
454
- that.options.rawList.forEach(function (raw, index) {
455
- promises.push(new Promise(function (resolve, reject) {
456
- let group = index;
457
- let source;
458
- if (!raw.list) {
459
- group = 0;
460
- that.group = false;
461
- source = [raw];
462
- }
463
- else {
464
- that.group = true;
465
- source = raw.list;
466
- }
467
- utils.fetch(source).then(function (list) {
468
- playlist.add(group, list);
469
- resolve(0);
470
- });
471
- }));
472
- });
473
- Promise.all(promises).then(function () {
474
- resolve(true);
475
- });
476
- }
477
- }
478
- }).then(function (c) {
479
- if (c) {
480
- playlist.create();
481
- controller.create();
482
- that.mode();
483
- }
484
- });
485
- },
486
- mode: function () {
487
- const total = playlist.data.length;
488
- if (!total || playlist.errnum === total) {
489
- return;
490
- }
491
- const step = controller.step === 'next' ? 1 : -1;
492
- const next = function () {
493
- let index = playlist.index + step;
494
- if (index > total || index < 0) {
495
- index = controller.step === 'next' ? 0 : total - 1;
496
- }
497
- playlist.index = index;
498
- };
499
- const random = function () {
500
- const p = utils.random(total);
501
- if (playlist.index !== p) {
502
- playlist.index = p;
503
- }
504
- else {
505
- next();
506
- }
507
- };
508
- switch (this.options.mode) {
509
- case 'random':
510
- random();
511
- break;
512
- case 'order':
513
- next();
514
- break;
515
- case 'loop':
516
- if (controller.step) {
517
- next();
518
- }
519
- if (playlist.index === -1) {
520
- random();
521
- }
522
- break;
523
- }
524
- this.init();
525
- },
526
- switch: function (index) {
527
- if (typeof index === 'number' &&
528
- index !== playlist.index &&
529
- playlist.current() &&
530
- !playlist.current().error) {
531
- playlist.index = index;
532
- this.init();
533
- }
534
- },
535
- init: function () {
536
- const item = playlist.current();
537
- if (!item || item.error) {
538
- this.mode();
539
- return;
540
- }
541
- let playing = false;
542
- if (!source.paused) {
543
- playing = true;
544
- this.stop();
545
- }
546
- source.attr('src', item.url);
547
- source.attr('title', item.name + ' - ' + item.artist);
548
- this.volume($storage.get('_PlayerVolume') || '0.7');
549
- this.muted($storage.get('_PlayerMuted'));
550
- progress.create();
551
- if (this.options.type === 'audio') {
552
- preview.create();
553
- }
554
- if (playing === true) {
555
- this.play();
556
- }
557
- },
558
- play: function () {
559
- NOWPLAYING && NOWPLAYING.player.pause();
560
- if (playlist.current().error) {
561
- this.mode();
562
- return;
563
- }
564
- source.play().then(function () {
565
- playlist.scroll();
566
- }).catch(function (e) {
567
- });
568
- },
569
- pause: function () {
570
- source.pause();
571
- document.title = originTitle;
572
- },
573
- stop: function () {
574
- source.pause();
575
- source.currentTime = 0;
576
- document.title = originTitle;
577
- },
578
- seek: function (time) {
579
- time = Math.max(time, 0);
580
- time = Math.min(time, source.duration);
581
- source.currentTime = time;
582
- progress.update(time / source.duration);
583
- },
584
- muted: function (status) {
585
- if (status === 'muted') {
586
- source.muted = status;
587
- $storage.set('_PlayerMuted', status);
588
- controller.update(0);
589
- }
590
- else {
591
- $storage.del('_PlayerMuted');
592
- source.muted = false;
593
- controller.update(source.volume);
594
- }
595
- },
596
- volume: function (percentage) {
597
- if (!isNaN(percentage)) {
598
- controller.update(percentage);
599
- $storage.set('_PlayerVolume', percentage);
600
- source.volume = percentage;
601
- }
602
- },
603
- mini: function () {
604
- info.hide();
605
- }
606
- };
607
- const lyrics = {
608
- el: null,
609
- data: null,
610
- index: 0,
611
- create: (box) => {
612
- const current = playlist.index;
613
- const raw = playlist.current().lrc;
614
- const callback = function (body) {
615
- if (current !== playlist.index) {
616
- return;
617
- }
618
- this.data = this.parse(body);
619
- let lrc = '';
620
- this.data.forEach(function (line, index) {
621
- lrc += '<p' + (index === 0 ? ' class="current"' : '') + '>' + line[1] + '</p>';
622
- });
623
- this.el = box.createChild('div', {
624
- className: 'inner',
625
- innerHTML: lrc
626
- }, 'replace');
627
- this.index = 0;
628
- };
629
- if (raw.startsWith('http')) {
630
- this.fetch(raw, callback);
631
- }
632
- else {
633
- callback(raw);
634
- }
635
- },
636
- update: function (currentTime) {
637
- if (!this.data) {
638
- return;
639
- }
640
- if (this.index > this.data.length - 1 || currentTime < this.data[this.index][0] || (!this.data[this.index + 1] || currentTime >= this.data[this.index + 1][0])) {
641
- for (let i = 0; i < this.data.length; i++) {
642
- if (currentTime >= this.data[i][0] && (!this.data[i + 1] || currentTime < this.data[i + 1][0])) {
643
- this.index = i;
644
- const y = -(this.index - 1);
645
- this.el.style.transform = 'translateY(' + y + 'rem)';
646
- this.el.getElementsByClassName('current')[0].removeClass('current');
647
- this.el.getElementsByTagName('p')[i].addClass('current');
648
- }
649
- }
650
- }
651
- },
652
- parse: function (lrc_s) {
653
- if (lrc_s) {
654
- lrc_s = lrc_s.replace(/([^\]^\n])\[/g, function (match, p1) {
655
- return p1 + '\n[';
656
- });
657
- const lyric = lrc_s.split('\n');
658
- let lrc = [];
659
- const lyricLen = lyric.length;
660
- for (let i = 0; i < lyricLen; i++) {
661
- const lrcTimes = lyric[i].match(/\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/g);
662
- const lrcText = lyric[i]
663
- .replace(/.*\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/g, '')
664
- .replace(/<(\d{2}):(\d{2})(\.(\d{2,3}))?>/g, '')
665
- .replace(/^\s+|\s+$/g, '');
666
- if (lrcTimes) {
667
- const timeLen = lrcTimes.length;
668
- for (let j = 0; j < timeLen; j++) {
669
- const oneTime = /\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/.exec(lrcTimes[j]);
670
- const min2sec = oneTime[1] * 60;
671
- const sec2sec = parseInt(oneTime[2]);
672
- const msec2sec = oneTime[4] ? parseInt(oneTime[4]) / ((oneTime[4] + '').length === 2 ? 100 : 1000) : 0;
673
- const lrcTime = min2sec + sec2sec + msec2sec;
674
- lrc.push([lrcTime, lrcText]);
675
- }
676
- }
677
- }
678
- lrc = lrc.filter(function (item) {
679
- return item[1];
680
- });
681
- lrc.sort(function (a, b) {
682
- return a[0] - b[0];
683
- });
684
- return lrc;
685
- }
686
- else {
687
- return [];
688
- }
689
- },
690
- fetch: function (url, callback) {
691
- fetch(url)
692
- .then(function (response) {
693
- return response.text();
694
- }).then(function (body) {
695
- callback(body);
696
- }).catch(function (ex) {
697
- });
698
- }
699
- };
700
- const events = {
701
- onerror: function () {
702
- playlist.error();
703
- t.player.mode();
704
- },
705
- ondurationchange: function () {
706
- if (source.duration !== 1) {
707
- progress.el.attr('data-dtime', utils.secondToTime(source.duration));
708
- }
709
- },
710
- onloadedmetadata: function () {
711
- t.player.seek(0);
712
- progress.el.attr('data-dtime', utils.secondToTime(source.duration));
713
- },
714
- onplay: function () {
715
- t.parentNode.addClass('playing');
716
- showtip(this.attr('title'));
717
- NOWPLAYING = t;
718
- },
719
- onpause: function () {
720
- t.parentNode.removeClass('playing');
721
- NOWPLAYING = null;
722
- },
723
- ontimeupdate: function () {
724
- if (!this.disableTimeupdate) {
725
- progress.update(this.currentTime / this.duration);
726
- lyrics.update(this.currentTime);
727
- }
728
- },
729
- onended: function (argument) {
730
- t.player.mode();
731
- t.player.play();
732
- }
733
- };
734
- const init = function (config) {
735
- if (t.player.created) {
736
- return;
737
- }
738
- t.player.options = Object.assign(option, config);
739
- t.player.options.mode = $storage.get('_PlayerMode') || t.player.options.mode;
740
- buttons.create();
741
- source = t.createChild(t.player.options.type, events);
742
- info.create();
743
- t.parentNode.addClass(t.player.options.type);
744
- t.player.created = true;
745
- };
746
- init(config);
747
- return t;
748
- };
1
+ let NOWPLAYING = null;
2
+ const isMobile = /mobile/i.test(window.navigator.userAgent);
3
+ const mediaPlayer = function (t, config) {
4
+ const buttons = {
5
+ el: {},
6
+ create: function () {
7
+ if (!t.player.options.btns) {
8
+ return;
9
+ }
10
+ t.player.options.btns.forEach(function (item) {
11
+ if (buttons.el[item]) {
12
+ return;
13
+ }
14
+ buttons.el[item] = t.createChild('div', {
15
+ className: item + ' btn',
16
+ onclick: function (event) {
17
+ t.player.fetch().then(function () {
18
+ t.player.options.events[item](event);
19
+ });
20
+ }
21
+ });
22
+ });
23
+ }
24
+ };
25
+ const controller = {
26
+ el: null,
27
+ btns: {
28
+ mode: undefined,
29
+ volume: undefined
30
+ },
31
+ step: 'next',
32
+ create: () => {
33
+ if (!t.player.options.controls) {
34
+ return;
35
+ }
36
+ const that = controller;
37
+ t.player.options.controls.forEach(function (item) {
38
+ if (that.btns[item]) {
39
+ return;
40
+ }
41
+ const opt = {
42
+ onclick: function (event) {
43
+ that.events[item] ? that.events[item](event) : t.player.options.events[item](event);
44
+ }
45
+ };
46
+ switch (item) {
47
+ case 'volume':
48
+ opt.className = ' ' + (source.muted ? 'off' : 'on');
49
+ opt.innerHTML = '<div class="bar"></div>';
50
+ opt['on' + utils.nameMap.dragStart] = that.events.volume;
51
+ opt.onclick = null;
52
+ break;
53
+ case 'mode':
54
+ opt.className = ' ' + t.player.options.mode;
55
+ break;
56
+ default:
57
+ opt.className = '';
58
+ break;
59
+ }
60
+ opt.className = item + opt.className + ' btn';
61
+ that.btns[item] = that.el.createChild('div', opt);
62
+ });
63
+ that.btns.volume.bar = that.btns.volume.child('.bar');
64
+ },
65
+ events: {
66
+ mode: function (e) {
67
+ switch (t.player.options.mode) {
68
+ case 'loop':
69
+ t.player.options.mode = 'random';
70
+ break;
71
+ case 'random':
72
+ t.player.options.mode = 'order';
73
+ break;
74
+ default:
75
+ t.player.options.mode = 'loop';
76
+ }
77
+ controller.btns.mode.className = 'mode ' + t.player.options.mode + ' btn';
78
+ $storage.set('_PlayerMode', t.player.options.mode);
79
+ },
80
+ volume: function (e) {
81
+ e.preventDefault();
82
+ const current = e.currentTarget;
83
+ let drag = false;
84
+ const thumbMove = function (e) {
85
+ e.preventDefault();
86
+ t.player.volume(controller.percent(e, current));
87
+ drag = true;
88
+ };
89
+ const thumbUp = function (e) {
90
+ e.preventDefault();
91
+ current.removeEventListener(utils.nameMap.dragEnd, thumbUp);
92
+ current.removeEventListener(utils.nameMap.dragMove, thumbMove);
93
+ if (drag) {
94
+ t.player.muted();
95
+ t.player.volume(controller.percent(e, current));
96
+ }
97
+ else {
98
+ if (source.muted) {
99
+ t.player.muted();
100
+ t.player.volume(source.volume);
101
+ }
102
+ else {
103
+ t.player.muted('muted');
104
+ controller.update(0);
105
+ }
106
+ }
107
+ };
108
+ current.addEventListener(utils.nameMap.dragMove, thumbMove);
109
+ current.addEventListener(utils.nameMap.dragEnd, thumbUp);
110
+ },
111
+ backward: function (e) {
112
+ controller.step = 'prev';
113
+ t.player.mode();
114
+ },
115
+ forward: function (e) {
116
+ controller.step = 'next';
117
+ t.player.mode();
118
+ }
119
+ },
120
+ update: function (percent) {
121
+ controller.btns.volume.className = 'volume ' + (!source.muted && percent > 0 ? 'on' : 'off') + ' btn';
122
+ controller.btns.volume.bar.changeOrGetWidth(Math.floor(percent * 100) + '%');
123
+ },
124
+ percent: function (e, el) {
125
+ let percentage = ((e.clientX || e.changedTouches[0].clientX) - el.left()) / el.changeOrGetWidth();
126
+ percentage = Math.max(percentage, 0);
127
+ return Math.min(percentage, 1);
128
+ }
129
+ };
130
+ const progress = {
131
+ el: null,
132
+ bar: null,
133
+ create: function () {
134
+ const current = playlist.current().el;
135
+ if (current) {
136
+ if (progress.el) {
137
+ progress.el.parentNode.removeClass('current')
138
+ .removeEventListener(utils.nameMap.dragStart, progress.drag);
139
+ progress.el.remove();
140
+ }
141
+ progress.el = current.createChild('div', {
142
+ className: 'progress'
143
+ });
144
+ progress.el.attr('data-dtime', utils.secondToTime(0));
145
+ progress.bar = progress.el.createChild('div', {
146
+ className: 'bar'
147
+ });
148
+ current.addClass('current');
149
+ current.addEventListener(utils.nameMap.dragStart, progress.drag);
150
+ playlist.scroll();
151
+ }
152
+ },
153
+ update: function (percent) {
154
+ progress.bar.changeOrGetWidth(Math.floor(percent * 100) + '%');
155
+ progress.el.attr('data-ptime', utils.secondToTime(percent * source.duration));
156
+ },
157
+ seeking: function (type) {
158
+ if (type) {
159
+ progress.el.addClass('seeking');
160
+ }
161
+ else {
162
+ progress.el.removeClass('seeking');
163
+ }
164
+ },
165
+ percent: function (e, el) {
166
+ let percentage = ((e.clientX || e.changedTouches[0].clientX) - el.left()) / el.changeOrGetWidth();
167
+ percentage = Math.max(percentage, 0);
168
+ return Math.min(percentage, 1);
169
+ },
170
+ drag: function (e) {
171
+ e.preventDefault();
172
+ const current = playlist.current().el;
173
+ const thumbMove = function (e) {
174
+ e.preventDefault();
175
+ const percentage = progress.percent(e, current);
176
+ progress.update(percentage);
177
+ lyrics.update(percentage * source.duration);
178
+ };
179
+ const thumbUp = function (e) {
180
+ e.preventDefault();
181
+ current.removeEventListener(utils.nameMap.dragEnd, thumbUp);
182
+ current.removeEventListener(utils.nameMap.dragMove, thumbMove);
183
+ const percentage = progress.percent(e, current);
184
+ progress.update(percentage);
185
+ t.player.seek(percentage * source.duration);
186
+ source.disableTimeupdate = false;
187
+ progress.seeking(false);
188
+ };
189
+ source.disableTimeupdate = true;
190
+ progress.seeking(true);
191
+ current.addEventListener(utils.nameMap.dragMove, thumbMove);
192
+ current.addEventListener(utils.nameMap.dragEnd, thumbUp);
193
+ }
194
+ };
195
+ const preview = {
196
+ el: null,
197
+ create: function () {
198
+ const current = playlist.current();
199
+ preview.el.innerHTML = '<div class="cover"><div class="disc"><img src="' + (current.cover) + '" class="blur" alt="music cover"/></div></div>' +
200
+ '<div class="info"><h4 class="title">' + current.name + '</h4><span>' + current.artist + '</span>' +
201
+ '<div class="lrc"></div></div>';
202
+ preview.el.child('.cover').addEventListener('click', t.player.options.events['play-pause']);
203
+ lyrics.create(preview.el.child('.lrc'));
204
+ }
205
+ };
206
+ let source;
207
+ const playlist = {
208
+ el: null,
209
+ data: [],
210
+ index: -1,
211
+ errnum: 0,
212
+ add: (group, list) => {
213
+ list.forEach(function (item, i) {
214
+ item.group = group;
215
+ item.name = item.name || item.title || 'Meida name';
216
+ item.artist = item.artist || item.author || 'Anonymous';
217
+ item.cover = item.cover || item.pic;
218
+ item.type = item.type || 'normal';
219
+ playlist.data.push(item);
220
+ });
221
+ },
222
+ clear: function () {
223
+ playlist.data = [];
224
+ playlist.el.innerHTML = '';
225
+ if (playlist.index !== -1) {
226
+ playlist.index = -1;
227
+ t.player.fetch();
228
+ }
229
+ },
230
+ create: function () {
231
+ const el = playlist.el;
232
+ playlist.data.map(function (item, index) {
233
+ if (item.el) {
234
+ return;
235
+ }
236
+ const id = 'list-' + t.player._id + '-' + item.group;
237
+ let tab = $dom('#' + id);
238
+ if (!tab) {
239
+ tab = el.createChild('div', {
240
+ id,
241
+ className: t.player.group ? 'tab' : '',
242
+ innerHTML: '<ol></ol>'
243
+ });
244
+ if (t.player.group) {
245
+ tab.attr('data-title', t.player.options.rawList[item.group].title)
246
+ .attr('data-id', t.player._id);
247
+ }
248
+ }
249
+ item.el = tab.child('ol').createChild('li', {
250
+ title: item.name + ' - ' + item.artist,
251
+ innerHTML: '<span class="info"><span>' + item.name + '</span><span>' + item.artist + '</span></span>',
252
+ onclick: function (event) {
253
+ const current = event.currentTarget;
254
+ if (playlist.index === index && progress.el) {
255
+ if (source.paused) {
256
+ t.player.play();
257
+ }
258
+ else {
259
+ t.player.seek(source.duration * progress.percent(event, current));
260
+ }
261
+ return;
262
+ }
263
+ t.player.switch(index);
264
+ t.player.play();
265
+ }
266
+ });
267
+ return item;
268
+ });
269
+ tabFormat();
270
+ },
271
+ current: function () {
272
+ return this.data[this.index];
273
+ },
274
+ scroll: function () {
275
+ const item = this.current();
276
+ let li = this.el.child('li.active');
277
+ li && li.removeClass('active');
278
+ let tab = this.el.child('.tab.active');
279
+ tab && tab.removeClass('active');
280
+ li = this.el.find('.nav li')[item.group];
281
+ li && li.addClass('active');
282
+ tab = this.el.find('.tab')[item.group];
283
+ tab && tab.addClass('active');
284
+ pageScroll(item.el, item.el.offsetTop);
285
+ return this;
286
+ },
287
+ title: function () {
288
+ if (source.paused) {
289
+ return;
290
+ }
291
+ const current = this.current();
292
+ document.title = 'Now Playing...' + current.name + ' - ' + current.artist + ' | ' + originTitle;
293
+ },
294
+ error: function () {
295
+ const current = this.current();
296
+ current.el.removeClass('current').addClass('error');
297
+ current.error = true;
298
+ this.errnum++;
299
+ }
300
+ };
301
+ const info = {
302
+ el: null,
303
+ create: function () {
304
+ if (this.el) {
305
+ return;
306
+ }
307
+ this.el = t.createChild('div', {
308
+ className: 'player-info',
309
+ innerHTML: (t.player.options.type === 'audio' ? '<div class="preview"></div>' : '') + '<div class="controller"></div><div class="playlist"></div>'
310
+ }, 'after');
311
+ preview.el = this.el.child('.preview');
312
+ playlist.el = this.el.child('.playlist');
313
+ controller.el = this.el.child('.controller');
314
+ },
315
+ hide: function () {
316
+ const el = this.el;
317
+ el.addClass('hide');
318
+ window.setTimeout(function () {
319
+ el.removeClass('show hide');
320
+ }, 300);
321
+ }
322
+ };
323
+ let option = {
324
+ type: 'audio',
325
+ mode: 'random',
326
+ btns: ['play-pause', 'music'],
327
+ controls: ['mode', 'backward', 'play-pause', 'forward', 'volume'],
328
+ events: {
329
+ 'play-pause': function (event) {
330
+ if (source.paused) {
331
+ t.player.play();
332
+ }
333
+ else {
334
+ t.player.pause();
335
+ }
336
+ },
337
+ music: function (event) {
338
+ if (info.el.hasClass('show')) {
339
+ info.hide();
340
+ }
341
+ else {
342
+ info.el.addClass('show');
343
+ playlist.scroll().title();
344
+ }
345
+ }
346
+ }
347
+ };
348
+ let utils = {
349
+ random: function (len) {
350
+ return Math.floor((Math.random() * len));
351
+ },
352
+ parse: function (link) {
353
+ let result = [];
354
+ [
355
+ ['music.163.com.*song.*id=(\\d+)', 'netease', 'song'],
356
+ ['music.163.com.*album.*id=(\\d+)', 'netease', 'album'],
357
+ ['music.163.com.*artist.*id=(\\d+)', 'netease', 'artist'],
358
+ ['music.163.com.*playlist.*id=(\\d+)', 'netease', 'playlist'],
359
+ ['music.163.com.*discover/toplist.*id=(\\d+)', 'netease', 'playlist'],
360
+ ['y.qq.com.*song/(\\w+).html', 'tencent', 'song'],
361
+ ['y.qq.com.*album/(\\w+).html', 'tencent', 'album'],
362
+ ['y.qq.com.*singer/(\\w+).html', 'tencent', 'artist'],
363
+ ['y.qq.com.*playsquare/(\\w+).html', 'tencent', 'playlist'],
364
+ ['y.qq.com.*playlist/(\\w+).html', 'tencent', 'playlist'],
365
+ ['xiami.com.*song/(\\w+)', 'xiami', 'song'],
366
+ ['xiami.com.*album/(\\w+)', 'xiami', 'album'],
367
+ ['xiami.com.*artist/(\\w+)', 'xiami', 'artist'],
368
+ ['xiami.com.*collect/(\\w+)', 'xiami', 'playlist']
369
+ ].forEach(function (rule) {
370
+ const patt = new RegExp(rule[0]);
371
+ const res = patt.exec(link);
372
+ if (res !== null) {
373
+ result = [rule[1], rule[2], res[1]];
374
+ }
375
+ });
376
+ return result;
377
+ },
378
+ fetch: function (source) {
379
+ const list = [];
380
+ return new Promise(function (resolve, reject) {
381
+ source.forEach(function (raw) {
382
+ const meta = utils.parse(raw);
383
+ if (meta[0]) {
384
+ const skey = JSON.stringify(meta);
385
+ const playlist = $storage.get(skey);
386
+ if (playlist) {
387
+ list.push(...JSON.parse(playlist));
388
+ resolve(list);
389
+ }
390
+ else {
391
+ fetch('https://api.i-meto.com/meting/api?server=' + meta[0] + '&type=' + meta[1] + '&id=' + meta[2] + '&r=' + Math.random())
392
+ .then(function (response) {
393
+ return response.json();
394
+ }).then(function (json) {
395
+ $storage.set(skey, JSON.stringify(json));
396
+ list.push(...json);
397
+ resolve(list);
398
+ }).catch((ex) => {
399
+ });
400
+ }
401
+ }
402
+ else {
403
+ list.push(raw);
404
+ resolve(list);
405
+ }
406
+ });
407
+ });
408
+ },
409
+ secondToTime: function (second) {
410
+ const add0 = function (num) {
411
+ return isNaN(num) ? '00' : (num < 10 ? '0' + num : '' + num);
412
+ };
413
+ const hour = Math.floor(second / 3600);
414
+ const min = Math.floor((second - hour * 3600) / 60);
415
+ const sec = Math.floor(second - hour * 3600 - min * 60);
416
+ return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':');
417
+ },
418
+ nameMap: {
419
+ dragStart: isMobile ? 'touchstart' : 'mousedown',
420
+ dragMove: isMobile ? 'touchmove' : 'mousemove',
421
+ dragEnd: isMobile ? 'touchend' : 'mouseup'
422
+ }
423
+ };
424
+ source = null;
425
+ t.player = {
426
+ _id: utils.random(999999),
427
+ group: true,
428
+ load: function (newList) {
429
+ let d = '';
430
+ if (newList && newList.length > 0) {
431
+ if (this.options.rawList !== newList) {
432
+ this.options.rawList = newList;
433
+ playlist.clear();
434
+ }
435
+ }
436
+ else {
437
+ d = 'none';
438
+ this.pause();
439
+ }
440
+ for (const el in buttons.el) {
441
+ buttons.el[el].display(d);
442
+ }
443
+ return this;
444
+ },
445
+ fetch: function () {
446
+ const that = this;
447
+ return new Promise(function (resolve, reject) {
448
+ if (playlist.data.length > 0) {
449
+ resolve(true);
450
+ }
451
+ else {
452
+ if (that.options.rawList) {
453
+ const promises = [];
454
+ that.options.rawList.forEach(function (raw, index) {
455
+ promises.push(new Promise(function (resolve, reject) {
456
+ let group = index;
457
+ let source;
458
+ if (!raw.list) {
459
+ group = 0;
460
+ that.group = false;
461
+ source = [raw];
462
+ }
463
+ else {
464
+ that.group = true;
465
+ source = raw.list;
466
+ }
467
+ utils.fetch(source).then(function (list) {
468
+ playlist.add(group, list);
469
+ resolve(0);
470
+ });
471
+ }));
472
+ });
473
+ Promise.all(promises).then(function () {
474
+ resolve(true);
475
+ });
476
+ }
477
+ }
478
+ }).then(function (c) {
479
+ if (c) {
480
+ playlist.create();
481
+ controller.create();
482
+ that.mode();
483
+ }
484
+ });
485
+ },
486
+ mode: function () {
487
+ const total = playlist.data.length;
488
+ if (!total || playlist.errnum === total) {
489
+ return;
490
+ }
491
+ const step = controller.step === 'next' ? 1 : -1;
492
+ const next = function () {
493
+ let index = playlist.index + step;
494
+ if (index > total || index < 0) {
495
+ index = controller.step === 'next' ? 0 : total - 1;
496
+ }
497
+ playlist.index = index;
498
+ };
499
+ const random = function () {
500
+ const p = utils.random(total);
501
+ if (playlist.index !== p) {
502
+ playlist.index = p;
503
+ }
504
+ else {
505
+ next();
506
+ }
507
+ };
508
+ switch (this.options.mode) {
509
+ case 'random':
510
+ random();
511
+ break;
512
+ case 'order':
513
+ next();
514
+ break;
515
+ case 'loop':
516
+ if (controller.step) {
517
+ next();
518
+ }
519
+ if (playlist.index === -1) {
520
+ random();
521
+ }
522
+ break;
523
+ }
524
+ this.init();
525
+ },
526
+ switch: function (index) {
527
+ if (typeof index === 'number' &&
528
+ index !== playlist.index &&
529
+ playlist.current() &&
530
+ !playlist.current().error) {
531
+ playlist.index = index;
532
+ this.init();
533
+ }
534
+ },
535
+ init: function () {
536
+ const item = playlist.current();
537
+ if (!item || item.error) {
538
+ this.mode();
539
+ return;
540
+ }
541
+ let playing = false;
542
+ if (!source.paused) {
543
+ playing = true;
544
+ this.stop();
545
+ }
546
+ source.attr('src', item.url);
547
+ source.attr('title', item.name + ' - ' + item.artist);
548
+ this.volume($storage.get('_PlayerVolume') || '0.7');
549
+ this.muted($storage.get('_PlayerMuted'));
550
+ progress.create();
551
+ if (this.options.type === 'audio') {
552
+ preview.create();
553
+ }
554
+ if (playing === true) {
555
+ this.play();
556
+ }
557
+ },
558
+ play: function () {
559
+ NOWPLAYING && NOWPLAYING.player.pause();
560
+ if (playlist.current().error) {
561
+ this.mode();
562
+ return;
563
+ }
564
+ source.play().then(function () {
565
+ playlist.scroll();
566
+ }).catch(function (e) {
567
+ });
568
+ },
569
+ pause: function () {
570
+ source.pause();
571
+ document.title = originTitle;
572
+ },
573
+ stop: function () {
574
+ source.pause();
575
+ source.currentTime = 0;
576
+ document.title = originTitle;
577
+ },
578
+ seek: function (time) {
579
+ time = Math.max(time, 0);
580
+ time = Math.min(time, source.duration);
581
+ source.currentTime = time;
582
+ progress.update(time / source.duration);
583
+ },
584
+ muted: function (status) {
585
+ if (status === 'muted') {
586
+ source.muted = status;
587
+ $storage.set('_PlayerMuted', status);
588
+ controller.update(0);
589
+ }
590
+ else {
591
+ $storage.del('_PlayerMuted');
592
+ source.muted = false;
593
+ controller.update(source.volume);
594
+ }
595
+ },
596
+ volume: function (percentage) {
597
+ if (!isNaN(percentage)) {
598
+ controller.update(percentage);
599
+ $storage.set('_PlayerVolume', percentage);
600
+ source.volume = percentage;
601
+ }
602
+ },
603
+ mini: function () {
604
+ info.hide();
605
+ }
606
+ };
607
+ const lyrics = {
608
+ el: null,
609
+ data: null,
610
+ index: 0,
611
+ create: (box) => {
612
+ const current = playlist.index;
613
+ const raw = playlist.current().lrc;
614
+ const callback = function (body) {
615
+ if (current !== playlist.index) {
616
+ return;
617
+ }
618
+ this.data = this.parse(body);
619
+ let lrc = '';
620
+ this.data.forEach(function (line, index) {
621
+ lrc += '<p' + (index === 0 ? ' class="current"' : '') + '>' + line[1] + '</p>';
622
+ });
623
+ this.el = box.createChild('div', {
624
+ className: 'inner',
625
+ innerHTML: lrc
626
+ }, 'replace');
627
+ this.index = 0;
628
+ };
629
+ if (raw.startsWith('http')) {
630
+ this.fetch(raw, callback);
631
+ }
632
+ else {
633
+ callback(raw);
634
+ }
635
+ },
636
+ update: function (currentTime) {
637
+ if (!this.data) {
638
+ return;
639
+ }
640
+ if (this.index > this.data.length - 1 || currentTime < this.data[this.index][0] || (!this.data[this.index + 1] || currentTime >= this.data[this.index + 1][0])) {
641
+ for (let i = 0; i < this.data.length; i++) {
642
+ if (currentTime >= this.data[i][0] && (!this.data[i + 1] || currentTime < this.data[i + 1][0])) {
643
+ this.index = i;
644
+ const y = -(this.index - 1);
645
+ this.el.style.transform = 'translateY(' + y + 'rem)';
646
+ this.el.getElementsByClassName('current')[0].removeClass('current');
647
+ this.el.getElementsByTagName('p')[i].addClass('current');
648
+ }
649
+ }
650
+ }
651
+ },
652
+ parse: function (lrc_s) {
653
+ if (lrc_s) {
654
+ lrc_s = lrc_s.replace(/([^\]^\n])\[/g, function (match, p1) {
655
+ return p1 + '\n[';
656
+ });
657
+ const lyric = lrc_s.split('\n');
658
+ let lrc = [];
659
+ const lyricLen = lyric.length;
660
+ for (let i = 0; i < lyricLen; i++) {
661
+ const lrcTimes = lyric[i].match(/\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/g);
662
+ const lrcText = lyric[i]
663
+ .replace(/.*\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/g, '')
664
+ .replace(/<(\d{2}):(\d{2})(\.(\d{2,3}))?>/g, '')
665
+ .replace(/^\s+|\s+$/g, '');
666
+ if (lrcTimes) {
667
+ const timeLen = lrcTimes.length;
668
+ for (let j = 0; j < timeLen; j++) {
669
+ const oneTime = /\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/.exec(lrcTimes[j]);
670
+ const min2sec = oneTime[1] * 60;
671
+ const sec2sec = parseInt(oneTime[2]);
672
+ const msec2sec = oneTime[4] ? parseInt(oneTime[4]) / ((oneTime[4] + '').length === 2 ? 100 : 1000) : 0;
673
+ const lrcTime = min2sec + sec2sec + msec2sec;
674
+ lrc.push([lrcTime, lrcText]);
675
+ }
676
+ }
677
+ }
678
+ lrc = lrc.filter(function (item) {
679
+ return item[1];
680
+ });
681
+ lrc.sort(function (a, b) {
682
+ return a[0] - b[0];
683
+ });
684
+ return lrc;
685
+ }
686
+ else {
687
+ return [];
688
+ }
689
+ },
690
+ fetch: function (url, callback) {
691
+ fetch(url)
692
+ .then(function (response) {
693
+ return response.text();
694
+ }).then(function (body) {
695
+ callback(body);
696
+ }).catch(function (ex) {
697
+ });
698
+ }
699
+ };
700
+ const events = {
701
+ onerror: function () {
702
+ playlist.error();
703
+ t.player.mode();
704
+ },
705
+ ondurationchange: function () {
706
+ if (source.duration !== 1) {
707
+ progress.el.attr('data-dtime', utils.secondToTime(source.duration));
708
+ }
709
+ },
710
+ onloadedmetadata: function () {
711
+ t.player.seek(0);
712
+ progress.el.attr('data-dtime', utils.secondToTime(source.duration));
713
+ },
714
+ onplay: function () {
715
+ t.parentNode.addClass('playing');
716
+ showtip(this.attr('title'));
717
+ NOWPLAYING = t;
718
+ },
719
+ onpause: function () {
720
+ t.parentNode.removeClass('playing');
721
+ NOWPLAYING = null;
722
+ },
723
+ ontimeupdate: function () {
724
+ if (!this.disableTimeupdate) {
725
+ progress.update(this.currentTime / this.duration);
726
+ lyrics.update(this.currentTime);
727
+ }
728
+ },
729
+ onended: function (argument) {
730
+ t.player.mode();
731
+ t.player.play();
732
+ }
733
+ };
734
+ const init = function (config) {
735
+ if (t.player.created) {
736
+ return;
737
+ }
738
+ t.player.options = Object.assign(option, config);
739
+ t.player.options.mode = $storage.get('_PlayerMode') || t.player.options.mode;
740
+ buttons.create();
741
+ source = t.createChild(t.player.options.type, events);
742
+ info.create();
743
+ t.parentNode.addClass(t.player.options.type);
744
+ t.player.created = true;
745
+ };
746
+ init(config);
747
+ return t;
748
+ };