@applemusic-like-lyrics/core 0.0.10 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,123 +1,124 @@
1
- import { Container as v } from "@pixi/display";
2
- import { Application as M } from "@pixi/app";
1
+ import { Container as C } from "@pixi/display";
2
+ import { Application as z } from "@pixi/app";
3
3
  import { BlurFilter as y } from "@pixi/filter-blur";
4
- import { ColorMatrixFilter as E } from "@pixi/filter-color-matrix";
5
- import { Texture as C } from "@pixi/core";
6
- import { Sprite as L } from "@pixi/sprite";
7
- import { create as z } from "jss";
8
- import A from "jss-preset-default";
9
- const D = /^(((?<hour>[0-9]+):)?(?<min>[0-9]+):)?(?<sec>[0-9]+([\.:]([0-9]+))?)/;
10
- function T(d) {
11
- const e = D.exec(d);
4
+ import { ColorMatrixFilter as v } from "@pixi/filter-color-matrix";
5
+ import { Texture as A } from "@pixi/core";
6
+ import { Sprite as S } from "@pixi/sprite";
7
+ import { BulgePinchFilter as E } from "@pixi/filter-bulge-pinch";
8
+ import { create as I } from "jss";
9
+ import D from "jss-preset-default";
10
+ const k = /^(((?<hour>[0-9]+):)?(?<min>[0-9]+):)?(?<sec>[0-9]+([\.:]([0-9]+))?)/;
11
+ function T(h) {
12
+ const e = k.exec(h);
12
13
  if (e) {
13
- const t = Number(e.groups?.hour || "0"), i = Number(e.groups?.min || "0"), n = Number(e.groups?.sec.replace(/:/, ".") || "0");
14
- return Math.floor((t * 3600 + i * 60 + n) * 1e3);
14
+ const t = Number(e.groups?.hour || "0"), i = Number(e.groups?.min || "0"), s = Number(e.groups?.sec.replace(/:/, ".") || "0");
15
+ return Math.floor((t * 3600 + i * 60 + s) * 1e3);
15
16
  } else
16
17
  throw new TypeError("时间戳字符串解析失败");
17
18
  }
18
- function I(d) {
19
+ function B(h) {
19
20
  const t = new DOMParser().parseFromString(
20
- d,
21
+ h,
21
22
  "application/xml"
22
23
  );
23
24
  let i = "v1";
24
- for (const a of t.querySelectorAll("ttm\\:agent"))
25
- if (a.getAttribute("type") === "person") {
26
- const s = a.getAttribute("xml:id");
27
- s && (i = s);
25
+ for (const r of t.querySelectorAll("ttm\\:agent"))
26
+ if (r.getAttribute("type") === "person") {
27
+ const n = r.getAttribute("xml:id");
28
+ n && (i = n);
28
29
  }
29
- const n = [];
30
- for (const a of t.querySelectorAll("body p[begin][end]")) {
31
- const s = {
30
+ const s = [];
31
+ for (const r of t.querySelectorAll("body p[begin][end]")) {
32
+ const n = {
32
33
  words: [],
33
- startTime: T(a.getAttribute("begin") ?? "0:0"),
34
- endTime: T(a.getAttribute("end") ?? "0:0"),
34
+ startTime: T(r.getAttribute("begin") ?? "0:0"),
35
+ endTime: T(r.getAttribute("end") ?? "0:0"),
35
36
  translatedLyric: "",
36
37
  romanLyric: "",
37
38
  isBG: !1,
38
- isDuet: a.getAttribute("ttm:agent") !== i
39
+ isDuet: r.getAttribute("ttm:agent") !== i
39
40
  };
40
- let r = null;
41
- for (const l of a.childNodes)
41
+ let a = null;
42
+ for (const l of r.childNodes)
42
43
  if (l.nodeType === Node.TEXT_NODE) {
43
- const h = l.textContent ?? "";
44
- /^(\s+)$/.test(h) ? s.words.push({
44
+ const o = l.textContent ?? "";
45
+ /^(\s+)$/.test(o) ? n.words.push({
45
46
  word: " ",
46
47
  startTime: 0,
47
48
  endTime: 0
48
- }) : s.words.push({
49
- word: h,
49
+ }) : n.words.push({
50
+ word: o,
50
51
  startTime: 0,
51
52
  endTime: 0
52
53
  });
53
54
  } else if (l.nodeType === Node.ELEMENT_NODE) {
54
- const h = l, o = h.getAttribute("ttm:role");
55
- if (h.nodeName === "span" && o)
56
- if (o === "x-bg") {
57
- const c = {
55
+ const o = l, c = o.getAttribute("ttm:role");
56
+ if (o.nodeName === "span" && c)
57
+ if (c === "x-bg") {
58
+ const m = {
58
59
  words: [],
59
- startTime: s.startTime,
60
- endTime: s.endTime,
60
+ startTime: n.startTime,
61
+ endTime: n.endTime,
61
62
  translatedLyric: "",
62
63
  romanLyric: "",
63
64
  isBG: !0,
64
- isDuet: s.isDuet
65
+ isDuet: n.isDuet
65
66
  };
66
- for (const u of h.childNodes)
67
- if (u.nodeType === Node.TEXT_NODE) {
68
- const f = u.textContent ?? "";
69
- /^(\s+)$/.test(f) ? c.words.push({
67
+ for (const p of o.childNodes)
68
+ if (p.nodeType === Node.TEXT_NODE) {
69
+ const d = p.textContent ?? "";
70
+ /^(\s+)$/.test(d) ? m.words.push({
70
71
  word: " ",
71
72
  startTime: 0,
72
73
  endTime: 0
73
- }) : c.words.push({
74
- word: f,
74
+ }) : m.words.push({
75
+ word: d,
75
76
  startTime: 0,
76
77
  endTime: 0
77
78
  });
78
- } else if (u.nodeType === Node.ELEMENT_NODE) {
79
- const f = u, b = f.getAttribute("ttm:role");
80
- if (f.nodeName === "span" && b)
81
- b === "x-translation" ? c.translatedLyric = f.innerHTML.trim() : b === "x-roman" && (c.romanLyric = f.innerHTML.trim());
82
- else if (f.hasAttribute("begin") && f.hasAttribute("end")) {
83
- const x = {
84
- word: u.textContent,
85
- startTime: T(f.getAttribute("begin")),
86
- endTime: T(f.getAttribute("end"))
79
+ } else if (p.nodeType === Node.ELEMENT_NODE) {
80
+ const d = p, g = d.getAttribute("ttm:role");
81
+ if (d.nodeName === "span" && g)
82
+ g === "x-translation" ? m.translatedLyric = d.innerHTML.trim() : g === "x-roman" && (m.romanLyric = d.innerHTML.trim());
83
+ else if (d.hasAttribute("begin") && d.hasAttribute("end")) {
84
+ const b = {
85
+ word: p.textContent,
86
+ startTime: T(d.getAttribute("begin")),
87
+ endTime: T(d.getAttribute("end"))
87
88
  };
88
- c.words.push(x);
89
+ m.words.push(b);
89
90
  }
90
91
  }
91
- const m = c.words[0];
92
- c.startTime = m.startTime, m?.word.startsWith("(") && (m.word = m.word.substring(1));
93
- const p = c.words[c.words.length - 1];
94
- c.endTime = p.endTime, p?.word.endsWith(")") && (p.word = p.word.substring(
92
+ const u = m.words[0];
93
+ m.startTime = u.startTime, u?.word.startsWith("(") && (u.word = u.word.substring(1));
94
+ const f = m.words[m.words.length - 1];
95
+ m.endTime = f.endTime, f?.word.endsWith(")") && (f.word = f.word.substring(
95
96
  0,
96
- p.word.length - 1
97
- )), r = c;
97
+ f.word.length - 1
98
+ )), a = m;
98
99
  } else
99
- o === "x-translation" ? s.translatedLyric = h.innerHTML : o === "x-roman" && (s.romanLyric = h.innerHTML);
100
- else if (h.hasAttribute("begin") && h.hasAttribute("end")) {
101
- const c = {
100
+ c === "x-translation" ? n.translatedLyric = o.innerHTML : c === "x-roman" && (n.romanLyric = o.innerHTML);
101
+ else if (o.hasAttribute("begin") && o.hasAttribute("end")) {
102
+ const m = {
102
103
  word: l.textContent ?? "",
103
- startTime: T(h.getAttribute("begin")),
104
- endTime: T(h.getAttribute("end"))
104
+ startTime: T(o.getAttribute("begin")),
105
+ endTime: T(o.getAttribute("end"))
105
106
  };
106
- s.words.push(c);
107
+ n.words.push(m);
107
108
  }
108
109
  }
109
- n.push(s), r && n.push(r);
110
+ s.push(n), a && s.push(a);
110
111
  }
111
- return console.log(n), n;
112
+ return s;
112
113
  }
113
- const Q = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
114
+ const ae = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
114
115
  __proto__: null,
115
- parseTTML: I
116
+ parseTTML: B
116
117
  }, Symbol.toStringTag, { value: "Module" }));
117
- class B extends v {
118
+ class O extends C {
118
119
  time = 0;
119
120
  }
120
- class k {
121
+ class $ {
121
122
  constructor(e) {
122
123
  this.canvas = e;
123
124
  const t = e.getBoundingClientRect();
@@ -126,8 +127,8 @@ class k {
126
127
  this.canvas.width = Math.max(1, i.width), this.canvas.height = Math.max(1, i.height), this.app.renderer.resize(
127
128
  this.canvas.width * this.currerntRenderScale,
128
129
  this.canvas.height * this.currerntRenderScale
129
- ), this.rebuildFilters();
130
- }), this.observer.observe(e), this.app = new M({
130
+ ), this.app.ticker.start(), this.rebuildFilters();
131
+ }), this.observer.observe(e), this.app = new z({
131
132
  view: e,
132
133
  resizeTo: this.canvas,
133
134
  powerPreference: "low-power",
@@ -137,20 +138,21 @@ class k {
137
138
  observer;
138
139
  app;
139
140
  curContainer;
141
+ staticMode = !1;
140
142
  lastContainer = /* @__PURE__ */ new Set();
141
143
  onTick = (e) => {
142
144
  for (const t of this.lastContainer)
143
- t.alpha = Math.max(0, t.alpha - e / 60), t.alpha <= 0 && (this.app.stage.removeChild(t), this.lastContainer.delete(t));
145
+ t.alpha = Math.max(0, t.alpha - e / 60), t.alpha <= 0 && (this.app.stage.removeChild(t), this.lastContainer.delete(t), t.destroy(!0));
144
146
  if (this.curContainer) {
145
147
  this.curContainer.alpha = Math.min(
146
148
  1,
147
149
  this.curContainer.alpha + e / 60
148
150
  );
149
- const [t, i, n, a] = this.curContainer.children, s = Math.max(this.app.screen.width, this.app.screen.height);
151
+ const [t, i, s, r] = this.curContainer.children, n = Math.max(this.app.screen.width, this.app.screen.height);
150
152
  t.position.set(this.app.screen.width / 2, this.app.screen.height / 2), i.position.set(
151
153
  this.app.screen.width / 2.5,
152
154
  this.app.screen.height / 2.5
153
- ), n.position.set(this.app.screen.width / 2, this.app.screen.height / 2), a.position.set(this.app.screen.width / 2, this.app.screen.height / 2), t.width = s * Math.sqrt(2), t.height = t.width, i.width = s * 0.8, i.height = i.width, n.width = s * 0.5, n.height = n.width, a.width = s * 0.25, a.height = a.width, this.curContainer.time += e * this.flowSpeed, t.rotation += e / 1e3 * this.flowSpeed, i.rotation -= e / 500 * this.flowSpeed, n.rotation += e / 1e3 * this.flowSpeed, a.rotation -= e / 750 * this.flowSpeed, n.x = this.app.screen.width / 2 + this.app.screen.width / 4 * Math.cos(this.curContainer.time / 1e3 * 0.75), n.y = this.app.screen.height / 2 + this.app.screen.width / 4 * Math.cos(this.curContainer.time / 1e3 * 0.75), a.x = this.app.screen.width / 2 + this.app.screen.width / 4 * 0.1 + Math.cos(this.curContainer.time * 6e-3 * 0.75), a.y = this.app.screen.height / 2 + this.app.screen.width / 4 * 0.1 + Math.cos(this.curContainer.time * 6e-3 * 0.75);
155
+ ), s.position.set(this.app.screen.width / 2, this.app.screen.height / 2), r.position.set(this.app.screen.width / 2, this.app.screen.height / 2), t.width = n * Math.sqrt(2), t.height = t.width, i.width = n * 0.8, i.height = i.width, s.width = n * 0.5, s.height = s.width, r.width = n * 0.25, r.height = r.width, this.curContainer.time += e * this.flowSpeed, t.rotation += e / 1e3 * this.flowSpeed, i.rotation -= e / 500 * this.flowSpeed, s.rotation += e / 1e3 * this.flowSpeed, r.rotation -= e / 750 * this.flowSpeed, s.x = this.app.screen.width / 2 + this.app.screen.width / 4 * Math.cos(this.curContainer.time / 1e3 * 0.75), s.y = this.app.screen.height / 2 + this.app.screen.width / 4 * Math.cos(this.curContainer.time / 1e3 * 0.75), r.x = this.app.screen.width / 2 + this.app.screen.width / 4 * 0.1 + Math.cos(this.curContainer.time * 6e-3 * 0.75), r.y = this.app.screen.height / 2 + this.app.screen.width / 4 * 0.1 + Math.cos(this.curContainer.time * 6e-3 * 0.75), this.curContainer.alpha >= 1 && this.lastContainer.size === 0 && this.staticMode && this.app.ticker.stop();
154
156
  }
155
157
  };
156
158
  flowSpeed = 2;
@@ -177,12 +179,45 @@ class k {
177
179
  ), this.rebuildFilters();
178
180
  }
179
181
  rebuildFilters() {
180
- const e = Math.min(this.canvas.width, this.canvas.height), t = new E();
181
- t.saturate(1.2, !1);
182
- const i = new E();
183
- i.brightness(0.6, !1);
184
- const n = new E();
185
- n.contrast(0.3, !0), this.app.stage.filters = [], this.app.stage.filters.push(new y(5, 1)), this.app.stage.filters.push(new y(10, 1)), this.app.stage.filters.push(new y(20, 2)), this.app.stage.filters.push(new y(40, 2)), e > 512 && this.app.stage.filters.push(new y(80, 2)), e > 768 && this.app.stage.filters.push(new y(160, 4)), e > 768 * 2 && this.app.stage.filters.push(new y(320, 4)), this.app.stage.filters.push(t, i, n), this.app.stage.filters.push(new y(5, 1));
182
+ const e = Math.min(this.canvas.width, this.canvas.height), t = Math.max(this.canvas.width, this.canvas.height), i = new v();
183
+ i.saturate(1.2, !1);
184
+ const s = new v();
185
+ s.brightness(0.6, !1);
186
+ const r = new v();
187
+ r.contrast(0.3, !0), this.app.stage.filters?.forEach((n) => {
188
+ n.destroy();
189
+ }), this.app.stage.filters = [], this.app.stage.filters.push(new y(5, 1)), this.app.stage.filters.push(new y(10, 1)), this.app.stage.filters.push(new y(20, 2)), this.app.stage.filters.push(new y(40, 2)), this.app.stage.filters.push(new y(80, 2)), e > 768 && this.app.stage.filters.push(new y(160, 4)), e > 768 * 2 && this.app.stage.filters.push(new y(320, 4)), this.app.stage.filters.push(i, s, r), this.app.stage.filters.push(new y(5, 1)), Math.random() > 0.5 ? (this.app.stage.filters.push(
190
+ new E({
191
+ radius: (t + e) / 2,
192
+ strength: 1,
193
+ center: [0.25, 1]
194
+ })
195
+ ), this.app.stage.filters.push(
196
+ new E({
197
+ radius: (t + e) / 2,
198
+ strength: 1,
199
+ center: [0.75, 0]
200
+ })
201
+ )) : (this.app.stage.filters.push(
202
+ new E({
203
+ radius: (t + e) / 2,
204
+ strength: 1,
205
+ center: [0.75, 1]
206
+ })
207
+ ), this.app.stage.filters.push(
208
+ new E({
209
+ radius: (t + e) / 2,
210
+ strength: 1,
211
+ center: [0.25, 0]
212
+ })
213
+ ));
214
+ }
215
+ /**
216
+ * 是否启用静态模式,即图片在更换后就会保持静止状态并禁用更新,以节省性能
217
+ * @param enable 是否启用静态模式
218
+ */
219
+ setStaticMode(e = !1) {
220
+ this.staticMode = e, this.app.ticker.start();
186
221
  }
187
222
  /**
188
223
  * 修改背景动画帧率,默认是 30 FPS
@@ -210,14 +245,33 @@ class k {
210
245
  * @param albumUrl 图片的目标链接
211
246
  */
212
247
  async setAlbumImage(e) {
213
- const t = await C.fromURL(e), i = new B(), n = new L(t), a = new L(t), s = new L(t), r = new L(t);
214
- n.anchor.set(0.5, 0.5), a.anchor.set(0.5, 0.5), s.anchor.set(0.5, 0.5), r.anchor.set(0.5, 0.5), n.rotation = Math.random() * Math.PI * 2, a.rotation = Math.random() * Math.PI * 2, s.rotation = Math.random() * Math.PI * 2, r.rotation = Math.random() * Math.PI * 2, i.addChild(n, a, s, r), this.curContainer && this.lastContainer.add(this.curContainer), this.curContainer = i, this.app.stage.addChild(this.curContainer), this.curContainer.alpha = 0;
248
+ const t = new Image();
249
+ t.src = e, t.crossOrigin = "anonymous";
250
+ let i = 5, s;
251
+ for (; !s?.baseTexture?.resource?.valid && i > 0; )
252
+ try {
253
+ await t.decode(), s = A.from(t, {
254
+ resourceOptions: {
255
+ autoLoad: !1
256
+ }
257
+ }), await s.baseTexture.resource.load();
258
+ } catch (c) {
259
+ console.warn(
260
+ `failed on loading album image, retrying (${i})`,
261
+ e,
262
+ c
263
+ ), s = void 0, i--;
264
+ }
265
+ if (!s)
266
+ return;
267
+ const r = new O(), n = new S(s), a = new S(s), l = new S(s), o = new S(s);
268
+ n.anchor.set(0.5, 0.5), a.anchor.set(0.5, 0.5), l.anchor.set(0.5, 0.5), o.anchor.set(0.5, 0.5), n.rotation = Math.random() * Math.PI * 2, a.rotation = Math.random() * Math.PI * 2, l.rotation = Math.random() * Math.PI * 2, o.rotation = Math.random() * Math.PI * 2, r.addChild(n, a, l, o), this.curContainer && this.lastContainer.add(this.curContainer), this.curContainer = r, this.app.stage.addChild(this.curContainer), this.curContainer.alpha = 0, this.app.ticker.start();
215
269
  }
216
270
  dispose() {
217
- this.observer.disconnect(), this.app.ticker.remove(this.onTick);
271
+ this.observer.disconnect(), this.app.ticker.remove(this.onTick), this.app.destroy(!0);
218
272
  }
219
273
  }
220
- class Z extends k {
274
+ class oe extends $ {
221
275
  element;
222
276
  constructor() {
223
277
  const e = document.createElement("canvas");
@@ -230,88 +284,8 @@ class Z extends k {
230
284
  super.dispose(), this.element.remove();
231
285
  }
232
286
  }
233
- const N = (d, e) => d.size === e.size && [...d].every((t) => e.has(t));
234
- function O(d) {
235
- const t = 2.5949095;
236
- return d < 0.5 ? Math.pow(2 * d, 2) * ((t + 1) * 2 * d - t) / 2 : (Math.pow(2 * d - 2, 2) * ((t + 1) * (d * 2 - 2) + t) + 2) / 2;
237
- }
238
- const g = (d, e, t) => Math.max(d, Math.min(e, t));
239
- class $ {
240
- constructor(e) {
241
- this.lyricPlayer = e, this.element.className = this.lyricPlayer.style.classes.interludeDots, this.element.appendChild(this.dot0), this.element.appendChild(this.dot1), this.element.appendChild(this.dot2);
242
- }
243
- element = document.createElement("div");
244
- dot0 = document.createElement("span");
245
- dot1 = document.createElement("span");
246
- dot2 = document.createElement("span");
247
- left = 0;
248
- top = 0;
249
- scale = 1;
250
- lastStyle = "";
251
- currentInterlude;
252
- currentTime = 0;
253
- targetBreatheDuration = 1500;
254
- getElement() {
255
- return this.element;
256
- }
257
- setTransform(e = this.left, t = this.top) {
258
- this.left = e, this.top = t, this.update();
259
- }
260
- setInterlude(e) {
261
- this.currentInterlude = e, this.currentTime = e?.[0] ?? 0;
262
- }
263
- update(e = 0) {
264
- this.currentTime += e;
265
- let t = "";
266
- if (t += `transform:translate(${this.left}px, ${this.top}px)`, this.currentInterlude) {
267
- const i = this.currentInterlude[1] - this.currentInterlude[0], n = this.currentTime - this.currentInterlude[0];
268
- if (n <= i) {
269
- const a = i / Math.ceil(i / this.targetBreatheDuration);
270
- let s = 1, r = 1;
271
- s *= Math.sin(1.5 * Math.PI - n / a * 2) / 10 + 1, n < 1e3 && (s *= 1 - Math.pow((1e3 - n) / 1e3, 2)), n < 500 ? r = 0 : n < 1e3 && (r *= (n - 500) / 500), i - n < 750 && (s *= 1 - O(
272
- (750 - (i - n)) / 750 / 2
273
- )), i - n < 375 && (r *= g(
274
- 0,
275
- (i - n) / 375,
276
- 1
277
- )), s = Math.max(0, s), t += ` scale(${s})`;
278
- const l = g(
279
- 0.25,
280
- n * 3 / i * 0.75,
281
- 1
282
- ), h = g(
283
- 0.25,
284
- (n - i / 3) * 3 / i * 0.75,
285
- 1
286
- ), o = g(
287
- 0.25,
288
- (n - i / 3 * 2) * 3 / i * 0.75,
289
- 1
290
- );
291
- this.dot0.style.opacity = `${g(
292
- 0,
293
- Math.max(0, r * l),
294
- 1
295
- )}`, this.dot1.style.opacity = `${g(
296
- 0,
297
- Math.max(0, r * h),
298
- 1
299
- )}`, this.dot2.style.opacity = `${g(
300
- 0,
301
- Math.max(0, r * o),
302
- 1
303
- )}`;
304
- } else
305
- t += " scale(0)", this.dot0.style.opacity = "0", this.dot1.style.opacity = "0", this.dot2.style.opacity = "0";
306
- } else
307
- t += " scale(0)", this.dot0.style.opacity = "0", this.dot1.style.opacity = "0", this.dot2.style.opacity = "0";
308
- t += ";", this.lastStyle !== t && (this.element.setAttribute("style", t), this.lastStyle = t);
309
- }
310
- dispose() {
311
- this.element.remove();
312
- }
313
- }
314
- class S {
287
+ const W = (h, e) => h.size === e.size && [...h].every((t) => e.has(t));
288
+ class w {
315
289
  currentPosition = 0;
316
290
  targetPosition = 0;
317
291
  currentTime = 0;
@@ -325,7 +299,7 @@ class S {
325
299
  }
326
300
  resetSolver() {
327
301
  const e = this.getV(this.currentTime);
328
- this.currentTime = 0, this.currentSolver = q(
302
+ this.currentTime = 0, this.currentSolver = N(
329
303
  this.currentPosition,
330
304
  e,
331
305
  this.targetPosition,
@@ -363,37 +337,189 @@ class S {
363
337
  return this.currentPosition;
364
338
  }
365
339
  }
366
- function q(d, e, t, i = 0, n) {
367
- const a = n?.soft ?? !1, s = n?.stiffness ?? 100, r = n?.damping ?? 10, l = n?.mass ?? 1, h = t - d;
368
- if (a || 1 <= r / (2 * Math.sqrt(s * l))) {
369
- const o = -Math.sqrt(s / l), c = -o * h - e;
370
- return (m) => (m -= i, m < 0 ? d : t - (h + m * c) * Math.E ** (m * o));
340
+ function N(h, e, t, i = 0, s) {
341
+ const r = s?.soft ?? !1, n = s?.stiffness ?? 100, a = s?.damping ?? 10, l = s?.mass ?? 1, o = t - h;
342
+ if (r || 1 <= a / (2 * Math.sqrt(n * l))) {
343
+ const c = -Math.sqrt(n / l), m = -c * o - e;
344
+ return (u) => (u -= i, u < 0 ? h : t - (o + u * m) * Math.E ** (u * c));
371
345
  } else {
372
- const o = Math.sqrt(
373
- 4 * l * s - r ** 2
374
- ), c = (r * h - 2 * l * e) / o, m = 0.5 * o / l, p = -(0.5 * r) / l;
375
- return (u) => (u -= i, u < 0 ? d : t - (Math.cos(u * m) * h + Math.sin(u * m) * c) * Math.E ** (u * p));
346
+ const c = Math.sqrt(
347
+ 4 * l * n - a ** 2
348
+ ), m = (a * o - 2 * l * e) / c, u = 0.5 * c / l, f = -(0.5 * a) / l;
349
+ return (p) => (p -= i, p < 0 ? h : t - (Math.cos(p * u) * o + Math.sin(p * u) * m) * Math.E ** (p * f));
376
350
  }
377
351
  }
378
- function F(d) {
379
- return (t) => (d(t + 1e-3) - d(t - 1e-3)) / (2 * 1e-3);
352
+ function F(h) {
353
+ return (t) => (h(t + 1e-3) - h(t - 1e-3)) / (2 * 1e-3);
380
354
  }
381
- function R(d) {
382
- return F(d);
355
+ function R(h) {
356
+ return F(h);
383
357
  }
384
- const w = /^[\p{Unified_Ideograph}\u0800-\u9FFC]+$/u;
385
- function W(d, e = "rgba(0,0,0,1)", t = "rgba(0,0,0,0.5)") {
386
- const i = 2 + d, n = d / i, a = (1 - n) / 2;
358
+ class q {
359
+ constructor(e) {
360
+ this.lyricPlayer = e, this.element.setAttribute(
361
+ "class",
362
+ this.lyricPlayer.style.classes.lyricLine
363
+ ), this.rebuildStyle();
364
+ }
365
+ element = document.createElement("div");
366
+ left = 0;
367
+ top = 0;
368
+ delay = 0;
369
+ // 由 LyricPlayer 来设置
370
+ lineSize = [0, 0];
371
+ lineTransforms = {
372
+ posX: new w(0),
373
+ posY: new w(0)
374
+ };
375
+ measureSize() {
376
+ return [
377
+ this.element.clientWidth,
378
+ this.element.clientHeight
379
+ ];
380
+ }
381
+ lastStyle = "";
382
+ show() {
383
+ this.rebuildStyle();
384
+ }
385
+ hide() {
386
+ this.rebuildStyle();
387
+ }
388
+ rebuildStyle() {
389
+ let e = `transform:translate(${this.lineTransforms.posX.getCurrentPosition()}px,${this.lineTransforms.posY.getCurrentPosition()}px);`;
390
+ !this.lyricPlayer.getEnableSpring() && this.isInSight && (e += `transition-delay:${this.delay}ms;`), e !== this.lastStyle && (this.lastStyle = e, this.element.setAttribute("style", e));
391
+ }
392
+ getElement() {
393
+ return this.element;
394
+ }
395
+ setTransform(e = this.left, t = this.top, i = !1, s = 0) {
396
+ this.left = e, this.top = t, this.delay = s * 1e3 | 0, i || !this.lyricPlayer.getEnableSpring() ? (i && this.element.classList.add(
397
+ this.lyricPlayer.style.classes.tmpDisableTransition
398
+ ), this.lineTransforms.posX.setPosition(e), this.lineTransforms.posY.setPosition(t), this.lyricPlayer.getEnableSpring() ? this.rebuildStyle() : this.show(), i && requestAnimationFrame(() => {
399
+ this.element.classList.remove(
400
+ this.lyricPlayer.style.classes.tmpDisableTransition
401
+ );
402
+ })) : (this.lineTransforms.posX.setTargetPosition(e, s), this.lineTransforms.posY.setTargetPosition(t, s));
403
+ }
404
+ update(e = 0) {
405
+ this.lyricPlayer.getEnableSpring() && (this.lineTransforms.posX.update(e), this.lineTransforms.posY.update(e), this.isInSight ? this.show() : this.hide());
406
+ }
407
+ get isInSight() {
408
+ const e = this.lineTransforms.posX.getCurrentPosition(), t = this.lineTransforms.posY.getCurrentPosition(), i = e + this.lineSize[0], s = t + this.lineSize[1], r = this.lyricPlayer.size[0], n = this.lyricPlayer.size[1];
409
+ return !(e > r || t > n || i < 0 || s < 0);
410
+ }
411
+ dispose() {
412
+ this.element.remove();
413
+ }
414
+ }
415
+ function X(h) {
416
+ const t = 2.5949095;
417
+ return h < 0.5 ? Math.pow(2 * h, 2) * ((t + 1) * 2 * h - t) / 2 : (Math.pow(2 * h - 2, 2) * ((t + 1) * (h * 2 - 2) + t) + 2) / 2;
418
+ }
419
+ const L = (h, e, t) => Math.max(h, Math.min(e, t));
420
+ class Y {
421
+ constructor(e) {
422
+ this.lyricPlayer = e, this.element.className = this.lyricPlayer.style.classes.interludeDots, this.element.appendChild(this.dot0), this.element.appendChild(this.dot1), this.element.appendChild(this.dot2);
423
+ }
424
+ element = document.createElement("div");
425
+ dot0 = document.createElement("span");
426
+ dot1 = document.createElement("span");
427
+ dot2 = document.createElement("span");
428
+ left = 0;
429
+ top = 0;
430
+ scale = 1;
431
+ lastStyle = "";
432
+ currentInterlude;
433
+ currentTime = 0;
434
+ targetBreatheDuration = 1500;
435
+ getElement() {
436
+ return this.element;
437
+ }
438
+ setTransform(e = this.left, t = this.top) {
439
+ this.left = e, this.top = t, this.update();
440
+ }
441
+ setInterlude(e) {
442
+ this.currentInterlude = e, this.currentTime = e?.[0] ?? 0;
443
+ }
444
+ update(e = 0) {
445
+ this.currentTime += e;
446
+ let t = "";
447
+ if (t += `transform:translate(${this.left}px, ${this.top}px)`, this.currentInterlude) {
448
+ const i = this.currentInterlude[1] - this.currentInterlude[0], s = this.currentTime - this.currentInterlude[0];
449
+ if (s <= i) {
450
+ const r = i / Math.ceil(i / this.targetBreatheDuration);
451
+ let n = 1, a = 1;
452
+ n *= Math.sin(1.5 * Math.PI - s / r * 2) / 10 + 1, s < 1e3 && (n *= 1 - Math.pow((1e3 - s) / 1e3, 2)), s < 500 ? a = 0 : s < 1e3 && (a *= (s - 500) / 500), i - s < 750 && (n *= 1 - X(
453
+ (750 - (i - s)) / 750 / 2
454
+ )), i - s < 375 && (a *= L(
455
+ 0,
456
+ (i - s) / 375,
457
+ 1
458
+ )), n = Math.max(0, n), t += ` scale(${n})`;
459
+ const l = L(
460
+ 0.25,
461
+ s * 3 / i * 0.75,
462
+ 1
463
+ ), o = L(
464
+ 0.25,
465
+ (s - i / 3) * 3 / i * 0.75,
466
+ 1
467
+ ), c = L(
468
+ 0.25,
469
+ (s - i / 3 * 2) * 3 / i * 0.75,
470
+ 1
471
+ );
472
+ this.dot0.style.opacity = `${L(
473
+ 0,
474
+ Math.max(0, a * l),
475
+ 1
476
+ )}`, this.dot1.style.opacity = `${L(
477
+ 0,
478
+ Math.max(0, a * o),
479
+ 1
480
+ )}`, this.dot2.style.opacity = `${L(
481
+ 0,
482
+ Math.max(0, a * c),
483
+ 1
484
+ )}`;
485
+ } else
486
+ t += " scale(0)", this.dot0.style.opacity = "0", this.dot1.style.opacity = "0", this.dot2.style.opacity = "0";
487
+ } else
488
+ t += " scale(0)", this.dot0.style.opacity = "0", this.dot1.style.opacity = "0", this.dot2.style.opacity = "0";
489
+ t += ";", this.lastStyle !== t && (this.element.setAttribute("style", t), this.lastStyle = t);
490
+ }
491
+ dispose() {
492
+ this.element.remove();
493
+ }
494
+ }
495
+ const _ = /^[\p{Unified_Ideograph}\u0800-\u9FFC]+$/u;
496
+ function G(h, e = "rgba(0,0,0,1)", t = "rgba(0,0,0,0.5)") {
497
+ const i = 2 + h, s = h / i, r = (1 - s) / 2;
387
498
  return [
388
- `linear-gradient(to right,${e} ${a * 100}%,${t} ${(a + n) * 100}%)`,
389
- n,
499
+ `linear-gradient(to right,${e} ${r * 100}%,${t} ${(r + s) * 100}%)`,
500
+ s,
390
501
  i
391
502
  ];
392
503
  }
393
- function P(d) {
394
- return d.endTime - d.startTime >= 1e3 && d.word.length <= 7;
504
+ function H(h, e) {
505
+ let t = [], i = [];
506
+ const s = [];
507
+ for (const r of h) {
508
+ const n = e(r);
509
+ t.push(n), i.push(r), n.length > 0 && n.trim().length === 0 ? (t.pop(), i.pop(), i.length === 1 ? s.push(i[0]) : i.length > 1 && s.push(i), s.push(r), t = [], i = []) : (!/^\s*[^\s]*\s*$/.test(t.join("")) || _.test(n)) && (t.pop(), i.pop(), i.length === 1 ? s.push(i[0]) : i.length > 1 && s.push(i), t = [n], i = [r]);
510
+ }
511
+ return i.length === 1 ? s.push(i[0]) : s.push(i), s;
512
+ }
513
+ function x(h) {
514
+ return h.endTime - h.startTime >= 1e3 && h.word.length <= 7;
395
515
  }
396
- class _ {
516
+ class V extends MouseEvent {
517
+ constructor(e, t) {
518
+ super(t.type, t), this.line = e;
519
+ }
520
+ }
521
+ class j extends EventTarget {
522
+ // rome-ignore lint/correctness/noUnreachableSuper: <explanation>
397
523
  constructor(e, t = {
398
524
  words: [],
399
525
  translatedLyric: "",
@@ -403,12 +529,12 @@ class _ {
403
529
  isBG: !1,
404
530
  isDuet: !1
405
531
  }) {
406
- this.lyricPlayer = e, this.lyricLine = t, this.element.setAttribute(
532
+ super(), this.lyricPlayer = e, this.lyricLine = t, this.element.setAttribute(
407
533
  "class",
408
534
  this.lyricPlayer.style.classes.lyricLine
409
535
  ), this.lyricLine.isBG && this.element.classList.add(this.lyricPlayer.style.classes.lyricBgLine), this.lyricLine.isDuet && this.element.classList.add(this.lyricPlayer.style.classes.lyricDuetLine), this.element.appendChild(document.createElement("div")), this.element.appendChild(document.createElement("div")), this.element.appendChild(document.createElement("div"));
410
- const i = this.element.children[0], n = this.element.children[1], a = this.element.children[2];
411
- i.setAttribute("class", this.lyricPlayer.style.classes.lyricMainLine), n.setAttribute("class", this.lyricPlayer.style.classes.lyricSubLine), a.setAttribute("class", this.lyricPlayer.style.classes.lyricSubLine), this.rebuildElement(), this.rebuildStyle();
536
+ const i = this.element.children[0], s = this.element.children[1], r = this.element.children[2];
537
+ i.setAttribute("class", this.lyricPlayer.style.classes.lyricMainLine), s.setAttribute("class", this.lyricPlayer.style.classes.lyricSubLine), r.setAttribute("class", this.lyricPlayer.style.classes.lyricSubLine), this.rebuildElement(), this.rebuildStyle();
412
538
  }
413
539
  element = document.createElement("div");
414
540
  left = 0;
@@ -420,10 +546,27 @@ class _ {
420
546
  // 由 LyricPlayer 来设置
421
547
  lineSize = [0, 0];
422
548
  lineTransforms = {
423
- posX: new S(0),
424
- posY: new S(0),
425
- scale: new S(1)
549
+ posX: new w(0),
550
+ posY: new w(0),
551
+ scale: new w(1)
426
552
  };
553
+ listenersMap = /* @__PURE__ */ new Map();
554
+ onMouseEvent = (e) => {
555
+ if (!this.dispatchEvent(new V(this, e)))
556
+ return e.preventDefault(), e.stopPropagation(), e.stopImmediatePropagation(), !1;
557
+ };
558
+ addEventListener(e, t, i) {
559
+ if (super.addEventListener(e, t, i), t) {
560
+ const s = this.listenersMap.get(e) ?? /* @__PURE__ */ new Set();
561
+ s.size === 0 && this.element.addEventListener(e, this.onMouseEvent), s.add(t), this.listenersMap.set(e, s);
562
+ }
563
+ }
564
+ removeEventListener(e, t, i) {
565
+ if (super.removeEventListener(e, t, i), t) {
566
+ const s = this.listenersMap.get(e);
567
+ s && (s.delete(t), s.size === 0 && this.element.removeEventListener(e, this.onMouseEvent));
568
+ }
569
+ }
427
570
  isEnabled = !1;
428
571
  enable() {
429
572
  this.isEnabled = !0, this.element.classList.add("active");
@@ -480,77 +623,83 @@ class _ {
480
623
  }
481
624
  rebuildElement() {
482
625
  const e = this.element.children[0], t = this.element.children[1], i = this.element.children[2];
483
- this.splittedWords = [], this.lyricLine.words.forEach((l) => {
484
- const h = l.word.split(/\s+/), o = h.reduce((m, p) => m + p.length, 0);
485
- let c = 0;
486
- h.forEach((m, p) => {
487
- p > 0 && this.splittedWords.push({
488
- word: " ",
489
- startTime: 0,
490
- endTime: 0,
491
- width: 0,
492
- height: 0,
493
- elements: [],
494
- elementAnimations: [],
495
- shouldEmphasize: !1
496
- }), this.splittedWords.push({
497
- word: m,
498
- startTime: l.startTime + (l.endTime - l.startTime) / o * c,
499
- endTime: l.startTime + (l.endTime - l.startTime) / o * (c + m.length),
500
- width: 0,
501
- height: 0,
502
- elements: [],
503
- elementAnimations: [],
504
- shouldEmphasize: P(l)
505
- }), c += m.length;
506
- });
507
- });
508
- const n = [], a = [];
509
- function s(l) {
510
- for (; l.firstChild; )
511
- l.firstChild.nodeType === Node.ELEMENT_NODE ? n.push(e.firstChild) : l.firstChild.nodeType === Node.TEXT_NODE && a.push(e.firstChild), l.removeChild(l.firstChild), s(l.firstChild);
626
+ if (this.lyricPlayer._getIsNonDynamic()) {
627
+ e.innerText = this.lyricLine.words.map((r) => r.word).join(""), t.innerText = this.lyricLine.translatedLyric, i.innerText = this.lyricLine.romanLyric;
628
+ return;
512
629
  }
513
- s(e);
514
- let r = null;
515
- this.splittedWords.forEach((l) => {
516
- if (l.word.trim().length > 0)
517
- if (l.shouldEmphasize) {
518
- const h = n.pop() ?? document.createElement("span");
519
- h.className = "emphasize", l.elements = [h];
520
- for (const o of l.word) {
521
- const c = n.pop() ?? document.createElement("span");
522
- c.className = "", c.innerText = o, h.appendChild(c), l.elements.push(c);
523
- }
524
- if (l.elementAnimations = this.initEmphasizeAnimation(l), console.log(l.word, w.test(l.word)), r && !w.test(l.word))
525
- if (r.childElementCount > 0)
526
- r.appendChild(h);
527
- else {
528
- const o = n.pop() ?? document.createElement("span");
529
- o.className = "", r.remove(), o.appendChild(r), o.appendChild(h), e.appendChild(o), r = o;
530
- }
531
- else
532
- r = w.test(l.word) ? null : h, e.appendChild(h);
533
- } else {
534
- const h = n.pop() ?? document.createElement("span");
535
- if (h.className = "", h.innerText = l.word, l.elements = [h], l.elementAnimations.push(this.initFloatAnimation(l, h)), r)
536
- if (r.childElementCount > 0)
537
- r.appendChild(h);
538
- else {
539
- const o = n.pop() ?? document.createElement("span");
540
- o.className = "", r.remove(), o.appendChild(r), o.appendChild(h), e.appendChild(o), r = o;
630
+ const s = H(this.lyricLine.words, (r) => r.word);
631
+ e.innerHTML = "", this.splittedWords = [];
632
+ for (const r of s)
633
+ if (r instanceof Array) {
634
+ const n = r.map((o) => x(o)).reduce((o, c) => o || c, !1), a = r.reduce(
635
+ (o, c) => (o.endTime = Math.max(o.endTime, c.endTime), o.startTime = Math.min(o.startTime, c.startTime), o.word += c.word, o),
636
+ { word: "", startTime: 1 / 0, endTime: -1 / 0 }
637
+ ), l = document.createElement("span");
638
+ for (const o of r) {
639
+ const c = document.createElement("span"), m = this.initFloatAnimation(
640
+ a,
641
+ c
642
+ );
643
+ if (n) {
644
+ const u = [];
645
+ for (const p of o.word.trim().split("")) {
646
+ const d = document.createElement("span");
647
+ d.innerText = p, u.push(d), c.appendChild(d);
541
648
  }
542
- else
543
- r = h, e.appendChild(h);
649
+ const f = {
650
+ ...o,
651
+ mainElement: c,
652
+ subElements: u,
653
+ elementAnimations: [m],
654
+ width: 0,
655
+ height: 0,
656
+ shouldEmphasize: n
657
+ };
658
+ f.elementAnimations.push(
659
+ ...this.initEmphasizeAnimation(f)
660
+ ), this.splittedWords.push(f);
661
+ } else
662
+ c.innerText = o.word, this.splittedWords.push({
663
+ ...o,
664
+ mainElement: c,
665
+ subElements: [],
666
+ elementAnimations: [m],
667
+ width: 0,
668
+ height: 0,
669
+ shouldEmphasize: n
670
+ });
671
+ l.appendChild(c);
544
672
  }
545
- else if (l.word.length > 0) {
546
- const h = a.pop() ?? document.createTextNode(" ");
547
- e.appendChild(h), r = null;
548
- } else
549
- r = null;
550
- }), t.innerText = this.lyricLine.translatedLyric, i.innerText = this.lyricLine.romanLyric;
673
+ a.word.trimStart() !== a.word && e.appendChild(document.createTextNode(" ")), e.appendChild(l), a.word.trimEnd() !== a.word && e.appendChild(document.createTextNode(" "));
674
+ } else if (r.word.trim().length === 0)
675
+ e.appendChild(document.createTextNode(" "));
676
+ else {
677
+ const n = x(r), a = document.createElement("span"), l = {
678
+ ...r,
679
+ mainElement: a,
680
+ subElements: [],
681
+ elementAnimations: [this.initFloatAnimation(r, a)],
682
+ width: 0,
683
+ height: 0,
684
+ shouldEmphasize: n
685
+ };
686
+ if (n) {
687
+ const o = [];
688
+ for (const c of r.word.trim().split("")) {
689
+ const m = document.createElement("span");
690
+ m.innerText = c, o.push(m), a.appendChild(m);
691
+ }
692
+ l.subElements = o, l.elementAnimations.push(
693
+ ...this.initEmphasizeAnimation(l)
694
+ );
695
+ } else
696
+ a.innerText = r.word.trim();
697
+ r.word.trimStart() !== r.word && e.appendChild(document.createTextNode(" ")), e.appendChild(a), r.word.trimEnd() !== r.word && e.appendChild(document.createTextNode(" ")), this.splittedWords.push(l);
698
+ }
699
+ t.innerText = this.lyricLine.translatedLyric, i.innerText = this.lyricLine.romanLyric;
551
700
  }
552
701
  initFloatAnimation(e, t) {
553
- const i = e.startTime - this.lyricLine.startTime, n = Math.max(1e3, e.endTime - e.startTime), a = t.animate(
702
+ const i = e.startTime - this.lyricLine.startTime, s = Math.max(1e3, e.endTime - e.startTime), r = t.animate(
554
703
  [
555
704
  {
556
705
  transform: "translateY(0px)"
@@ -560,107 +709,128 @@ class _ {
560
709
  }
561
710
  ],
562
711
  {
563
- duration: isFinite(n) ? n : 0,
712
+ duration: isFinite(s) ? s : 0,
564
713
  delay: isFinite(i) ? i : 0,
565
714
  id: "float-word",
566
715
  composite: "add",
567
716
  fill: "both"
568
717
  }
569
718
  );
570
- return a.pause(), a;
719
+ return r.pause(), r;
571
720
  }
572
721
  initEmphasizeAnimation(e) {
573
722
  const t = e.startTime - this.lyricLine.startTime, i = e.endTime - e.startTime;
574
- return e.elements.map((n, a, s) => {
575
- if (a === 0)
576
- return this.initFloatAnimation(e, n);
577
- {
578
- const r = n.animate(
579
- [
580
- {
581
- offset: 0,
582
- transform: "translate3d(0, 0px, 0px)",
583
- filter: "drop-shadow(0 0 0 var(--amll-lyric-line-color))"
584
- },
585
- {
586
- offset: 0.5,
587
- transform: "translate3d(0, -2%, 20px)",
588
- filter: "drop-shadow(0 0 0.2rem var(--amll-lyric-line-color))"
589
- },
590
- {
591
- offset: 1,
592
- transform: "translate3d(0, 0px, 0)",
593
- filter: "drop-shadow(0 0 0 var(--amll-lyric-line-color))"
594
- }
595
- ],
723
+ return e.subElements.map((s, r, n) => {
724
+ const a = Math.max(1e3, e.endTime - e.startTime), l = t + i / n.length * r, o = s.animate(
725
+ [
726
+ {
727
+ offset: 0,
728
+ transform: "translate3d(0, 0, 0px)",
729
+ filter: "drop-shadow(0 0 0 var(--amll-lyric-view-color,white))"
730
+ },
731
+ {
732
+ offset: 0.5,
733
+ transform: "translate3d(0, -2%, 20px)",
734
+ filter: "drop-shadow(0 0 0.05em var(--amll-lyric-view-color,white))"
735
+ },
596
736
  {
597
- duration: Math.max(1e3, e.endTime - e.startTime),
598
- delay: t + i / (s.length - 1) * (a - 1),
599
- id: "glow-word",
600
- iterations: 1,
601
- composite: "replace",
602
- fill: "both"
737
+ offset: 1,
738
+ transform: "translate3d(0, 0, 0)",
739
+ filter: "drop-shadow(0 0 0 var(--amll-lyric-view-color,white))"
603
740
  }
604
- );
605
- return r.pause(), r;
606
- }
741
+ ],
742
+ {
743
+ duration: isFinite(a) ? a : 0,
744
+ delay: isFinite(l) ? l : 0,
745
+ id: "glow-word",
746
+ iterations: 1,
747
+ composite: "replace",
748
+ fill: "both"
749
+ }
750
+ );
751
+ return o.pause(), o;
607
752
  });
608
753
  }
609
754
  updateMaskImage() {
610
755
  this._hide && (this.element.style.display = "", this.element.style.visibility = "hidden"), this.splittedWords.forEach((e) => {
611
- const t = e.elements[0];
756
+ const t = e.mainElement;
612
757
  if (t) {
613
758
  e.width = t.clientWidth, e.height = t.clientHeight;
614
- const [i, n, a] = W(
615
- 16 / e.width,
616
- "rgba(0,0,0,0.75)",
759
+ const i = e.height / 2, [s, r, n] = G(
760
+ i / e.width,
761
+ "rgba(0,0,0,1)",
617
762
  "rgba(0,0,0,0.25)"
618
- ), s = `${a * 100}% 100%`;
619
- this.lyricPlayer.supportMaskImage ? (t.style.maskImage = i, t.style.maskOrigin = "left", t.style.maskSize = s) : (t.style.webkitMaskImage = i, t.style.webkitMaskOrigin = "left", t.style.webkitMaskSize = s);
620
- const r = e.width + 16, l = `clamp(${-r}px,calc(${-r}px + (var(--amll-player-time) - ${e.startTime})*${r / Math.abs(e.endTime - e.startTime)}px),0px) 0px, left top`;
621
- t.style.maskPosition = l, t.style.webkitMaskPosition = l;
763
+ ), a = `${n * 100}% 100%`;
764
+ this.lyricPlayer.supportMaskImage ? (t.style.maskImage = s, t.style.maskOrigin = "left", t.style.maskSize = a) : (t.style.webkitMaskImage = s, t.style.webkitMaskOrigin = "left", t.style.webkitMaskSize = a);
765
+ const l = e.width + i, o = `clamp(${-l}px,calc(${-l}px + (var(--amll-player-time) - ${e.startTime})*${l / Math.abs(e.endTime - e.startTime)}px),0px) 0px, left top`;
766
+ t.style.maskPosition = o, t.style.webkitMaskPosition = o;
622
767
  }
623
768
  }), this._hide && (this.element.style.display = "none", this.element.style.visibility = "");
624
769
  }
625
770
  getElement() {
626
771
  return this.element;
627
772
  }
628
- setTransform(e = this.left, t = this.top, i = this.scale, n = 1, a = 0, s = !1, r = 0) {
629
- this.left = e, this.top = t, this.scale = i, this.delay = r * 1e3 | 0;
630
- const l = this.element.children[0];
631
- l.style.opacity = `${n}`, s || !this.lyricPlayer.getEnableSpring() ? (this.blur = Math.min(32, a), s && this.element.classList.add(
632
- this.lyricPlayer.style.classes.tmpDisableTransition
633
- ), this.lineTransforms.posX.setPosition(e), this.lineTransforms.posY.setPosition(t), this.lineTransforms.scale.setPosition(i), this.lyricPlayer.getEnableSpring() ? this.rebuildStyle() : this.show(), s && requestAnimationFrame(() => {
634
- this.element.classList.remove(
773
+ setTransform(e = this.left, t = this.top, i = this.scale, s = 1, r = 0, n = !1, a = 0) {
774
+ const l = this.isInSight, o = this.lyricPlayer.getEnableSpring();
775
+ this.left = e, this.top = t, this.scale = i, this.delay = a * 1e3 | 0;
776
+ const c = this.element.children[0], m = this.element.children[1], u = this.element.children[2];
777
+ if (c.style.opacity = `${s}`, m.style.opacity = `${s / 2}`, u.style.opacity = `${s / 2}`, n || !o) {
778
+ if (this.blur = Math.min(32, r), n && this.element.classList.add(
635
779
  this.lyricPlayer.style.classes.tmpDisableTransition
636
- );
637
- })) : (this.lineTransforms.posX.setTargetPosition(e, r), this.lineTransforms.posY.setTargetPosition(t, r), this.lineTransforms.scale.setTargetPosition(i), this.blur !== Math.min(32, a) && (this.blur = Math.min(32, a), this.element.style.filter = `blur(${Math.min(32, a)}px)`));
780
+ ), this.lineTransforms.posX.setPosition(e), this.lineTransforms.posY.setPosition(t), this.lineTransforms.scale.setPosition(i), o)
781
+ this.rebuildStyle();
782
+ else {
783
+ const f = this.isInSight;
784
+ l || f ? this.show() : this.hide();
785
+ }
786
+ n && requestAnimationFrame(() => {
787
+ this.element.classList.remove(
788
+ this.lyricPlayer.style.classes.tmpDisableTransition
789
+ );
790
+ });
791
+ } else
792
+ this.lineTransforms.posX.setTargetPosition(e, a), this.lineTransforms.posY.setTargetPosition(t, a), this.lineTransforms.scale.setTargetPosition(i), this.blur !== Math.min(32, r) && (this.blur = Math.min(32, r), this.element.style.filter = `blur(${Math.min(32, r)}px)`);
638
793
  }
639
794
  update(e = 0) {
640
795
  this.lyricPlayer.getEnableSpring() && (this.lineTransforms.posX.update(e), this.lineTransforms.posY.update(e), this.lineTransforms.scale.update(e), this.isInSight ? this.show() : this.hide());
641
796
  }
642
797
  get isInSight() {
643
- const e = this.lineTransforms.posX.getCurrentPosition(), t = this.lineTransforms.posY.getCurrentPosition(), i = e + this.lineSize[0], n = t + this.lineSize[1], a = this.lyricPlayer.pos[0], s = this.lyricPlayer.pos[1], r = this.lyricPlayer.pos[0] + this.lyricPlayer.size[0], l = this.lyricPlayer.pos[1] + this.lyricPlayer.size[1];
644
- return !(e > r || t > l || i < a || n < s);
798
+ const e = this.lineTransforms.posX.getCurrentPosition(), t = this.lineTransforms.posY.getCurrentPosition(), i = e + this.lineSize[0], s = t + this.lineSize[1], r = this.lyricPlayer.size[0], n = this.lyricPlayer.size[1];
799
+ return !(e > r || i < 0 || t > n || s < 0);
645
800
  }
646
801
  dispose() {
647
802
  this.element.remove();
648
803
  }
649
804
  }
650
- const G = z(A());
651
- class ee extends EventTarget {
805
+ const J = I(D());
806
+ class K extends MouseEvent {
807
+ constructor(e, t, i) {
808
+ super(`line-${i.type}`, i), this.lineIndex = e, this.line = t;
809
+ }
810
+ }
811
+ class le extends EventTarget {
652
812
  element = document.createElement("div");
653
813
  currentTime = 0;
654
814
  lyricLines = [];
655
815
  processedLines = [];
656
816
  lyricLinesEl = [];
657
- lyricLinesSize = /* @__PURE__ */ new Map();
817
+ lyricLinesSize = /* @__PURE__ */ new WeakMap();
818
+ lyricLinesIndexes = /* @__PURE__ */ new WeakMap();
658
819
  hotLines = /* @__PURE__ */ new Set();
659
820
  bufferedLines = /* @__PURE__ */ new Set();
660
821
  scrollToIndex = 0;
822
+ allowScroll = !0;
823
+ scrolledHandler = 0;
824
+ isScrolled = !1;
825
+ invokedByScrollEvent = !1;
826
+ padding = 32;
827
+ scrollOffset = 0;
828
+ hidePassedLines = !1;
661
829
  resizeObserver = new ResizeObserver((e) => {
662
830
  const t = e[0].contentRect;
663
- this.size[0] = t.width, this.size[1] = t.height, this.pos[0] = t.left, this.pos[1] = t.top, this.rebuildStyle(), this.calcLayout(!0), this.lyricLinesEl.forEach((i) => i.updateMaskImage());
831
+ this.size[0] = t.width, this.size[1] = t.height;
832
+ const i = getComputedStyle(e[0].target), s = this.element.clientWidth - parseFloat(i.paddingLeft) - parseFloat(i.paddingRight), r = this.element.clientHeight - parseFloat(i.paddingTop) - parseFloat(i.paddingBottom);
833
+ this.innerSize[0] = s, this.innerSize[1] = r, this.rebuildStyle(), this.calcLayout(!0, !0), this.lyricLinesEl.forEach((n) => n.updateMaskImage());
664
834
  });
665
835
  posXSpringParams = {
666
836
  mass: 1,
@@ -678,14 +848,29 @@ class ee extends EventTarget {
678
848
  stiffness: 100
679
849
  };
680
850
  enableBlur = !0;
851
+ enableScale = !0;
681
852
  interludeDots;
682
853
  interludeDotsSize = [0, 0];
854
+ bottomLine;
683
855
  supportPlusLighter = CSS.supports("mix-blend-mode", "plus-lighter");
684
856
  supportMaskImage = CSS.supports("mask-image", "none");
685
857
  disableSpring = !1;
686
- alignAnchor = 0.5;
858
+ alignAnchor = "center";
859
+ alignPosition = 0.5;
860
+ isNonDynamic = !1;
687
861
  size = [0, 0];
688
- pos = [0, 0];
862
+ innerSize = [0, 0];
863
+ onLineClickedHandler = (e) => {
864
+ const t = new K(
865
+ this.lyricLinesIndexes.get(e.line) ?? -1,
866
+ e.line,
867
+ e
868
+ );
869
+ this.dispatchEvent(t) || (e.preventDefault(), e.stopPropagation(), e.stopImmediatePropagation());
870
+ };
871
+ _getIsNonDynamic() {
872
+ return this.isNonDynamic;
873
+ }
689
874
  /**
690
875
  * 设置是否使用物理弹簧算法实现歌词动画效果,默认启用
691
876
  *
@@ -703,37 +888,72 @@ class ee extends EventTarget {
703
888
  getEnableSpring() {
704
889
  return !this.disableSpring;
705
890
  }
706
- style = G.createStyleSheet({
891
+ /**
892
+ * 是否启用歌词行缩放效果,默认启用
893
+ *
894
+ * 如果启用,非选中的歌词行会轻微缩小以凸显当前播放歌词行效果
895
+ *
896
+ * 此效果对性能影响微乎其微,推荐启用
897
+ * @param enable 是否启用歌词行缩放效果
898
+ */
899
+ setEnableScale(e = !0) {
900
+ this.enableScale = e, this.calcLayout();
901
+ }
902
+ /**
903
+ * 获取当前是否启用了歌词行缩放效果
904
+ * @returns 是否启用歌词行缩放效果
905
+ */
906
+ getEnableScale() {
907
+ return this.enableScale;
908
+ }
909
+ style = J.createStyleSheet({
707
910
  lyricPlayer: {
708
911
  userSelect: "none",
709
- padding: "1rem",
710
- boxSizing: "border-box",
711
- fontSize: "max(5vh, 12px)",
712
- fontWeight: "bold",
912
+ fontSize: "var(--amll-lyric-player-font-size,max(min(5vh, 10vw), 12px))",
913
+ padding: "1em",
914
+ margin: "-1em",
713
915
  width: "100%",
714
916
  height: "100%",
715
917
  overflow: "hidden",
716
918
  maxWidth: "100%",
717
919
  maxHeight: "100%",
718
920
  zIndex: 1,
719
- color: "var(--amll-lyric-line-color)",
921
+ color: "var(--amll-lyric-view-color,white)",
720
922
  mixBlendMode: "plus-lighter",
721
- contain: "strict"
923
+ contain: "strict",
924
+ "&:hover": {
925
+ "& $lyricLine": {
926
+ filter: "unset !important"
927
+ }
928
+ }
722
929
  },
723
930
  lyricLine: {
724
931
  position: "absolute",
725
932
  transformOrigin: "left",
726
- maxWidth: "65%",
727
- padding: "max(2vh, 1rem) 1rem",
933
+ maxWidth: "var(--amll-lyric-player-width,100%)",
934
+ minWidth: "var(--amll-lyric-player-width,100%)",
935
+ width: "var(--amll-lyric-player-width,100%)",
936
+ padding: "2vh 0.05em",
728
937
  contain: "content",
729
- transition: "filter 0.25s",
730
- margin: "max(2vh, 1rem) -1rem"
938
+ willChange: "filter,transform,opacity",
939
+ transition: "filter 0.25s, background-color 0.25s, box-shadow 0.25s",
940
+ boxSizing: "border-box",
941
+ borderRadius: "8px",
942
+ "& span": {
943
+ padding: "0.05em",
944
+ margin: "-0.05em"
945
+ },
946
+ "&:hover": {
947
+ backgroundColor: "var(--amll-lyric-view-hover-bg-color,#fff1)",
948
+ boxShadow: "0 0 0 8px var(--amll-lyric-view-hover-bg-color,#fff1)"
949
+ },
950
+ "&:active": {
951
+ boxShadow: "0 0 0 4px var(--amll-lyric-view-hover-bg-color,#fff1)"
952
+ }
731
953
  },
732
954
  "@media (max-width: 1024px)": {
733
955
  lyricLine: {
734
- maxWidth: "75%",
735
- padding: "max(1vh, 1rem) 1rem",
736
- margin: "0 -1rem"
956
+ padding: "1vh 0"
737
957
  }
738
958
  },
739
959
  lyricDuetLine: {
@@ -746,57 +966,58 @@ class ee extends EventTarget {
746
966
  transition: "opacity 0.25s",
747
967
  "&.active": {
748
968
  transition: "opacity 0.25s 0.25s",
749
- opacity: 1
969
+ opacity: 0.75
750
970
  }
751
971
  },
752
972
  lyricMainLine: {
753
973
  transition: "opacity 0.3s 0.25s",
754
- margin: "-1rem",
755
- padding: "1rem",
974
+ willChange: "opacity",
975
+ margin: "-1em",
976
+ padding: "1em",
756
977
  "& span": {
757
- display: "inline-block",
758
- margin: "-1rem",
759
- padding: "1rem"
978
+ display: "inline-block"
760
979
  },
761
980
  "& > span": {
762
981
  whiteSpace: "pre-wrap",
763
- wordBreak: "keep-all",
764
982
  maxLines: "1",
983
+ // willChange: "transform,display,mask-image",
765
984
  "&.emphasize": {
766
- margin: "-1rem",
767
- padding: "1rem",
768
985
  transformStyle: "preserve-3d",
769
- perspective: "50vw"
986
+ perspective: "50vw",
987
+ padding: "1em",
988
+ margin: "-1em"
770
989
  }
771
990
  }
772
991
  },
773
992
  lyricSubLine: {
774
- fontSize: "max(50%, 10px)",
993
+ fontSize: "max(0.5em, 10px)",
994
+ transition: "opacity 0.3s 0.25s",
775
995
  opacity: 0.5
776
996
  },
777
997
  disableSpring: {
778
998
  "& > *": {
779
- transition: "filter 0.25s, transform 0.5s"
999
+ transition: "filter 0.25s, transform 0.5s, background-color 0.25s, box-shadow 0.25s"
780
1000
  }
781
1001
  },
782
1002
  interludeDots: {
783
- height: "min(1rem,2.5vh)",
1003
+ height: "clamp(0.5em,1vh,3em)",
784
1004
  transformOrigin: "center",
785
1005
  width: "fit-content",
786
1006
  padding: "2.5% 0",
787
1007
  position: "absolute",
788
1008
  display: "flex",
789
- gap: "0.5rem",
1009
+ gap: "0.25em",
1010
+ left: "1em",
790
1011
  "& > *": {
791
- width: "100%",
1012
+ height: "clamp(0.5em,1vh,3em)",
792
1013
  display: "inline-block",
793
1014
  borderRadius: "50%",
794
1015
  aspectRatio: "1 / 1",
795
- backgroundColor: "var(--amll-lyric-line-color)",
1016
+ backgroundColor: "var(--amll-lyric-view-color,white)",
796
1017
  marginRight: "4px"
797
1018
  },
798
1019
  "&.duet": {
799
- right: "1rem",
1020
+ right: "1em",
800
1021
  transformOrigin: "center"
801
1022
  }
802
1023
  },
@@ -810,10 +1031,14 @@ class ee extends EventTarget {
810
1031
  }
811
1032
  });
812
1033
  onPageShow = () => {
813
- this.calcLayout(!0);
1034
+ this.calcLayout(!0, !0);
814
1035
  };
815
1036
  constructor() {
816
- super(), this.interludeDots = new $(this), this.element.setAttribute("class", this.style.classes.lyricPlayer), this.disableSpring && this.element.classList.add(this.style.classes.disableSpring), this.rebuildStyle(), this.resizeObserver.observe(this.element), this.element.appendChild(this.interludeDots.getElement()), this.style.attach(), this.interludeDots.setTransform(0, 200), window.addEventListener("pageshow", this.onPageShow);
1037
+ super(), this.interludeDots = new Y(this), this.bottomLine = new q(this), this.element.setAttribute("class", this.style.classes.lyricPlayer), this.disableSpring && this.element.classList.add(this.style.classes.disableSpring), this.rebuildStyle(), this.resizeObserver.observe(this.element), this.element.appendChild(this.interludeDots.getElement()), this.element.appendChild(this.bottomLine.getElement()), this.style.attach(), this.interludeDots.setTransform(0, 200), window.addEventListener("pageshow", this.onPageShow), this.element.addEventListener("wheel", (e) => {
1038
+ this.allowScroll && (this.isScrolled = !0, clearTimeout(this.scrolledHandler), this.scrolledHandler = setTimeout(() => {
1039
+ this.isScrolled = !1, this.scrollOffset = 0;
1040
+ }, 5e3), this.invokedByScrollEvent = !0, e.deltaMode === e.DOM_DELTA_PIXEL ? (this.scrollOffset += e.deltaY, this.calcLayout(!0)) : (this.scrollOffset += e.deltaY * 50, this.calcLayout(!1)), this.invokedByScrollEvent = !1);
1041
+ });
817
1042
  }
818
1043
  /**
819
1044
  * 获取当前播放时间里是否处于间奏区间
@@ -821,7 +1046,7 @@ class ee extends EventTarget {
821
1046
  * 否则返回 undefined
822
1047
  *
823
1048
  * 这个只允许内部调用
824
- * @returns [开始时间,结束时间] 或 undefined 如果不处于间奏区间
1049
+ * @returns [开始时间,结束时间,大概处于的歌词行ID,下一句是否为对唱歌词] 或 undefined 如果不处于间奏区间
825
1050
  */
826
1051
  getCurrentInterlude() {
827
1052
  if (this.bufferedLines.size > 0)
@@ -829,12 +1054,18 @@ class ee extends EventTarget {
829
1054
  const e = this.currentTime + 20, t = this.scrollToIndex;
830
1055
  if (t === 0) {
831
1056
  if (this.processedLines[0]?.startTime && this.processedLines[0].startTime > e)
832
- return [0, this.processedLines[0].startTime, -2];
1057
+ return [
1058
+ e,
1059
+ this.processedLines[0].startTime,
1060
+ -2,
1061
+ this.processedLines[0].isDuet
1062
+ ];
833
1063
  } else if (this.processedLines[t]?.endTime && this.processedLines[t + 1]?.startTime && this.processedLines[t + 1].startTime > e && this.processedLines[t].endTime < e)
834
1064
  return [
835
- this.processedLines[t].endTime,
1065
+ Math.max(this.processedLines[t].endTime, e),
836
1066
  this.processedLines[t + 1].startTime,
837
- t
1067
+ t,
1068
+ this.processedLines[t + 1].isDuet
838
1069
  ];
839
1070
  }
840
1071
  /**
@@ -844,7 +1075,14 @@ class ee extends EventTarget {
844
1075
  */
845
1076
  rebuildStyle() {
846
1077
  let e = "";
847
- e += "--amll-lyric-player-width:", e += this.element.clientWidth, e += "px;", e += "--amll-lyric-player-height:", e += this.element.clientHeight, e += "px;", e += "--amll-lyric-line-color:", e += "#FFFFFF;", e += "--amll-player-time:", e += this.currentTime, e += ";", this.element.setAttribute("style", e);
1078
+ e += "--amll-lyric-player-width:", e += this.innerSize[0] - this.padding * 2, e += "px;", e += "--amll-lyric-player-height:", e += this.innerSize[1] - this.padding * 2, e += "px;", e += "--amll-player-time:", e += this.currentTime, e += ";", this.element.setAttribute("style", e);
1079
+ }
1080
+ /**
1081
+ * 设置是否隐藏已经播放过的歌词行,默认不隐藏
1082
+ * @param hide 是否隐藏已经播放过的歌词行,默认不隐藏
1083
+ */
1084
+ setHidePassedLines(e) {
1085
+ this.hidePassedLines = e, this.calcLayout();
848
1086
  }
849
1087
  /**
850
1088
  * 设置是否启用歌词行的模糊效果
@@ -861,47 +1099,71 @@ class ee extends EventTarget {
861
1099
  this.lyricLines = e;
862
1100
  const t = 750;
863
1101
  this.processedLines = e.filter(
864
- (i) => i.words.reduce((n, a) => n + a.word.trim().length, 0) > 0
865
- ).map((i, n, a) => {
1102
+ (i) => i.words.reduce((s, r) => s + r.word.trim().length, 0) > 0
1103
+ ).map((i, s, r) => {
866
1104
  if (i.isBG)
867
1105
  return {
868
1106
  ...i
869
1107
  };
1108
+ if (s === 0)
1109
+ return {
1110
+ ...i,
1111
+ startTime: Math.max(i.startTime - t, 0)
1112
+ };
870
1113
  {
871
- const s = a[n - 1], r = a[n - 2];
872
- if (s?.isBG && r) {
873
- if (r.endTime < i.startTime)
1114
+ const n = r[s - 1], a = r[s - 2];
1115
+ if (n?.isBG && a) {
1116
+ if (a.endTime < i.startTime)
874
1117
  return {
875
1118
  ...i,
876
- startTime: Math.max(r.endTime, i.startTime - t) || i.startTime
1119
+ startTime: Math.max(a.endTime, i.startTime - t) || i.startTime
877
1120
  };
878
- } else if (s?.endTime && s.endTime < i.startTime)
1121
+ } else if (n?.endTime && n.endTime < i.startTime)
879
1122
  return {
880
1123
  ...i,
881
- startTime: Math.max(s?.endTime, i.startTime - t) || i.startTime
1124
+ startTime: Math.max(n?.endTime, i.startTime - t) || i.startTime
882
1125
  };
883
1126
  return {
884
1127
  ...i
885
1128
  };
886
1129
  }
887
- }), this.processedLines.forEach((i, n, a) => {
888
- const s = a[n + 1], r = i.words[i.words.length - 1];
889
- r && P(r) && (s ? s.startTime > i.endTime && (i.endTime = Math.min(i.endTime + 1500, s.startTime)) : i.endTime = i.endTime + 1500);
890
- }), this.processedLines.forEach((i, n, a) => {
1130
+ }), this.isNonDynamic = !0;
1131
+ for (const i of this.processedLines)
1132
+ if (i.words.length > 1) {
1133
+ this.isNonDynamic = !1;
1134
+ break;
1135
+ }
1136
+ this.processedLines.forEach((i, s, r) => {
1137
+ const n = r[s + 1], a = i.words[i.words.length - 1];
1138
+ a && x(a) && (n ? n.startTime > i.endTime && (i.endTime = Math.min(i.endTime + 1500, n.startTime)) : i.endTime = i.endTime + 1500);
1139
+ }), this.processedLines.forEach((i, s, r) => {
891
1140
  if (i.isBG)
892
1141
  return;
893
- const s = a[n + 1];
894
- s?.isBG && (s.startTime = Math.min(s.startTime, i.startTime));
895
- }), this.lyricLinesEl.forEach((i) => i.dispose()), this.lyricLinesEl = this.processedLines.map(
896
- (i) => new _(this, i)
897
- ), this.lyricLinesEl.forEach((i) => {
898
- this.element.appendChild(i.getElement()), i.updateMaskImage();
899
- }), this.hotLines.clear(), this.bufferedLines.clear(), this.setLinePosXSpringParams({}), this.setLinePosYSpringParams({}), this.setLineScaleSpringParams({}), this.setCurrentTime(0, !0), this.calcLayout(!0);
1142
+ const n = r[s + 1];
1143
+ n?.isBG && (n.startTime = Math.min(n.startTime, i.startTime));
1144
+ }), this.lyricLinesEl.forEach((i) => {
1145
+ i.removeEventListener("click", this.onLineClickedHandler), i.removeEventListener("contextmenu", this.onLineClickedHandler), i.dispose();
1146
+ }), this.lyricLinesEl = this.processedLines.map((i) => {
1147
+ const s = new j(this, i);
1148
+ return s.addEventListener("click", this.onLineClickedHandler), s.addEventListener("contextmenu", this.onLineClickedHandler), s;
1149
+ }), this.lyricLinesEl.forEach((i, s) => {
1150
+ this.element.appendChild(i.getElement()), this.lyricLinesIndexes.set(i, s), i.updateMaskImage();
1151
+ }), this.interludeDots.setInterlude(void 0), this.hotLines.clear(), this.bufferedLines.clear(), this.setLinePosXSpringParams({}), this.setLinePosYSpringParams({}), this.setLineScaleSpringParams({}), this.setCurrentTime(0, !0), this.calcLayout(!0, !0);
1152
+ }
1153
+ /**
1154
+ * 重置用户滚动状态
1155
+ *
1156
+ * 请在用户完成滚动点击跳转歌词时调用本事件再调用 `calcLayout` 以正确滚动到目标位置
1157
+ */
1158
+ resetScroll() {
1159
+ this.isScrolled = !1, this.scrollOffset = 0, this.invokedByScrollEvent = !1, clearTimeout(this.scrolledHandler), this.scrolledHandler = 0;
900
1160
  }
901
1161
  /**
902
1162
  * 重新布局定位歌词行的位置,调用完成后再逐帧调用 `update`
903
1163
  * 函数即可让歌词通过动画移动到目标位置。
904
1164
  *
1165
+ * 函数有一个 `force` 参数,用于指定是否强制修改布局,也就是不经过动画直接调整元素位置和大小。
1166
+ *
905
1167
  * 此函数还有一个 `reflow` 参数,用于指定是否需要重新计算布局
906
1168
  *
907
1169
  * 因为计算布局必定会导致浏览器重排布局,所以会大幅度影响流畅度和性能,故请只在以下情况下将其​设置为 true:
@@ -910,54 +1172,50 @@ class ee extends EventTarget {
910
1172
  * 2. 加载了新的歌词时(不论前后歌词是否完全一样)
911
1173
  * 3. 用户自行跳转了歌曲播放位置(不论距离远近)
912
1174
  *
1175
+ * @param force 是否不经过动画直接修改布局定位
913
1176
  * @param reflow 是否进行重新布局(重新计算每行歌词大小)
914
1177
  */
915
- calcLayout(e = !1) {
916
- e && (this.lyricLinesEl.forEach((o) => {
917
- const c = o.measureSize();
918
- this.lyricLinesSize.set(o, c), o.lineSize = c;
919
- }), this.interludeDotsSize[0] = this.interludeDots.getElement().clientWidth, this.interludeDotsSize[1] = this.interludeDots.getElement().clientHeight);
920
- const t = 0.95;
921
- let n = -this.lyricLinesEl.slice(0, this.scrollToIndex).reduce(
922
- (o, c) => o + (c.getLine().isBG ? 0 : this.lyricLinesSize.get(c)?.[1] ?? 0),
1178
+ calcLayout(e = !1, t = !1) {
1179
+ t && (this.lyricLinesEl.forEach((p) => {
1180
+ const d = p.measureSize();
1181
+ this.lyricLinesSize.set(p, d), p.lineSize = d;
1182
+ }), this.interludeDotsSize[0] = this.interludeDots.getElement().clientWidth, this.interludeDotsSize[1] = this.interludeDots.getElement().clientHeight, this.bottomLine.lineSize = this.bottomLine.measureSize());
1183
+ const i = this.getCurrentInterlude();
1184
+ let s = -this.scrollOffset, r = this.scrollToIndex, n = 0;
1185
+ i ? (n = i[1] - i[0], n >= 5e3 && this.lyricLinesEl[i[2] + 1] && (r = i[2] + 1)) : this.interludeDots.setInterlude(void 0);
1186
+ const a = this.enableScale ? 0.95 : 1, l = this.lyricLinesEl.slice(0, r).reduce(
1187
+ (p, d) => p + (d.getLine().isBG ? 0 : this.lyricLinesSize.get(d)?.[1] ?? 0),
923
1188
  0
924
1189
  );
925
- if (this.alignAnchor === "bottom") {
926
- n += this.element.clientHeight / 2;
927
- const o = this.lyricLinesEl[this.scrollToIndex];
928
- if (o) {
929
- const c = this.lyricLinesSize.get(o)?.[1] ?? 0;
930
- n -= c / 2;
1190
+ s -= l, s += this.size[1] * this.alignPosition;
1191
+ const o = this.lyricLinesEl[r];
1192
+ if (o) {
1193
+ const p = this.lyricLinesSize.get(o)?.[1] ?? 0;
1194
+ switch (this.alignAnchor) {
1195
+ case "bottom":
1196
+ s -= p;
1197
+ break;
1198
+ case "center":
1199
+ s -= p / 2;
1200
+ break;
931
1201
  }
932
- } else if (typeof this.alignAnchor == "number") {
933
- n += this.element.clientHeight * this.alignAnchor;
934
- const o = this.lyricLinesEl[this.scrollToIndex];
935
- if (o) {
936
- const c = this.lyricLinesSize.get(o)?.[1] ?? 0;
937
- n -= c / 2;
938
- }
939
- }
940
- const a = this.getCurrentInterlude();
941
- let s = 0;
942
- if (a && (s = a[1] - a[0], s >= 5e3)) {
943
- const o = this.lyricLinesEl[a[2] + 1];
944
- o && (n -= this.lyricLinesSize.get(o)?.[1] ?? 0);
945
1202
  }
946
- const r = Math.max(...this.bufferedLines);
947
- let l = 0, h = !1;
948
- this.lyricLinesEl.forEach((o, c) => {
949
- const m = this.bufferedLines.has(c), p = m || c >= this.scrollToIndex && c < r, u = o.getLine();
950
- let f = 0;
951
- u.isDuet && (f = this.size[0] - (this.lyricLinesSize.get(o)?.[0] ?? 0)), !h && s >= 5e3 && (c === this.scrollToIndex && a?.[2] === -2 || c === this.scrollToIndex + 1) && (h = !0, this.interludeDots.setTransform(0, n), a && this.interludeDots.setInterlude([a[0], a[1]]), n += this.interludeDotsSize[1]), o.setTransform(
952
- f,
953
- n,
954
- p ? 1 : t,
955
- m ? 1 : 1 / 3,
956
- this.enableBlur ? 3 * (p ? 0 : 1 + (c < this.scrollToIndex ? Math.abs(this.scrollToIndex - c) : Math.abs(c - Math.max(this.scrollToIndex, r)))) : 0,
1203
+ const c = Math.max(...this.bufferedLines);
1204
+ let m = 0, u = 0.05, f = !1;
1205
+ this.lyricLinesEl.forEach((p, d) => {
1206
+ const g = this.bufferedLines.has(d), b = g || d >= this.scrollToIndex && d < c, P = p.getLine();
1207
+ P.isDuet && this.size[0] - (this.lyricLinesSize.get(p)?.[0] ?? 0), !f && n >= 5e3 && (d === this.scrollToIndex && i?.[2] === -2 || d === this.scrollToIndex + 1) && (f = !0, this.interludeDots.setTransform(32, s), i && this.interludeDots.setInterlude([i[0], i[1]]), s += this.interludeDotsSize[1]);
1208
+ const M = this.hidePassedLines && d < (i ? i[2] + 1 : this.scrollToIndex) ? 0 : g ? 1 : 1 / 3;
1209
+ p.setTransform(
1210
+ this.padding,
1211
+ s,
1212
+ b ? 1 : a,
1213
+ M,
1214
+ !this.invokedByScrollEvent && this.enableBlur ? b ? 0 : 1 + (d < this.scrollToIndex ? Math.abs(this.scrollToIndex - d) : Math.abs(d - Math.max(this.scrollToIndex, c))) : 0,
957
1215
  e,
958
- l
959
- ), u.isBG && p ? n += this.lyricLinesSize.get(o)?.[1] ?? 0 : u.isBG || (n += this.lyricLinesSize.get(o)?.[1] ?? 0), n >= 0 && (l += 0.05);
960
- });
1216
+ m
1217
+ ), P.isBG && b ? s += this.lyricLinesSize.get(p)?.[1] ?? 0 : P.isBG || (s += this.lyricLinesSize.get(p)?.[1] ?? 0), s >= 0 && (m += u, u /= 1.2);
1218
+ }), this.bottomLine.setTransform(this.padding, s, e, m);
961
1219
  }
962
1220
  /**
963
1221
  * 获取当前歌词的播放位置
@@ -981,16 +1239,35 @@ class ee extends EventTarget {
981
1239
  return this.element;
982
1240
  }
983
1241
  /**
984
- * 设置歌词行的对齐方式,默认为 `top`
1242
+ * 获取一个特殊的底栏元素,默认是空白的,可以往内部添加任意元素
1243
+ *
1244
+ * 这个元素始终在歌词的底部,可以用于显示歌曲创作者等信息
985
1245
  *
986
- * - 设置成 `top` 的话歌词将会向组件顶部对齐
987
- * - 设置成 `bottom` 的话歌词将会向组件底部对齐
988
- * - 设置成 [0.0-1.0] 之间任意数字的话则会根据当前组件高度从顶部向下位移为对齐位置垂直居中对齐
1246
+ * 但是请勿删除该元素,只能在内部存放元素
1247
+ *
1248
+ * @returns 一个元素,可以往内部添加任意元素
1249
+ */
1250
+ getBottomLineElement() {
1251
+ return this.bottomLine.getElement();
1252
+ }
1253
+ /**
1254
+ * 设置目标歌词行的对齐方式,默认为 `center`
1255
+ *
1256
+ * - 设置成 `top` 的话将会向目标歌词行的顶部对齐
1257
+ * - 设置成 `bottom` 的话将会向目标歌词行的底部对齐
1258
+ * - 设置成 `center` 的话将会向目标歌词行的垂直中心对齐
989
1259
  * @param alignAnchor 歌词行对齐方式,详情见函数说明
990
1260
  */
991
1261
  setAlignAnchor(e) {
992
1262
  this.alignAnchor = e;
993
1263
  }
1264
+ /**
1265
+ * 设置默认的歌词行对齐位置,相对于整个歌词播放组件的大小位置,默认为 `0.5`
1266
+ * @param alignPosition 一个 `[0.0-1.0]` 之间的任意数字,代表组件高度由上到下的比例位置
1267
+ */
1268
+ setAlignPosition(e) {
1269
+ this.alignPosition = e;
1270
+ }
994
1271
  /**
995
1272
  * 设置当前播放进度,单位为毫秒且**必须是整数**,此时将会更新内部的歌词进度信息
996
1273
  * 内部会根据调用间隔和播放进度自动决定如何滚动和显示歌词,所以这个的调用频率越快越准确越好
@@ -999,35 +1276,36 @@ class ee extends EventTarget {
999
1276
  * @param time 当前播放进度,单位为毫秒
1000
1277
  */
1001
1278
  setCurrentTime(e, t = !1) {
1002
- this.currentTime = e, this.element.style.setProperty("--amll-player-time", `${e}`);
1003
- const i = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set();
1004
- this.hotLines.forEach((s) => {
1005
- const r = this.processedLines[s];
1006
- if (r) {
1007
- if (r.isBG)
1279
+ if (this.currentTime = e, this.element.style.setProperty("--amll-player-time", `${e}`), this.isScrolled)
1280
+ return;
1281
+ const i = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set();
1282
+ this.hotLines.forEach((n) => {
1283
+ const a = this.processedLines[n];
1284
+ if (a) {
1285
+ if (a.isBG)
1008
1286
  return;
1009
- const l = this.processedLines[s + 1];
1287
+ const l = this.processedLines[n + 1];
1010
1288
  if (l?.isBG) {
1011
- const h = Math.min(r.startTime, l?.startTime), o = Math.max(r.endTime, l?.endTime);
1012
- (h > e || o <= e) && (this.hotLines.delete(s), i.add(s), this.hotLines.delete(s + 1), i.add(s + 1), t && (this.lyricLinesEl[s].disable(), this.lyricLinesEl[s + 1].disable()));
1289
+ const o = Math.min(a.startTime, l?.startTime), c = Math.max(a.endTime, l?.endTime);
1290
+ (o > e || c <= e) && (this.hotLines.delete(n), i.add(n), this.hotLines.delete(n + 1), i.add(n + 1), t && (this.lyricLinesEl[n].disable(), this.lyricLinesEl[n + 1].disable()));
1013
1291
  } else
1014
- (r.startTime > e || r.endTime <= e) && (this.hotLines.delete(s), i.add(s), t && this.lyricLinesEl[s].disable());
1292
+ (a.startTime > e || a.endTime <= e) && (this.hotLines.delete(n), i.add(n), t && this.lyricLinesEl[n].disable());
1015
1293
  } else
1016
- this.hotLines.delete(s), i.add(s), t && this.lyricLinesEl[s].disable();
1017
- }), this.processedLines.forEach((s, r, l) => {
1018
- !s.isBG && s.startTime <= e && s.endTime > e && (this.hotLines.has(r) || (this.hotLines.add(r), a.add(r), t && this.lyricLinesEl[r].enable(), l[r + 1]?.isBG && (this.hotLines.add(r + 1), a.add(r + 1), t && this.lyricLinesEl[r + 1].enable())));
1019
- }), this.bufferedLines.forEach((s) => {
1020
- this.hotLines.has(s) || (n.add(s), t && this.lyricLinesEl[s].disable());
1294
+ this.hotLines.delete(n), i.add(n), t && this.lyricLinesEl[n].disable();
1295
+ }), this.processedLines.forEach((n, a, l) => {
1296
+ !n.isBG && n.startTime <= e && n.endTime > e && (this.hotLines.has(a) || (this.hotLines.add(a), r.add(a), t && this.lyricLinesEl[a].enable(), l[a + 1]?.isBG && (this.hotLines.add(a + 1), r.add(a + 1), t && this.lyricLinesEl[a + 1].enable())));
1297
+ }), this.bufferedLines.forEach((n) => {
1298
+ this.hotLines.has(n) || (s.add(n), t && this.lyricLinesEl[n].disable());
1021
1299
  }), t ? (this.bufferedLines.size > 0 ? this.scrollToIndex = Math.min(...this.bufferedLines) : this.scrollToIndex = this.processedLines.findIndex(
1022
- (s) => s.startTime >= e
1023
- ), this.bufferedLines.clear(), this.hotLines.forEach((s) => this.bufferedLines.add(s)), this.calcLayout(!0)) : (n.size > 0 || a.size > 0) && (n.size === 0 && a.size > 0 ? (a.forEach((s) => {
1024
- this.bufferedLines.add(s), this.lyricLinesEl[s].enable();
1025
- }), this.scrollToIndex = Math.min(...this.bufferedLines)) : a.size === 0 && n.size > 0 ? N(n, this.bufferedLines) && this.bufferedLines.forEach((s) => {
1026
- this.hotLines.has(s) || (this.bufferedLines.delete(s), this.lyricLinesEl[s].disable());
1027
- }) : (a.forEach((s) => {
1028
- this.bufferedLines.add(s), this.lyricLinesEl[s].enable();
1029
- }), n.forEach((s) => {
1030
- this.bufferedLines.delete(s), this.lyricLinesEl[s].disable();
1300
+ (n) => n.startTime >= e
1301
+ ), this.bufferedLines.clear(), this.hotLines.forEach((n) => this.bufferedLines.add(n)), this.calcLayout(!0)) : (s.size > 0 || r.size > 0) && (s.size === 0 && r.size > 0 ? (r.forEach((n) => {
1302
+ this.bufferedLines.add(n), this.lyricLinesEl[n].enable();
1303
+ }), this.scrollToIndex = Math.min(...this.bufferedLines)) : r.size === 0 && s.size > 0 ? W(s, this.bufferedLines) && this.bufferedLines.forEach((n) => {
1304
+ this.hotLines.has(n) || (this.bufferedLines.delete(n), this.lyricLinesEl[n].disable());
1305
+ }) : (r.forEach((n) => {
1306
+ this.bufferedLines.add(n), this.lyricLinesEl[n].enable();
1307
+ }), s.forEach((n) => {
1308
+ this.bufferedLines.delete(n), this.lyricLinesEl[n].disable();
1031
1309
  }), this.bufferedLines.size > 0 && (this.scrollToIndex = Math.min(...this.bufferedLines))), this.calcLayout());
1032
1310
  }
1033
1311
  /**
@@ -1038,7 +1316,7 @@ class ee extends EventTarget {
1038
1316
  */
1039
1317
  update(e = 0) {
1040
1318
  const t = e / 1e3;
1041
- this.interludeDots.update(e), this.lyricLinesEl.forEach((i) => i.update(t));
1319
+ this.interludeDots.update(e), this.bottomLine.update(t), this.lyricLinesEl.forEach((i) => i.update(t));
1042
1320
  }
1043
1321
  /**
1044
1322
  * 设置所有歌词行在横坐标上的弹簧属性,包括重量、弹力和阻力。
@@ -1049,7 +1327,7 @@ class ee extends EventTarget {
1049
1327
  this.posXSpringParams = {
1050
1328
  ...this.posXSpringParams,
1051
1329
  ...e
1052
- }, this.lyricLinesEl.forEach(
1330
+ }, this.bottomLine.lineTransforms.posX.updateParams(this.posXSpringParams), this.lyricLinesEl.forEach(
1053
1331
  (t) => t.lineTransforms.posX.updateParams(this.posXSpringParams)
1054
1332
  );
1055
1333
  }
@@ -1062,7 +1340,7 @@ class ee extends EventTarget {
1062
1340
  this.posYSpringParams = {
1063
1341
  ...this.posYSpringParams,
1064
1342
  ...e
1065
- }, this.lyricLinesEl.forEach(
1343
+ }, this.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams), this.lyricLinesEl.forEach(
1066
1344
  (t) => t.lineTransforms.posY.updateParams(this.posYSpringParams)
1067
1345
  );
1068
1346
  }
@@ -1080,12 +1358,12 @@ class ee extends EventTarget {
1080
1358
  );
1081
1359
  }
1082
1360
  dispose() {
1083
- this.element.remove(), this.resizeObserver.disconnect(), this.style.detach(), this.lyricLinesEl.forEach((e) => e.dispose()), window.removeEventListener("pageshow", this.onPageShow);
1361
+ this.element.remove(), this.resizeObserver.disconnect(), this.style.detach(), this.lyricLinesEl.forEach((e) => e.dispose()), window.removeEventListener("pageshow", this.onPageShow), this.bottomLine.dispose(), this.interludeDots.dispose();
1084
1362
  }
1085
1363
  }
1086
1364
  export {
1087
- Z as BackgroundRender,
1088
- ee as LyricPlayer,
1089
- Q as ttml
1365
+ oe as BackgroundRender,
1366
+ le as LyricPlayer,
1367
+ ae as ttml
1090
1368
  };
1091
1369
  //# sourceMappingURL=amll-core.mjs.map