@applemusic-like-lyrics/core 0.5.1 → 0.5.2

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.
@@ -882,13 +882,6 @@ interface RealWord extends LyricWord {
882
882
  padding: number;
883
883
  shouldEmphasize: boolean;
884
884
  }
885
- declare class RawLyricLineMouseEvent extends MouseEvent {
886
- readonly line: LyricLineBase;
887
- constructor(line: LyricLineBase, event: MouseEvent);
888
- }
889
- type MouseEventMap = { [evt in keyof HTMLElementEventMap]: HTMLElementEventMap[evt] extends MouseEvent ? evt : never };
890
- type MouseEventTypes = MouseEventMap[keyof MouseEventMap];
891
- type MouseEventListener = (this: LyricLineEl, ev: RawLyricLineMouseEvent) => void;
892
885
  declare class LyricLineEl extends LyricLineBase {
893
886
  private lyricPlayer;
894
887
  private lyricLine;
@@ -906,10 +899,6 @@ declare class LyricLineEl extends LyricLineBase {
906
899
  */
907
900
  private balancer?;
908
901
  constructor(lyricPlayer: DomLyricPlayer, lyricLine?: LyricLine);
909
- private listenersMap;
910
- private readonly onMouseEvent;
911
- addMouseEventListener(type: MouseEventTypes, callback: MouseEventListener | null, options?: boolean | AddEventListenerOptions | undefined): void;
912
- removeMouseEventListener(type: MouseEventTypes, callback: MouseEventListener | null, options?: boolean | EventListenerOptions | undefined): void;
913
902
  areWordsOnSameLine(word1: RealWord, word2: RealWord): boolean;
914
903
  private isEnabled;
915
904
  enable(maskAnimationTime?: number, shouldPlay?: boolean): Promise<void>;
@@ -941,6 +930,7 @@ declare class LyricLineEl extends LyricLineBase {
941
930
  private applyAlphaToDom;
942
931
  override setTransform(scale?: number, opacity?: number, blur?: number, force?: boolean, delay?: number, mode?: LyricLineRenderMode): void;
943
932
  update(delta?: number): void;
933
+ /** @internal */
944
934
  _getDebugTargetPos(): string;
945
935
  teardownContent(): void;
946
936
  private disposeElements;
@@ -965,7 +955,7 @@ declare class LyricLineGroup extends LyricLineGroupBase<LyricLineEl> {
965
955
  //#endregion
966
956
  //#region src/lyric-player/dom/index.d.ts
967
957
  /**
968
- * 歌词行鼠标相关事件,可以获取到歌词行的索引和歌词行元素
958
+ * 歌词行鼠标相关事件,可以获取到歌词行的索引、主歌词行以及背景歌词行(如果有)元素
969
959
  */
970
960
  declare class LyricLineMouseEvent extends MouseEvent {
971
961
  /**
@@ -976,7 +966,17 @@ declare class LyricLineMouseEvent extends MouseEvent {
976
966
  * 歌词行元素
977
967
  */
978
968
  readonly line: LyricLineBase;
979
- constructor(lineIndex: number, line: LyricLineBase, event: MouseEvent);
969
+ /**
970
+ * 背景人声歌词行元素 (如果存在)
971
+ */
972
+ readonly bgLine: LyricLineBase | undefined;
973
+ /**
974
+ * 自定义标志位,用于记录外部是否调用了 `stopPropagation`
975
+ */
976
+ isPropagationStopped: boolean;
977
+ constructor(lineIndex: number, line: LyricLineBase, bgLine: LyricLineBase | undefined, event: MouseEvent);
978
+ override stopPropagation(): void;
979
+ override stopImmediatePropagation(): void;
980
980
  }
981
981
  type LyricLineMouseEventListener = (evt: LyricLineMouseEvent) => void;
982
982
  /**
@@ -985,12 +985,13 @@ type LyricLineMouseEventListener = (evt: LyricLineMouseEvent) => void;
985
985
  * 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
986
986
  */
987
987
  declare class DomLyricPlayer extends LyricPlayerBase {
988
+ private abortController;
988
989
  override currentLyricGroups: LyricLineGroup[];
989
990
  override onResize(): void;
990
991
  readonly supportPlusLighter: boolean;
991
992
  readonly supportMaskImage: boolean;
992
993
  readonly innerSize: [number, number];
993
- private readonly onLineClickedHandler;
994
+ private readonly onMouseEventHandler;
994
995
  /**
995
996
  * 是否为非逐词歌词
996
997
  * @internal
@@ -882,13 +882,6 @@ interface RealWord extends LyricWord {
882
882
  padding: number;
883
883
  shouldEmphasize: boolean;
884
884
  }
885
- declare class RawLyricLineMouseEvent extends MouseEvent {
886
- readonly line: LyricLineBase;
887
- constructor(line: LyricLineBase, event: MouseEvent);
888
- }
889
- type MouseEventMap = { [evt in keyof HTMLElementEventMap]: HTMLElementEventMap[evt] extends MouseEvent ? evt : never };
890
- type MouseEventTypes = MouseEventMap[keyof MouseEventMap];
891
- type MouseEventListener = (this: LyricLineEl, ev: RawLyricLineMouseEvent) => void;
892
885
  declare class LyricLineEl extends LyricLineBase {
893
886
  private lyricPlayer;
894
887
  private lyricLine;
@@ -906,10 +899,6 @@ declare class LyricLineEl extends LyricLineBase {
906
899
  */
907
900
  private balancer?;
908
901
  constructor(lyricPlayer: DomLyricPlayer, lyricLine?: LyricLine);
909
- private listenersMap;
910
- private readonly onMouseEvent;
911
- addMouseEventListener(type: MouseEventTypes, callback: MouseEventListener | null, options?: boolean | AddEventListenerOptions | undefined): void;
912
- removeMouseEventListener(type: MouseEventTypes, callback: MouseEventListener | null, options?: boolean | EventListenerOptions | undefined): void;
913
902
  areWordsOnSameLine(word1: RealWord, word2: RealWord): boolean;
914
903
  private isEnabled;
915
904
  enable(maskAnimationTime?: number, shouldPlay?: boolean): Promise<void>;
@@ -941,6 +930,7 @@ declare class LyricLineEl extends LyricLineBase {
941
930
  private applyAlphaToDom;
942
931
  override setTransform(scale?: number, opacity?: number, blur?: number, force?: boolean, delay?: number, mode?: LyricLineRenderMode): void;
943
932
  update(delta?: number): void;
933
+ /** @internal */
944
934
  _getDebugTargetPos(): string;
945
935
  teardownContent(): void;
946
936
  private disposeElements;
@@ -965,7 +955,7 @@ declare class LyricLineGroup extends LyricLineGroupBase<LyricLineEl> {
965
955
  //#endregion
966
956
  //#region src/lyric-player/dom/index.d.ts
967
957
  /**
968
- * 歌词行鼠标相关事件,可以获取到歌词行的索引和歌词行元素
958
+ * 歌词行鼠标相关事件,可以获取到歌词行的索引、主歌词行以及背景歌词行(如果有)元素
969
959
  */
970
960
  declare class LyricLineMouseEvent extends MouseEvent {
971
961
  /**
@@ -976,7 +966,17 @@ declare class LyricLineMouseEvent extends MouseEvent {
976
966
  * 歌词行元素
977
967
  */
978
968
  readonly line: LyricLineBase;
979
- constructor(lineIndex: number, line: LyricLineBase, event: MouseEvent);
969
+ /**
970
+ * 背景人声歌词行元素 (如果存在)
971
+ */
972
+ readonly bgLine: LyricLineBase | undefined;
973
+ /**
974
+ * 自定义标志位,用于记录外部是否调用了 `stopPropagation`
975
+ */
976
+ isPropagationStopped: boolean;
977
+ constructor(lineIndex: number, line: LyricLineBase, bgLine: LyricLineBase | undefined, event: MouseEvent);
978
+ override stopPropagation(): void;
979
+ override stopImmediatePropagation(): void;
980
980
  }
981
981
  type LyricLineMouseEventListener = (evt: LyricLineMouseEvent) => void;
982
982
  /**
@@ -985,12 +985,13 @@ type LyricLineMouseEventListener = (evt: LyricLineMouseEvent) => void;
985
985
  * 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
986
986
  */
987
987
  declare class DomLyricPlayer extends LyricPlayerBase {
988
+ private abortController;
988
989
  override currentLyricGroups: LyricLineGroup[];
989
990
  override onResize(): void;
990
991
  readonly supportPlusLighter: boolean;
991
992
  readonly supportMaskImage: boolean;
992
993
  readonly innerSize: [number, number];
993
- private readonly onLineClickedHandler;
994
+ private readonly onMouseEventHandler;
994
995
  /**
995
996
  * 是否为非逐词歌词
996
997
  * @internal
@@ -14,6 +14,7 @@ function clamp1(x) {
14
14
  return Math.max(1, x);
15
15
  }
16
16
  var BaseRenderer = class extends AbstractBaseRenderer {
17
+ canvas;
17
18
  observer;
18
19
  flowSpeed = 1;
19
20
  currerntRenderScale = .75;
@@ -538,10 +539,10 @@ function generateControlPoints(width, height, variationFraction = randomRange(.4
538
539
  }
539
540
  //#endregion
540
541
  //#region \0raw:/home/runner/work/applemusic-like-lyrics/applemusic-like-lyrics/packages/core/src/bg-render/mesh-renderer/mesh.frag.glsl
541
- var mesh_frag_default = "precision highp float;\r\n\r\nvarying vec3 v_color;\r\nvarying vec2 v_uv;\r\nuniform sampler2D u_texture;\r\nuniform float u_time;\r\nuniform float u_volume;\r\nuniform float u_alpha;\r\n\r\n// 预计算常量\r\nconst float INV_255 = 1.0 / 255.0;\r\nconst float HALF_INV_255 = 0.5 / 255.0;\r\nconst float GRADIENT_NOISE_A = 52.9829189;\r\nconst vec2 GRADIENT_NOISE_B = vec2(0.06711056, 0.00583715);\r\n\r\n/* Gradient noise from Jorge Jimenez's presentation: */\r\n/* http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */\r\nfloat gradientNoise(in vec2 uv) {\r\n return fract(GRADIENT_NOISE_A * fract(dot(uv, GRADIENT_NOISE_B)));\r\n}\r\n\r\n// 优化的旋转函数,避免重复计算sin/cos\r\nvec2 rot(vec2 v, float angle) {\r\n float s = sin(angle);\r\n float c = cos(angle);\r\n return vec2(c * v.x - s * v.y, s * v.x + c * v.y);\r\n}\r\n\r\nvoid main() {\r\n // 合并计算以减少指令数\r\n float volumeEffect = u_volume * 2.0;\r\n float timeVolume = u_time + u_volume;\r\n \r\n float dither = INV_255 * gradientNoise(gl_FragCoord.xy) - HALF_INV_255;\r\n vec2 centeredUV = v_uv - vec2(0.2);\r\n vec2 rotatedUV = rot(centeredUV, timeVolume * 2.0);\r\n vec2 finalUV = rotatedUV * max(0.001, 1.0 - volumeEffect) + vec2(0.5);\r\n \r\n vec4 result = texture2D(u_texture, finalUV);\r\n \r\n float alphaVolumeFactor = u_alpha * max(0.5, 1.0 - u_volume * 0.5);\r\n result.rgb *= v_color * alphaVolumeFactor;\r\n result.a *= alphaVolumeFactor;\r\n \r\n result.rgb += vec3(dither);\r\n \r\n float dist = distance(v_uv, vec2(0.5));\r\n float vignette = smoothstep(0.8, 0.3, dist);\r\n float mask = 0.6 + vignette * 0.4;\r\n result.rgb *= mask;\r\n \r\n gl_FragColor = result;\r\n}\r\n";
542
+ var mesh_frag_default = "precision mediump float;\n\nvarying vec3 v_color;\nvarying vec2 v_uv;\nuniform sampler2D u_texture;\nuniform float u_volume;\nuniform float u_alpha;\nuniform float u_sinAngle;\nuniform float u_cosAngle;\n\n// 预计算常量\nconst float INV_255 = 1.0 / 255.0;\nconst float HALF_INV_255 = 0.5 / 255.0;\nconst float GRADIENT_NOISE_A = 52.9829189;\nconst vec2 GRADIENT_NOISE_B = vec2(0.06711056, 0.00583715);\n\nfloat gradientNoise(in vec2 uv) {\n return fract(GRADIENT_NOISE_A * fract(dot(uv, GRADIENT_NOISE_B)));\n}\n\nvoid main() {\n float volumeEffect = u_volume * 2.0;\n\n float dither = INV_255 * gradientNoise(gl_FragCoord.xy) - HALF_INV_255;\n\n vec2 centeredUV = v_uv - vec2(0.2);\n\n vec2 rotatedUV = vec2(\n u_cosAngle * centeredUV.x - u_sinAngle * centeredUV.y,\n u_sinAngle * centeredUV.x + u_cosAngle * centeredUV.y\n );\n\n vec2 finalUV = rotatedUV * max(0.001, 1.0 - volumeEffect) + vec2(0.5);\n \n vec4 result = texture2D(u_texture, finalUV);\n \n float alphaVolumeFactor = u_alpha * max(0.5, 1.0 - u_volume * 0.5);\n result.rgb *= v_color * alphaVolumeFactor;\n result.a *= alphaVolumeFactor;\n \n result.rgb += vec3(dither);\n \n float dist = distance(v_uv, vec2(0.5));\n float vignette = smoothstep(0.8, 0.3, dist);\n float mask = 0.6 + vignette * 0.4;\n result.rgb *= mask;\n \n gl_FragColor = result;\n}\n";
542
543
  //#endregion
543
544
  //#region \0raw:/home/runner/work/applemusic-like-lyrics/applemusic-like-lyrics/packages/core/src/bg-render/mesh-renderer/mesh.vert.glsl
544
- var mesh_vert_default = "precision highp float;\n\nattribute vec2 a_pos;\nattribute vec3 a_color;\nattribute vec2 a_uv;\nvarying vec3 v_color;\nvarying vec2 v_uv;\n\nuniform float u_aspect;\n\nvoid main() {\n v_color = a_color;\n v_uv = a_uv;\n vec2 pos = a_pos;\n if (u_aspect > 1.0) {\n pos.y *= u_aspect;\n } else {\n pos.x /= u_aspect;\n }\n gl_Position = vec4(pos, 0.0, 1.0);\n}\n";
545
+ var mesh_vert_default = "precision mediump float;\n\nattribute vec2 a_pos;\nattribute vec3 a_color;\nattribute vec2 a_uv;\nvarying vec3 v_color;\nvarying vec2 v_uv;\n\nuniform float u_aspect;\n\nvoid main() {\n v_color = a_color;\n v_uv = a_uv;\n vec2 pos = a_pos;\n if (u_aspect > 1.0) {\n pos.y *= u_aspect;\n } else {\n pos.x /= u_aspect;\n }\n gl_Position = vec4(pos, 0.0, 1.0);\n}\n";
545
546
  //#endregion
546
547
  //#region src/bg-render/mesh-renderer/index.ts
547
548
  /**
@@ -572,6 +573,7 @@ function easeInOutSine(x) {
572
573
  return -(Math.cos(Math.PI * x) - 1) / 2;
573
574
  }
574
575
  var GLProgram = class {
576
+ label;
575
577
  gl;
576
578
  program;
577
579
  vertexShader;
@@ -653,6 +655,10 @@ var GLProgram = class {
653
655
  }
654
656
  };
655
657
  var Mesh = class {
658
+ gl;
659
+ attrPos;
660
+ attrColor;
661
+ attrUV;
656
662
  vertexWidth = 0;
657
663
  vertexHeight = 0;
658
664
  vertexBuffer;
@@ -1075,6 +1081,7 @@ var BHPMesh = class extends Mesh {
1075
1081
  }
1076
1082
  };
1077
1083
  var GLTexture = class {
1084
+ gl;
1078
1085
  tex;
1079
1086
  constructor(gl, albumImageData) {
1080
1087
  this.gl = gl;
@@ -1240,11 +1247,14 @@ var MeshGradientRenderer = class extends BaseRenderer {
1240
1247
  gl.clear(gl.COLOR_BUFFER_BIT);
1241
1248
  this.mainProgram.use();
1242
1249
  gl.activeTexture(gl.TEXTURE0);
1243
- this.mainProgram.setUniform1f("u_time", tickTime / 1e4);
1250
+ const uTime = tickTime / 1e4;
1244
1251
  this.mainProgram.setUniform1f("u_aspect", this.manualControl ? 1 : this.canvas.width / this.canvas.height);
1245
1252
  this.mainProgram.setUniform1i("u_texture", 0);
1246
1253
  this.mainProgram.setUniform1f("u_volume", this.volume);
1247
1254
  this.mainProgram.setUniform1f("u_alpha", 1);
1255
+ const angle = (uTime + this.volume) * 2;
1256
+ this.mainProgram.setUniform1f("u_sinAngle", Math.sin(angle));
1257
+ this.mainProgram.setUniform1f("u_cosAngle", Math.cos(angle));
1248
1258
  state.texture.bind();
1249
1259
  state.mesh.bind();
1250
1260
  state.mesh.draw();
@@ -1482,6 +1492,7 @@ var TimedContainer = class extends Container {
1482
1492
  time = 0;
1483
1493
  };
1484
1494
  var PixiRenderer = class extends BaseRenderer {
1495
+ canvas;
1485
1496
  app;
1486
1497
  curContainer;
1487
1498
  staticMode = false;
@@ -1711,7 +1722,6 @@ var lyric_player_module_default = {
1711
1722
  "bgWrapperHidden": "FmKaba_bgWrapperHidden",
1712
1723
  "bgWrapperTop": "FmKaba_bgWrapperTop",
1713
1724
  "bottomLine": "FmKaba_bottomLine",
1714
- "dirty": "FmKaba_dirty",
1715
1725
  "disableSpring": "FmKaba_disableSpring",
1716
1726
  "duet": "FmKaba_duet",
1717
1727
  "emphasize": "FmKaba_emphasize",
@@ -2149,6 +2159,7 @@ function solveSpring(from, velocity, to, delay = 0, params) {
2149
2159
  //#endregion
2150
2160
  //#region src/lyric-player/base/bottom-line.ts
2151
2161
  var BottomLineEl = class {
2162
+ lyricPlayer;
2152
2163
  element = document.createElement("div");
2153
2164
  left = 0;
2154
2165
  top = 0;
@@ -3251,6 +3262,8 @@ var LyricPlayerBase = class extends EventTarget {
3251
3262
  //#endregion
3252
3263
  //#region src/lyric-player/base/group.ts
3253
3264
  var LyricLineGroupBase = class {
3265
+ mainLine;
3266
+ bgLine;
3254
3267
  posY = new Spring(0);
3255
3268
  bgSlideY = new Spring(-80);
3256
3269
  top = 0;
@@ -3334,6 +3347,7 @@ var LyricLineGroupBase = class {
3334
3347
  //#endregion
3335
3348
  //#region src/lyric-player/dom/lyric-group.ts
3336
3349
  var LyricLineGroup = class extends LyricLineGroupBase {
3350
+ lyricPlayer;
3337
3351
  element;
3338
3352
  bgWrapper;
3339
3353
  lastIsActive;
@@ -3583,6 +3597,7 @@ function getMeasurementContext() {
3583
3597
  * 用于平衡歌词行在换行后的各行长度
3584
3598
  */
3585
3599
  var LineBalancer = class {
3600
+ mainElement;
3586
3601
  isBalancing = false;
3587
3602
  lastBalancedContainerWidth = -1;
3588
3603
  constructor(mainElement) {
@@ -3906,13 +3921,9 @@ function generateFadeGradient(width, padding = 0, bright = "rgba(0,0,0,var(--bri
3906
3921
  const leftPos = (1 - widthInTotal) / 2;
3907
3922
  return [`linear-gradient(to right,${bright} ${leftPos * 100}%,${dark} ${(leftPos + widthInTotal) * 100}%)`, totalAspect];
3908
3923
  }
3909
- var RawLyricLineMouseEvent = class extends MouseEvent {
3910
- constructor(line, event) {
3911
- super(event.type, event);
3912
- this.line = line;
3913
- }
3914
- };
3915
3924
  var LyricLineEl = class extends LyricLineBase {
3925
+ lyricPlayer;
3926
+ lyricLine;
3916
3927
  element = document.createElement("div");
3917
3928
  splittedWords = [];
3918
3929
  built = false;
@@ -3953,33 +3964,6 @@ var LyricLineEl = class extends LyricLineBase {
3953
3964
  if (LyricLineBase.wordSegmenter) this.balancer = new LineBalancer(main);
3954
3965
  this.rebuildStyle();
3955
3966
  }
3956
- listenersMap = /* @__PURE__ */ new Map();
3957
- onMouseEvent = (e) => {
3958
- const wrapped = new RawLyricLineMouseEvent(this, e);
3959
- for (const listener of this.listenersMap.get(e.type) ?? []) listener.call(this, wrapped);
3960
- if (!this.dispatchEvent(wrapped) || wrapped.defaultPrevented) {
3961
- e.preventDefault();
3962
- e.stopPropagation();
3963
- e.stopImmediatePropagation();
3964
- }
3965
- };
3966
- addMouseEventListener(type, callback, options) {
3967
- if (callback) {
3968
- const listeners = this.listenersMap.get(type) ?? /* @__PURE__ */ new Set();
3969
- if (listeners.size === 0) this.element.addEventListener(type, this.onMouseEvent, options);
3970
- listeners.add(callback);
3971
- this.listenersMap.set(type, listeners);
3972
- }
3973
- }
3974
- removeMouseEventListener(type, callback, options) {
3975
- if (callback) {
3976
- const listeners = this.listenersMap.get(type);
3977
- if (listeners) {
3978
- listeners.delete(callback);
3979
- if (listeners.size === 0) this.element.removeEventListener(type, this.onMouseEvent, options);
3980
- }
3981
- }
3982
- }
3983
3967
  areWordsOnSameLine(word1, word2) {
3984
3968
  if (word1?.mainElement && word2?.mainElement) {
3985
3969
  const word1el = word1.mainElement;
@@ -4096,7 +4080,7 @@ var LyricLineEl = class extends LyricLineBase {
4096
4080
  const trans = this.element.children[1];
4097
4081
  const roman = this.element.children[2];
4098
4082
  if (this.lyricPlayer._getIsNonDynamic()) {
4099
- main.innerText = this.lyricLine.words.map((w) => this.lyricPlayer.processObsceneWord(w)).join("");
4083
+ main.textContent = this.lyricLine.words.map((w) => this.lyricPlayer.processObsceneWord(w)).join("");
4100
4084
  this.setSubLinesText(trans, roman);
4101
4085
  return;
4102
4086
  }
@@ -4109,8 +4093,8 @@ var LyricLineEl = class extends LyricLineBase {
4109
4093
  }
4110
4094
  /** 设置翻译与音译行文本 */
4111
4095
  setSubLinesText(trans, roman) {
4112
- trans.innerText = this.lyricLine.translatedLyric;
4113
- roman.innerText = this.lyricLine.romanLyric;
4096
+ trans.textContent = this.lyricLine.translatedLyric;
4097
+ roman.textContent = this.lyricLine.romanLyric;
4114
4098
  }
4115
4099
  getRubyCharCount(word) {
4116
4100
  return (word.ruby ?? []).reduce((total, ruby) => total + ruby.word.length, 0);
@@ -4128,7 +4112,7 @@ var LyricLineEl = class extends LyricLineBase {
4128
4112
  const rubySegments = this.getRubySegments(word);
4129
4113
  for (const ruby of rubySegments) {
4130
4114
  const rubyPartEl = document.createElement("span");
4131
- rubyPartEl.innerText = ruby.word;
4115
+ rubyPartEl.textContent = ruby.word;
4132
4116
  rubyPartEl.dataset.startTime = String(ruby.startTime);
4133
4117
  rubyPartEl.dataset.endTime = String(ruby.endTime);
4134
4118
  rubyWordEl.appendChild(rubyPartEl);
@@ -4145,24 +4129,24 @@ var LyricLineEl = class extends LyricLineBase {
4145
4129
  const trimmedWord = displayWord.trim();
4146
4130
  if (LyricLineBase.graphemeSegmenter) for (const { segment } of LyricLineBase.graphemeSegmenter.segment(trimmedWord)) {
4147
4131
  const charEl = document.createElement("span");
4148
- charEl.innerText = segment;
4132
+ charEl.textContent = segment;
4149
4133
  subElements.push(charEl);
4150
4134
  wordContainer.appendChild(charEl);
4151
4135
  }
4152
4136
  else for (const segment of Array.from(trimmedWord)) {
4153
4137
  const charEl = document.createElement("span");
4154
- charEl.innerText = segment;
4138
+ charEl.textContent = segment;
4155
4139
  subElements.push(charEl);
4156
4140
  wordContainer.appendChild(charEl);
4157
4141
  }
4158
4142
  } else if (hasRomanLine) {
4159
4143
  const wordEl = document.createElement("div");
4160
- wordEl.innerText = displayWord.trim();
4144
+ wordEl.textContent = displayWord.trim();
4161
4145
  wordContainer.appendChild(wordEl);
4162
- } else if (romanWord.length === 0) wordContainer.innerText = displayWord.trim();
4146
+ } else if (romanWord.length === 0) wordContainer.textContent = displayWord.trim();
4163
4147
  if (hasRomanLine) {
4164
4148
  const romanWordEl = document.createElement("div");
4165
- romanWordEl.innerText = romanWord.length > 0 ? romanWord : "\xA0";
4149
+ romanWordEl.textContent = romanWord.length > 0 ? romanWord : "\xA0";
4166
4150
  romanWordEl.classList.add(lyric_player_module_default.romanWord);
4167
4151
  wordContainer.appendChild(romanWordEl);
4168
4152
  }
@@ -4276,7 +4260,7 @@ var LyricLineEl = class extends LyricLineBase {
4276
4260
  const glow = el.animate(frames, {
4277
4261
  duration: animateDu,
4278
4262
  delay: Number.isFinite(wordDe) ? wordDe : 0,
4279
- id: `emphasize-word-${el.innerText}-${i}`,
4263
+ id: `emphasize-word-${el.textContent}-${i}`,
4280
4264
  iterations: 1,
4281
4265
  composite: "replace",
4282
4266
  fill: "both"
@@ -4562,6 +4546,7 @@ var LyricLineEl = class extends LyricLineBase {
4562
4546
  this.updateMaskAlphaTargets(currentScale);
4563
4547
  this.applyAlphaToDom(delta);
4564
4548
  }
4549
+ /** @internal */
4565
4550
  _getDebugTargetPos() {
4566
4551
  return `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;
4567
4552
  }
@@ -4602,13 +4587,29 @@ var LyricLineEl = class extends LyricLineBase {
4602
4587
  //#endregion
4603
4588
  //#region src/lyric-player/dom/index.ts
4604
4589
  /**
4605
- * 歌词行鼠标相关事件,可以获取到歌词行的索引和歌词行元素
4590
+ * 歌词行鼠标相关事件,可以获取到歌词行的索引、主歌词行以及背景歌词行(如果有)元素
4606
4591
  */
4607
4592
  var LyricLineMouseEvent = class extends MouseEvent {
4608
- constructor(lineIndex, line, event) {
4593
+ lineIndex;
4594
+ line;
4595
+ bgLine;
4596
+ /**
4597
+ * 自定义标志位,用于记录外部是否调用了 `stopPropagation`
4598
+ */
4599
+ isPropagationStopped = false;
4600
+ constructor(lineIndex, line, bgLine, event) {
4609
4601
  super(`line-${event.type}`, event);
4610
4602
  this.lineIndex = lineIndex;
4611
4603
  this.line = line;
4604
+ this.bgLine = bgLine;
4605
+ }
4606
+ stopPropagation() {
4607
+ this.isPropagationStopped = true;
4608
+ super.stopPropagation();
4609
+ }
4610
+ stopImmediatePropagation() {
4611
+ this.isPropagationStopped = true;
4612
+ super.stopImmediatePropagation();
4612
4613
  }
4613
4614
  };
4614
4615
  /**
@@ -4617,6 +4618,7 @@ var LyricLineMouseEvent = class extends MouseEvent {
4617
4618
  * 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
4618
4619
  */
4619
4620
  var DomLyricPlayer = class extends LyricPlayerBase {
4621
+ abortController = new AbortController();
4620
4622
  currentLyricGroups = [];
4621
4623
  onResize() {
4622
4624
  const computedStyles = getComputedStyle(this.element);
@@ -4626,10 +4628,18 @@ var DomLyricPlayer = class extends LyricPlayerBase {
4626
4628
  supportPlusLighter = CSS.supports("mix-blend-mode", "plus-lighter");
4627
4629
  supportMaskImage = CSS.supports("mask-image", "none");
4628
4630
  innerSize = [0, 0];
4629
- onLineClickedHandler = (e) => {
4630
- const evt = new LyricLineMouseEvent(this.lyricLinesIndexes.get(e.line) ?? -1, e.line, e);
4631
- if (!this.dispatchEvent(evt)) {
4632
- e.preventDefault();
4631
+ onMouseEventHandler = (e) => {
4632
+ const target = e.target;
4633
+ if (!(target instanceof Element)) return;
4634
+ const groupEl = target.closest(`.${lyric_player_module_default.lyricLineWrapper}`);
4635
+ if (!groupEl) return;
4636
+ const group = this.lyricGroupElementMap.get(groupEl);
4637
+ if (!group) return;
4638
+ const mainLine = group.mainLine;
4639
+ const bgLine = group.bgLine;
4640
+ const evt = new LyricLineMouseEvent(this.lyricLinesIndexes.get(mainLine) ?? -1, mainLine, bgLine, e);
4641
+ if (!this.dispatchEvent(evt) || evt.defaultPrevented) e.preventDefault();
4642
+ if (evt.isPropagationStopped) {
4633
4643
  e.stopPropagation();
4634
4644
  e.stopImmediatePropagation();
4635
4645
  }
@@ -4650,6 +4660,8 @@ var DomLyricPlayer = class extends LyricPlayerBase {
4650
4660
  this.onResize();
4651
4661
  this.element.classList.add("amll-lyric-player", "dom");
4652
4662
  if (this.disableSpring) this.element.classList.add(lyric_player_module_default.disableSpring);
4663
+ this.element.addEventListener("click", this.onMouseEventHandler, { signal: this.abortController.signal });
4664
+ this.element.addEventListener("contextmenu", this.onMouseEventHandler, { signal: this.abortController.signal });
4653
4665
  }
4654
4666
  rebuildStyle() {}
4655
4667
  setWordFadeWidth(value = .5) {
@@ -4669,21 +4681,12 @@ var DomLyricPlayer = class extends LyricPlayerBase {
4669
4681
  if (this.hasDuetLine) this.element.classList.add(lyric_player_module_default.hasDuetLine);
4670
4682
  else this.element.classList.remove(lyric_player_module_default.hasDuetLine);
4671
4683
  if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${initialTime}`);
4672
- for (const group of this.currentLyricGroups) {
4673
- const linesToDispose = [group.mainLine, group.bgLine].filter((line) => !!line);
4674
- for (const line of linesToDispose) {
4675
- line.removeMouseEventListener("click", this.onLineClickedHandler);
4676
- line.removeMouseEventListener("contextmenu", this.onLineClickedHandler);
4677
- }
4678
- group.dispose();
4679
- }
4684
+ for (const group of this.currentLyricGroups) group.dispose();
4680
4685
  this.currentLyricGroups = [];
4681
4686
  let currentGroup = null;
4682
4687
  for (let i = 0; i < this.processedLines.length; i++) {
4683
4688
  const line = this.processedLines[i];
4684
4689
  const lineEl = new LyricLineEl(this, line);
4685
- lineEl.addMouseEventListener("click", this.onLineClickedHandler);
4686
- lineEl.addMouseEventListener("contextmenu", this.onLineClickedHandler);
4687
4690
  this.lyricLinesIndexes.set(lineEl, i);
4688
4691
  if (!line.isBG || !currentGroup) {
4689
4692
  currentGroup = new LyricLineGroup(this, lineEl);
@@ -4726,6 +4729,7 @@ var DomLyricPlayer = class extends LyricPlayerBase {
4726
4729
  }
4727
4730
  dispose() {
4728
4731
  super.dispose();
4732
+ this.abortController.abort();
4729
4733
  this.element.remove();
4730
4734
  for (const group of this.currentLyricGroups) group.dispose();
4731
4735
  this.bottomLine.dispose();